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

重绘一大波icon;修复框架子vm的props属性传递;重写datepicker组件;重写分页组件;

old
宇天 2018-02-03 02:10:34 +08:00
parent c76a1b3264
commit 88dab988da
25 changed files with 5987 additions and 6868 deletions

View File

@ -19,7 +19,12 @@ const prefixer = postcss().use(
)
const jsOpt = {
presets: ['es2015'],
plugins: ['transform-es2015-modules-amd']
plugins: [
'transform-es2015-modules-amd',
'transform-decorators-legacy',
'transform-class-properties',
'transform-object-rest-spread'
]
}
const cssOpt = {
includePaths: ['src/css/'],

View File

@ -18,7 +18,12 @@ const prefixer = postcss().use(
)
const jsOpt = {
presets: ['es2015', 'minify'],
plugins: ['transform-es2015-modules-amd']
plugins: [
'transform-es2015-modules-amd',
'transform-decorators-legacy',
'transform-class-properties',
'transform-object-rest-spread'
]
}
const cssOpt = {
includePaths: ['src/css/'],

53
package-lock.json generated
View File

@ -1,5 +1,5 @@
{
"name": "doui-yua",
"name": "doui-anot",
"version": "0.0.1",
"lockfileVersion": 1,
"requires": true,
@ -463,6 +463,47 @@
"babel-helper-is-void-0": "0.2.0"
}
},
"babel-plugin-syntax-class-properties": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
"integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=",
"dev": true
},
"babel-plugin-syntax-decorators": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz",
"integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=",
"dev": true
},
"babel-plugin-syntax-object-rest-spread": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
"integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
"dev": true
},
"babel-plugin-transform-class-properties": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
"integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=",
"dev": true,
"requires": {
"babel-helper-function-name": "6.24.1",
"babel-plugin-syntax-class-properties": "6.13.0",
"babel-runtime": "6.26.0",
"babel-template": "6.26.0"
}
},
"babel-plugin-transform-decorators-legacy": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.4.tgz",
"integrity": "sha1-dBtY9sW86eYCfgiC2cmU8E82aSU=",
"dev": true,
"requires": {
"babel-plugin-syntax-decorators": "6.13.0",
"babel-runtime": "6.26.0",
"babel-template": "6.26.0"
}
},
"babel-plugin-transform-es2015-arrow-functions": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
@ -721,6 +762,16 @@
"integrity": "sha512-bPbUhkeN2Nc0KH0/A19GwQGj8w+CvdJzyu8t59VoEDgsNMQ9Bopzi5DrVkrSsVjbYUaZpzq/DYLrH+wD5K2Tig==",
"dev": true
},
"babel-plugin-transform-object-rest-spread": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
"integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=",
"dev": true,
"requires": {
"babel-plugin-syntax-object-rest-spread": "6.13.0",
"babel-runtime": "6.26.0"
}
},
"babel-plugin-transform-property-literals": {
"version": "6.8.5",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.8.5.tgz",

View File

@ -1,5 +1,5 @@
{
"name": "doui-yua",
"name": "doui-anot",
"version": "0.0.1",
"description": "基于Anot框架的doUI组件库。支持IE10+,及现代浏览器。",
"main": "index.js",
@ -13,13 +13,16 @@
},
"keywords": [
"doui",
"yua"
"Anot"
],
"author": "yutent",
"license": "MIT",
"devDependencies": {
"autoprefixer": "^7.2.5",
"babel-core": "^6.26.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-minify": "^0.2.0",
"chalk": "^2.3.0",

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -3297,11 +3297,12 @@
if (/^:/.test(attr.name)) {
var name = attr.name.match(rmsAttr)[1]
var value = null
if (!name || Anot.directives[name]) {
if (!name || Anot.directives[name] || events[name]) {
return
}
try {
value = parseExpr(attr.value, vmodels, {}).apply(0, vmodels)
value = toJson(value)
elem.removeAttribute(attr.name)
if (!value) {
return
@ -4092,7 +4093,7 @@
elem.addEventListener(type, callback, false)
var old = binding.rollback
binding.rollback = function() {
elem.anotStter = null
elem.anotSetter = null
Anot.unbind(elem, type, callback)
old && old()
}
@ -4196,7 +4197,7 @@
elem.msFocus = false
})
}
elem.anotStter = updateVModel //#765
elem.anotSetter = updateVModel //#765
watchValueInTimer(function() {
if (root.contains(elem)) {
if (!elem.msFocus) {
@ -4346,8 +4347,8 @@
function newSetter(value) {
// jshint ignore:line
setters[this.tagName].call(this, value)
if (!this.msFocus && this.anotStter) {
this.anotStter()
if (!this.msFocus && this.anotSetter) {
this.anotSetter()
}
}
var inputProto = HTMLInputElement.prototype

View File

@ -42,16 +42,16 @@
&:active {font-weight:bold;
&::before {animation:ripple .3s cubic-bezier(0.23, 1, 0.32, 1);}
}
&::after {content:"\e652";}
&::after {content:"\e692";}
&.prev-month {left:35px;
&::after {content:"\e659"}
&::after {content:"\e67c"}
}
&.next-month {left:auto; right:35px;
&::after {content:"\e658"}
&::after {content:"\e66e"}
}
&.next-year {left:auto; right:0;
&::after {content:"\e653"}
&::after {content:"\e694"}
}
}

219
src/js/drag/index.js Normal file
View File

@ -0,0 +1,219 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2017-03-29 18:39:35
*
*/
'use strict'
function getBindingCallback(elem, name, vmodels) {
var callback = elem.getAttribute(name)
if (callback) {
for (var i = 0, vm; (vm = vmodels[i++]); ) {
if (vm.hasOwnProperty(callback) && typeof vm[callback] === 'function') {
return vm[callback]
}
}
}
}
Anot.ui.drag = '1.0.0'
// 元素拖动
Anot.directive('drag', {
priority: 1500,
init: function(binding) {
binding.expr = '"' + binding.expr + '"'
Anot(binding.element).css('cursor', 'move')
//取得拖动的3种状态回调
//按下,且拖拽之前
binding.beforedrag = getBindingCallback(
binding.element,
'data-beforedrag',
binding.vmodels
)
//拖拽过程
binding.dragging = getBindingCallback(
binding.element,
'data-dragging',
binding.vmodels
)
// 拖拽结束,且释放鼠标
binding.dragged = getBindingCallback(
binding.element,
'data-dragged',
binding.vmodels
)
//默认允许溢出可视区
binding.overflow = true
//方向,x轴, y轴, xy轴
binding.axis = 'xy'
if (!!binding.element.dataset.axis) {
binding.axis = binding.element.dataset.axis
delete binding.element.dataset.axis
}
//默认不限制拖拽区域
binding.limit = false
if (!!binding.element.dataset.limit) {
binding.limit = binding.element.dataset.limit
//这里,只要不为空,除parent外,其他值都默认为window, 故"可溢出"为false
binding.overflow = false
delete binding.element.dataset.limit
}
delete binding.element.dataset.beforedrag
delete binding.element.dataset.dragging
delete binding.element.dataset.dragged
},
update: function(val) {
var _this = this,
target = val ? this.element.parentNode : this.element,
$drag = Anot(this.element),
$doc = Anot(document),
$target = null,
parentElem = null
// val值不为空时, 获取真正的拖动元素
// 仅从父级上找
while (val && target) {
if (target.classList.contains(val) || target.id === val) {
break
} else {
target = target.parentNode
}
}
$target = Anot(target)
// 限制范围为parent时,获取父级元素
if (this.limit === 'parent') {
parentElem = target.parentNode
}
var dx, dy, mx, my, ox, oy, fox, foy, tw, th, ww, wh, bst, bsl
$drag.bind('mousedown', function(ev) {
var gcs = getComputedStyle(target),
cst = gcs.transform.replace(/matrix\((.*)\)/, '$1'),
offset = $target.offset()
cst = cst !== 'none' ? cst.split(', ') : [1, 0, 0, 1, 0, 0]
cst[4] -= 0
cst[5] -= 0
//记录初始的transform位移
dx = cst[4]
dy = cst[5]
//滚动条的偏移
bst = $doc.scrollTop()
bsl = $doc.scrollLeft()
// 计算元素的offset值, 需要修正
ox = offset.left - dx - bsl
oy = offset.top - dy - bst
mx = ev.pageX //按下鼠标的的坐标值
my = ev.pageY //按下鼠标的的坐标值
// 在按下时才获取窗口大小, 是为了防止人为的改变窗口大小,导致计算不准备
// 同时减少不必要的事件监听(页面上可能会很多可拖动元素)
ww = window.innerWidth
wh = window.innerHeight
// 同样,在点击之后获取元素的宽高,可保证获取到的是真实的值
tw = target.clientWidth
th = target.clientHeight
//拖拽前回调
if (_this.beforedrag) {
var result = _this.beforedrag.call(_this.vmodels, target, ox, oy)
if (result === false) {
return
}
}
//限制区域, 4个值依次是: 上, 下, 左, 右
var limit = [0, wh - th, 0, ww - tw]
if (_this.limit === 'parent') {
var pgcs = getComputedStyle(parentElem),
pcst = pgcs.transform.replace(/matrix\((.*)\)/, '$1'),
poffset = Anot(parentElem).offset()
pcst = pcst !== 'none' ? pcst.split(', ') : [1, 0, 0, 1, 0, 0]
var pox = poffset.left - pcst[4] - bsl,
poy = poffset.top - pcst[5] - bst
limit = [
poy,
poy + parentElem.clientHeight - th,
pox,
pox + parentElem.clientWidth - tw
]
}
var mvfn = $doc.bind('mousemove', function(ev) {
//坐标轴限制
if (_this.axis !== 'y') {
cst[4] = ev.pageX - mx + dx
}
if (_this.axis !== 'x') {
cst[5] = ev.pageY - my + dy
}
;(fox = ox + cst[4]), //修正的offset
(foy = oy + cst[5]) //修正的offset
//如果不允许溢出可视区
if (!_this.overflow) {
if (_this.axis !== 'y') {
if (fox <= limit[2]) {
fox = limit[2]
//修正矩阵
cst[4] = fox - ox
}
if (fox >= limit[3]) {
fox = limit[3]
//修正矩阵
cst[4] = fox - ox
}
}
if (_this.axis !== 'x') {
if (foy <= limit[0]) {
foy = limit[0]
//修正矩阵
cst[5] = foy - oy
}
if (foy >= limit[1]) {
foy = limit[1]
//修正矩阵
cst[5] = foy - oy
}
}
}
$target.css({
transform: 'matrix(' + cst.join(', ') + ')'
})
//拖拽过程的回调
if (_this.dragging) {
_this.dragging.call(_this.vmodels, target, fox, foy)
}
// 防止拖动到边缘时导致页面滚动
ev.preventDefault()
}),
upfn = $doc.bind('mouseup', function(ev) {
$doc.unbind('mousemove', mvfn)
$doc.unbind('mouseup', upfn)
//结束回调
if (_this.dragged) {
_this.dragged.call(_this.vmodels, target, fox, foy)
}
})
})
}
})

View File

@ -1,216 +0,0 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2017-03-29 18:39:35
*
*/
"use strict";
define(['yua'], function(){
function getBindingCallback(elem, name, vmodels) {
var callback = elem.getAttribute(name)
if (callback) {
for (var i = 0, vm; vm = vmodels[i++]; ) {
if (vm.hasOwnProperty(callback) && typeof vm[callback] === "function") {
return vm[callback]
}
}
}
}
yua.ui.drag = '1.0.0'
// 元素拖动
yua.directive('drag', {
priority: 1500,
init: function(binding){
binding.expr = '"' + binding.expr + '"'
yua(binding.element).css('cursor', 'move')
//取得拖动的3种状态回调
//按下,且拖拽之前
binding.beforedrag = getBindingCallback(binding.element, 'data-beforedrag', binding.vmodels)
//拖拽过程
binding.dragging = getBindingCallback(binding.element, 'data-dragging', binding.vmodels)
// 拖拽结束,且释放鼠标
binding.dragged = getBindingCallback(binding.element, 'data-dragged', binding.vmodels)
//默认允许溢出可视区
binding.overflow = true
//方向,x轴, y轴, xy轴
binding.axis = 'xy'
if(!!binding.element.dataset.axis){
binding.axis = binding.element.dataset.axis
delete binding.element.dataset.axis
}
//默认不限制拖拽区域
binding.limit = false
if(!!binding.element.dataset.limit) {
binding.limit = binding.element.dataset.limit
//这里,只要不为空,除parent外,其他值都默认为window, 故"可溢出"为false
binding.overflow = false
delete binding.element.dataset.limit
}
delete binding.element.dataset.beforedrag
delete binding.element.dataset.dragging
delete binding.element.dataset.dragged
},
update: function(val){
var _this = this,
target = val ? this.element.parentNode : this.element,
$drag = yua(this.element),
$doc = yua(document),
$target = null,
parentElem = null;
// val值不为空时, 获取真正的拖动元素
// 仅从父级上找
while(val && target){
if(target.classList.contains(val) || target.id === val){
break
}else{
target = target.parentNode
}
}
$target = yua(target);
// 限制范围为parent时,获取父级元素
if(this.limit === 'parent'){
parentElem = target.parentNode
}
var dx,dy,mx,my,ox,oy,fox,foy,tw,th,ww,wh,bst,bsl;
$drag.bind('mousedown', function(ev){
var gcs = getComputedStyle(target),
cst = gcs.transform.replace(/matrix\((.*)\)/, '$1'),
offset = $target.offset();
cst = cst !== 'none' ? cst.split(', ') : [1,0,0,1,0,0]
cst[4] -= 0
cst[5] -= 0
//记录初始的transform位移
dx = cst[4]
dy = cst[5]
//滚动条的偏移
bst = $doc.scrollTop()
bsl = $doc.scrollLeft()
// 计算元素的offset值, 需要修正
ox = offset.left - dx - bsl
oy = offset.top - dy - bst
mx = ev.pageX //按下鼠标的的坐标值
my = ev.pageY //按下鼠标的的坐标值
// 在按下时才获取窗口大小, 是为了防止人为的改变窗口大小,导致计算不准备
// 同时减少不必要的事件监听(页面上可能会很多可拖动元素)
ww = window.innerWidth;
wh = window.innerHeight;
// 同样,在点击之后获取元素的宽高,可保证获取到的是真实的值
tw = target.clientWidth;
th = target.clientHeight;
//拖拽前回调
if(_this.beforedrag){
var result = _this.beforedrag.call(_this.vmodels, target, ox, oy)
if(result === false){
return
}
}
//限制区域, 4个值依次是: 上, 下, 左, 右
var limit = [0, wh - th, 0, ww - tw]
if(_this.limit === 'parent') {
var pgcs = getComputedStyle(parentElem),
pcst = pgcs.transform.replace(/matrix\((.*)\)/, '$1'),
poffset = yua(parentElem).offset();
pcst = pcst !== 'none' ? pcst.split(', ') : [1,0,0,1,0,0]
var pox = poffset.left - pcst[4] - bsl,
poy = poffset.top - pcst[5] - bst;
limit = [poy, poy + parentElem.clientHeight - th, pox, pox + parentElem.clientWidth - tw]
}
var mvfn = $doc.bind('mousemove', function(ev){
//坐标轴限制
if(_this.axis !== 'y'){
cst[4] = ev.pageX - mx + dx
}
if(_this.axis !== 'x'){
cst[5] = ev.pageY - my + dy
}
fox = ox + cst[4], //修正的offset
foy = oy + cst[5]; //修正的offset
//如果不允许溢出可视区
if(!_this.overflow){
if(_this.axis !== 'y'){
if(fox <= limit[2]) {
fox = limit[2]
//修正矩阵
cst[4] = fox - ox
}
if(fox >= limit[3]){
fox = limit[3]
//修正矩阵
cst[4] = fox - ox
}
}
if(_this.axis !== 'x'){
if(foy <= limit[0]) {
foy = limit[0]
//修正矩阵
cst[5] = foy - oy
}
if(foy >= limit[1]){
foy = limit[1]
//修正矩阵
cst[5] = foy - oy
}
}
}
$target.css({
transform: 'matrix(' + cst.join(', ') + ')'
})
//拖拽过程的回调
if(_this.dragging){
_this.dragging.call(_this.vmodels, target, fox, foy)
}
// 防止拖动到边缘时导致页面滚动
ev.preventDefault()
}),
upfn = $doc.bind('mouseup', function(ev){
$doc.unbind('mousemove', mvfn)
$doc.unbind('mouseup', upfn)
//结束回调
if(_this.dragged){
_this.dragged.call(_this.vmodels, target, fox, foy)
}
});
})
}
})
})

File diff suppressed because it is too large Load Diff

View File

@ -1,578 +0,0 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2016-09-21 01:36:29
*
*/
"use strict";
define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){
var layerDom = {},
layerObj = {},
unique = null, //储存当前打开的1/2/3类型的弹窗
lid = 0,
defconf = {
type: 1, // 弹窗类型
skin: 'def', //默认主题
icon: 1, //图标类型
background: '#fff',
shade: true, //遮罩
shadeClose: false, //遮罩点击关闭弹窗
radius: '0px', //弹窗圆角半径
area: ['auto', 'auto'],
title: '', //弹窗主标题(在工具栏上的)
menubar: true, //是否显示菜单栏
content: '', // 弹窗的内容
fixed: false, //是否固定不可拖拽
offset: null, //弹窗出来时的坐标, 为数组,可有4个值,依次是 上右下左
btns: ['确定', '取消'], //弹窗的2个按钮的文字
yes: close, //确定按钮对应的回调
no: close, //取消按钮对应的回调
success: null //弹窗初始化完成时的回调
};
function uuid(){
return 'layer-' + (++lid)
}
function close(id){
if(typeof id !== 'string' && typeof id !== 'number'){
return console.error(new Error('要关闭的layer实例不存在'))
}
if(/^\$wrap\-/.test(id) || layerObj['$wrap-' + id]){
try {
id = (layerObj['$wrap-' + id] ? '$wrap-' : '') + id;
//未显示过,忽略
if(!layerObj[id].show){
return
}
layerObj[id].parentElem.replaceChild(layerObj[id].wrap, layerDom[id][1])
unique = null
}catch(err){}
}else{
try {
document.body.removeChild(layerDom[id][1])
document.body.removeChild(layerDom[id][0])
unique = null
}catch(err){}
delete layerDom[id]
delete yua.vmodels[id]
}
}
function reapeat(str, num){
var idx = 0,
result = ''
while(idx < num){
result += str
idx++
}
return result
}
function fixOffset(val){
if(!val && val !== 0){
return 'auto'
}else{
return val
}
}
var __constructor = function(conf){
if(conf){
this.ready(conf).append().show()
}
},
__layer = {
alert: function(msg, conf){
if(typeof conf === 'function'){
conf = {yes: conf}
}else if(typeof conf === 'object'){
conf = conf
}else{
conf = {}
}
conf.icon = 6
conf.content = msg
return __layer.open(conf)
},
confirm: function(msg, conf){
if(typeof conf === 'function'){
conf = {yes: conf}
}else if(typeof conf === 'object'){
conf = conf
}else{
conf = {}
}
conf.type = 2
conf.icon = 8
conf.content = msg
return __layer.open(conf)
},
msg: function(msg, conf){
if(typeof conf !== 'object'){
var tmp = conf
conf = {timeout: 2500}
if(typeof tmp === 'number'){
conf.icon = tmp
}
}
if(!conf.hasOwnProperty('timeout')){
conf.timeout = 2500
}
conf.specialMode = true;//特殊模式
conf.content = '<p class="msg-box">' + msg + '</p>'
conf.type = 7
conf.fixed = true
conf.shade = false
conf.menubar = false
conf.radius = '5px'
return __layer.open(conf)
},
loading: function(style, time, cb){
style = style >>> 0
if(typeof time === 'function'){
cb = time;
time = 0
} else{
time = time >>> 0
if(typeof cb !== 'function'){
cb = yua.noop
}
}
return __layer.open({type: 6, load: style, yes: cb, timeout: time, menubar: false, background: 'none', fixed: true})
},
tips: function(msg, elem, conf){
if(!(elem instanceof HTMLElement)){
return console.error(new Error('tips类型必须指定一个目标容器'))
}
if(typeof conf !== 'object'){
var tmp = conf
conf = {timeout: 2500}
if(typeof tmp === 'number'){
conf.icon = tmp
}
}
if(!conf.hasOwnProperty('timeout')){
conf.timeout = 2500
}
if(!conf.background){
conf.background = 'rgba(0,0,0,.5)'
}
if(!conf.color){
conf.color = '#fff'
}
conf.$elem = elem
conf.content = msg
conf.type = 5;
conf.icon = 0;
conf.fixed = true;
conf.shade = false;
conf.menubar = false;
return __layer.open(conf)
},
prompt: function(msg, callback){
if(typeof callback !== 'function'){
return console.error('argument [callback] requires a function, but ' + (typeof callback) + ' given')
}
var conf = {
type: 3,
icon: 7,
prompt: '',
title: msg,
content: '<input class="prompt-value" :duplex="prompt" />',
yes: function(id){
callback(id, yua.vmodels[id].prompt)
}
}
return __layer.open(conf)
},
use: function(skin, callback){
require(['css!./skin/' + skin], callback)
},
close: close,
open: function(conf){
if(typeof conf === 'string'){
conf = '$wrap-' + conf
if(!layerObj[conf]){
throw new Error('layer实例不存在')
}else{
//只能显示一个实例
if(layerObj[conf].show){
return
}
layerObj[conf].show = true
if(!yua.vmodels[conf]){
yua.define(layerObj[conf].obj.init)
}
yua.scan(layerDom[conf][1])
layerObj[conf].obj.show()
layerObj[conf].parentElem.appendChild(layerDom[conf][1])
layerObj[conf].parentElem.replaceChild(layerDom[conf][1], layerObj[conf].wrap)
}
}else{
return new __constructor(conf).init.$id
}
},
version: '0.0.1-base'
};
/*type: { // 弹窗类型对应的id值
1: 'alert',
2: 'confirm',
3: 'prompt',
4: 'iframe',
5: 'tips',
6: 'loading',
7: 'msg',
}*/
__constructor.prototype = {
dot: { //loading的子元素数量
0: 4,
1: 9,
2: 2,
3: 3,
4: 2,
5: 5,
6: 5,
7: 5
},
timeout: null,
create: function(){
var layBox = document.createElement('div'),
coverBox = document.createElement('div');
coverBox.className = 'do-layer-cover type-' + this.init.type
// 允许点击遮罩关闭弹层时, 添加控制器
if(this.init.shadeClose){
coverBox.setAttribute(':controller', this.cInit.$id)
coverBox.setAttribute(':click', 'close(\'' + this.init.$id + '\')')
}
layBox.className = 'do-layer skin-'
+ this.init.skin
+ (this.init.type === 5 && ' active' || '')
+ ' type-'
+ ((!this.init.specialMode && this.init.type === 7) ? 'unspecial' : this.init.type);
//暂时隐藏,避免修正定位时,能看到闪一下
layBox.style.visibility = 'hidden'
layBox.style.borderRadius = this.init.radius
layBox.setAttribute(':controller', this.init.$id)
//没有菜单栏, 且未禁止拖拽,则加上可拖拽属性
if(!this.init.menubar && !this.init.fixed){
layBox.setAttribute(':drag', '')
layBox.setAttribute('data-limit', 'window')
}
//弹窗的宽高
var boxcss = ''
if(this.init.area[0] !== 'auto'){
boxcss += 'width: ' + this.init.area[0] + ';'
}
if(this.init.area[1] !== 'auto'){
boxcss += 'height: ' + this.init.area[1] + ';'
}
layBox.innerHTML = this.getMenubar()
+ '<div class="layer-content do-fn-cl '
+ (this.init.icon === 0 && 'none-icon' || '')
+ '" style="'
+ boxcss
+ '">'
+ this.getCont()
+ '</div>'
+ this.getBtns()
+ (this.init.type === 5 && '<i class="arrow" style="border-top-color: '
+ this.init.background
+ '"></i>' || '')
return [this.init.shade ? coverBox : null, layBox]
},
getCont: function(){
if(this.init.type === 6){
return this.getLoading(this.init.load)
}else{
return this.getIcon()
+ '<div class="detail" :html="content"></div>'
}
},
getLoading: function(style){
return '<div class="do-ui-load load-style-'
+ style
+ '">'
+ '<span class="dot-box">'
+ reapeat('<i></i>', this.dot[style])
+ '</span>'
+ '</div>'
},
//获取窗口导航条
getMenubar: function(){
var html = ''
if(this.init.menubar){
html += '<div class="layer-title do-fn-noselect" ';
//可拖拽
if(!this.init.fixed){
html += ':drag="do-layer" data-limit="window" '
}
html += '>{{title}}'
+ '<a class="action-close deficon" :click="no(\'' + this.init.$id + '\')"></a>'
+ '</div>'
}
return html
},
//获取窗口内容的图标
getIcon: function(){
if(this.init.icon === 0){
return ''
}
if(this.init.type < 4 || this.init.type === 5 || this.init.specialMode){
return '<span class="deficon icon-' + this.init.icon + '"></span>'
}
return ''
},
// 获取窗口按钮
getBtns: function(){
if(this.init.type > 3){
return ''
}else{
var html = '<div class="layer-btns do-fn-noselect">';
if(this.init.type > 1){
html += '<a href="javascript:;" class="action-no" '
+ ':click="no(\'' + this.init.$id + '\')" '
+ ':text="btns[1]"></a>'
+ '<a href="javascript:;" class="action-yes" '
+ ':click="yes(\'' + this.init.$id + '\')" '
+ ':text="btns[0]"></a>'
}else{
html += '<a href="javascript:;" class="action-yes" '
+ ':click="yes(\'' + this.init.$id + '\')" '
+ ':text="btns[0]"></a>'
}
html += '</div>'
return html
}
},
append: function(){
//如果有已经打开的弹窗,则关闭
if(unique){
__layer.close(unique)
}
if(this.init.type < 4){
unique = this.init.$id
}
layerDom[this.init.$id] = this.create()
if(layerDom[this.init.$id][0]){
document.body.appendChild(layerDom[this.init.$id][0])
//仅在允许点击遮罩时,初始化控制器,减少资源消耗
if(this.init.shadeClose){
yua.define(this.cInit)
yua.scan(layerDom[this.init.$id][0])
}
}
document.body.appendChild(layerDom[this.init.$id][1])
yua.define(this.init)
yua.scan(layerDom[this.init.$id][1])
return this
},
show: function(){
var _this = this;
setTimeout(function(){
var style = {visibility: '', background: _this.init.background},
css = getComputedStyle(layerDom[_this.init.$id][1]);
if(_this.init.type === 5){
style.color = _this.init.color
var $elem = yua(_this.init.$elem),
ew = $elem.innerWidth(),
ol = $elem.offset().left - document.body.scrollLeft,
ot = $elem.offset().top - document.body.scrollTop;
style.left = ol + (ew * 0.7)
style.top = ot - parseInt(css.height) - 8
}else{
if(_this.init.offset){
style.top = fixOffset(_this.init.offset[0])
style.right = fixOffset(_this.init.offset[1])
style.bottom = fixOffset(_this.init.offset[2])
style.left = fixOffset(_this.init.offset[3])
}else{
style = yua.mix(style, {
marginLeft: -parseInt(css.width) / 2,
marginTop: -parseInt(css.height) / 2,
})
}
}
yua(layerDom[_this.init.$id][1]).css(style)
}, 4)
if(this.init.success && typeof this.init.success === 'function'){
//弹窗成功的回调
this.init.success(this.init.$id)
}
// loading类型,回调需要自动触发
if(this.init.type > 3) {
//大于0自动触发超时关闭
if(this.init.timeout > 0){
clearTimeout(this.timeout)
this.timeout = setTimeout(function(){
clearTimeout(_this.timeout)
__layer.close(_this.init.$id)
// 为loading类型时,自动关闭同时触发回调
if(_this.init.type === 6){
_this.init.yes(_this.init.$id)
}
}, this.init.timeout)
} else if(this.init.type === 6) {
// loading类型, 非自动关闭时, 主动触发回调
this.init.yes(this.init.$id)
}
}
},
ready: function(conf){
this.init = yua.mix({}, defconf, conf)
if(!this.init.$id){
this.init.$id = uuid();
}
if(this.init.icon > 17){
this.icon.icon = 17
}
//base版没有iframe类型
if(this.init.type === 4){
this.icon.type = 7
}
this.cInit = {
$id: this.init.$id + '-c',
close: this.init.shadeClose ? close : yua.noop
};
return this
}
}
yua.directive('layer', {
priority: 1400,
init: function(binding){
if(!binding.param){
binding.element.style.display = 'none'
}
},
update: function(val){
if(!val){
return console.error(new Error(':layer指令格式不正确或无效属性. [' + this.name + '="' + this.expr) + '"]')
}
var _this = this,
init = Object.assign({}, this.element.dataset);
if(!this.param){
init.type = 7;
init.$id = '$wrap-' + val;
if(!init.hasOwnProperty('menubar')){
init.menubar = false;
}
var tmp = new __constructor().ready(init);
tmp.init.content = this.element.cloneNode(true);
layerObj[tmp.init.$id] = {obj: tmp, parentElem: this.element.parentNode, wrap: this.element, show: false};
layerDom[tmp.init.$id] = tmp.create();
}else if(this.param === 'tips'){
var $elem = yua(this.element),
ew = $elem.innerWidth(),
ol = $elem.offset().left - document.body.scrollLeft,
ot = $elem.offset().top - document.body.scrollTop,
tipsBox = document.createElement('div'),
tipsArrow = document.createElement('i'),
tipsCont = document.createElement('div');
tipsBox.className = 'do-layer skin-def type-5'
tipsBox.style.left = ol + (ew * 0.7) + 'px'
if(init.background){
tipsBox.style.background = init.background
tipsArrow.style.borderTopColor = init.background
}
if(init.color){
tipsBox.style.color = init.color
}
tipsCont.className = 'layer-content'
tipsCont.textContent = val
tipsArrow.className = 'arrow'
tipsBox.appendChild(tipsCont)
tipsBox.appendChild(tipsArrow)
yua(document).bind('scroll', function(){
ol = $elem.offset().left - document.body.scrollLeft;
ot = $elem.offset().top - document.body.scrollTop;
tipsBox.style.left = ol + (ew * 0.7) + 'px'
tipsBox.style.top = (ot - tipsBox.offsetHeight - 8) + 'px'
})
$elem.bind('mouseenter', function(ev){
_this.element.parentNode.appendChild(tipsBox)
clearTimeout(_this.showTime)
clearTimeout(_this.hideTime)
_this.showTime = setTimeout(function(){
tipsBox.style.top = (ot - tipsBox.offsetHeight - 8) + 'px'
tipsBox.classList.add('active')
}, 4)
})
$elem.bind('mouseleave', function(){
_this.hideTime = setTimeout(function(){
clearTimeout(_this.hideTime)
try{
_this.element.parentNode.removeChild(tipsBox)
}catch(err){}
}, 150)
})
}
}
})
if(!window.layer)
window.layer = __layer
return __layer
})

View File

@ -1,578 +0,0 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2016-09-21 01:36:29
*
*/
"use strict";
define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){
var layerDom = {},
layerObj = {},
unique = null, //储存当前打开的1/2/3类型的弹窗
lid = 0,
defconf = {
type: 1, // 弹窗类型
skin: 'def', //默认主题
icon: 1, //图标类型
background: '#fff',
shade: true, //遮罩
shadeClose: false, //遮罩点击关闭弹窗
radius: '0px', //弹窗圆角半径
area: ['auto', 'auto'],
title: '', //弹窗主标题(在工具栏上的)
menubar: true, //是否显示菜单栏
content: '', // 弹窗的内容
fixed: false, //是否固定不可拖拽
offset: null, //弹窗出来时的坐标, 为数组,可有4个值,依次是 上右下左
btns: ['确定', '取消'], //弹窗的2个按钮的文字
yes: close, //确定按钮对应的回调
no: close, //取消按钮对应的回调
success: null //弹窗初始化完成时的回调
};
function uuid(){
return 'layer-' + (++lid)
}
function close(id){
if(typeof id !== 'string' && typeof id !== 'number'){
return console.error(new Error('要关闭的layer实例不存在'))
}
if(/^\$wrap\-/.test(id) || layerObj['$wrap-' + id]){
try {
id = (layerObj['$wrap-' + id] ? '$wrap-' : '') + id;
//未显示过,忽略
if(!layerObj[id].show){
return
}
layerObj[id].parentElem.replaceChild(layerObj[id].wrap, layerDom[id][1])
unique = null
}catch(err){}
}else{
try {
document.body.removeChild(layerDom[id][1])
document.body.removeChild(layerDom[id][0])
unique = null
}catch(err){}
delete layerDom[id]
delete yua.vmodels[id]
}
}
function reapeat(str, num){
var idx = 0,
result = ''
while(idx < num){
result += str
idx++
}
return result
}
function fixOffset(val){
if(!val && val !== 0){
return 'auto'
}else{
return val
}
}
var __constructor = function(conf){
if(conf){
this.ready(conf).append().show()
}
},
__layer = {
alert: function(msg, conf){
if(typeof conf === 'function'){
conf = {yes: conf}
}else if(typeof conf === 'object'){
conf = conf
}else{
conf = {}
}
conf.icon = 6
conf.content = msg
return __layer.open(conf)
},
confirm: function(msg, conf){
if(typeof conf === 'function'){
conf = {yes: conf}
}else if(typeof conf === 'object'){
conf = conf
}else{
conf = {}
}
conf.type = 2
conf.icon = 8
conf.content = msg
return __layer.open(conf)
},
msg: function(msg, conf){
if(typeof conf !== 'object'){
var tmp = conf
conf = {timeout: 2500}
if(typeof tmp === 'number'){
conf.icon = tmp
}
}
if(!conf.hasOwnProperty('timeout')){
conf.timeout = 2500
}
conf.specialMode = true;//特殊模式
conf.content = '<p class="msg-box">' + msg + '</p>'
conf.type = 7
conf.fixed = true
conf.shade = false
conf.menubar = false
conf.radius = '5px'
return __layer.open(conf)
},
loading: function(style, time, cb){
style = style >>> 0
if(typeof time === 'function'){
cb = time;
time = 0
} else{
time = time >>> 0
if(typeof cb !== 'function'){
cb = yua.noop
}
}
return __layer.open({type: 6, load: style, yes: cb, timeout: time, menubar: false, background: 'none', fixed: true})
},
tips: function(msg, elem, conf){
if(!(elem instanceof HTMLElement)){
return console.error(new Error('tips类型必须指定一个目标容器'))
}
if(typeof conf !== 'object'){
var tmp = conf
conf = {timeout: 2500}
if(typeof tmp === 'number'){
conf.icon = tmp
}
}
if(!conf.hasOwnProperty('timeout')){
conf.timeout = 2500
}
if(!conf.background){
conf.background = 'rgba(0,0,0,.5)'
}
if(!conf.color){
conf.color = '#fff'
}
conf.$elem = elem
conf.content = msg
conf.type = 5;
conf.icon = 0;
conf.fixed = true;
conf.shade = false;
conf.menubar = false;
return __layer.open(conf)
},
prompt: function(msg, callback){
if(typeof callback !== 'function'){
return console.error('argument [callback] requires a function, but ' + (typeof callback) + ' given')
}
var conf = {
type: 3,
icon: 7,
prompt: '',
title: msg,
content: '<input class="prompt-value" :duplex="prompt" />',
yes: function(id){
callback(id, yua.vmodels[id].prompt)
}
}
return __layer.open(conf)
},
use: function(skin, callback){
require(['css!./skin/' + skin], callback)
},
close: close,
open: function(conf){
if(typeof conf === 'string'){
conf = '$wrap-' + conf
if(!layerObj[conf]){
throw new Error('layer实例不存在')
}else{
//只能显示一个实例
if(layerObj[conf].show){
return
}
layerObj[conf].show = true
if(!yua.vmodels[conf]){
yua.define(layerObj[conf].obj.init)
}
yua.scan(layerDom[conf][1])
layerObj[conf].obj.show()
layerObj[conf].parentElem.appendChild(layerDom[conf][1])
layerObj[conf].parentElem.replaceChild(layerDom[conf][1], layerObj[conf].wrap)
}
}else{
return new __constructor(conf).init.$id
}
},
version: '0.0.1-base'
};
/*type: { // 弹窗类型对应的id值
1: 'alert',
2: 'confirm',
3: 'prompt',
4: 'iframe',
5: 'tips',
6: 'loading',
7: 'msg',
}*/
__constructor.prototype = {
dot: { //loading的子元素数量
0: 4,
1: 9,
2: 2,
3: 3,
4: 2,
5: 5,
6: 5,
7: 5
},
timeout: null,
create: function(){
var layBox = document.createElement('div'),
coverBox = document.createElement('div');
coverBox.className = 'do-layer-cover type-' + this.init.type
// 允许点击遮罩关闭弹层时, 添加控制器
if(this.init.shadeClose){
coverBox.setAttribute(':controller', this.cInit.$id)
coverBox.setAttribute(':click', 'close(\'' + this.init.$id + '\')')
}
layBox.className = 'do-layer skin-'
+ this.init.skin
+ (this.init.type === 5 && ' active' || '')
+ ' type-'
+ ((!this.init.specialMode && this.init.type === 7) ? 'unspecial' : this.init.type);
//暂时隐藏,避免修正定位时,能看到闪一下
layBox.style.visibility = 'hidden'
layBox.style.borderRadius = this.init.radius
layBox.setAttribute(':controller', this.init.$id)
//没有菜单栏, 且未禁止拖拽,则加上可拖拽属性
if(!this.init.menubar && !this.init.fixed){
layBox.setAttribute(':drag', '')
layBox.setAttribute('data-limit', 'window')
}
//弹窗的宽高
var boxcss = ''
if(this.init.area[0] !== 'auto'){
boxcss += 'width: ' + this.init.area[0] + ';'
}
if(this.init.area[1] !== 'auto'){
boxcss += 'height: ' + this.init.area[1] + ';'
}
layBox.innerHTML = this.getMenubar()
+ '<div class="layer-content do-fn-cl '
+ (this.init.icon === 0 && 'none-icon' || '')
+ '" style="'
+ boxcss
+ '">'
+ this.getCont()
+ '</div>'
+ this.getBtns()
+ (this.init.type === 5 && '<i class="arrow" style="border-top-color: '
+ this.init.background
+ '"></i>' || '')
return [this.init.shade ? coverBox : null, layBox]
},
getCont: function(){
if(this.init.type === 6){
return this.getLoading(this.init.load)
}else{
return this.getIcon()
+ '<div class="detail" :html="content"></div>'
}
},
getLoading: function(style){
return '<div class="do-ui-load load-style-'
+ style
+ '">'
+ '<span class="dot-box">'
+ reapeat('<i></i>', this.dot[style])
+ '</span>'
+ '</div>'
},
//获取窗口导航条
getMenubar: function(){
var html = ''
if(this.init.menubar){
html += '<div class="layer-title do-fn-noselect" ';
//可拖拽
if(!this.init.fixed){
html += ':drag="do-layer" data-limit="window" '
}
html += '>{{title}}'
+ '<a class="action-close deficon" :click="no(\'' + this.init.$id + '\')"></a>'
+ '</div>'
}
return html
},
//获取窗口内容的图标
getIcon: function(){
if(this.init.icon === 0){
return ''
}
if(this.init.type < 4 || this.init.type === 5 || this.init.specialMode){
return '<span class="deficon icon-' + this.init.icon + '"></span>'
}
return ''
},
// 获取窗口按钮
getBtns: function(){
if(this.init.type > 3){
return ''
}else{
var html = '<div class="layer-btns do-fn-noselect">';
if(this.init.type > 1){
html += '<a href="javascript:;" class="action-no" '
+ ':click="no(\'' + this.init.$id + '\')" '
+ ':text="btns[1]"></a>'
+ '<a href="javascript:;" class="action-yes" '
+ ':click="yes(\'' + this.init.$id + '\')" '
+ ':text="btns[0]"></a>'
}else{
html += '<a href="javascript:;" class="action-yes" '
+ ':click="yes(\'' + this.init.$id + '\')" '
+ ':text="btns[0]"></a>'
}
html += '</div>'
return html
}
},
append: function(){
//如果有已经打开的弹窗,则关闭
if(unique){
__layer.close(unique)
}
if(this.init.type < 4){
unique = this.init.$id
}
layerDom[this.init.$id] = this.create()
if(layerDom[this.init.$id][0]){
document.body.appendChild(layerDom[this.init.$id][0])
//仅在允许点击遮罩时,初始化控制器,减少资源消耗
if(this.init.shadeClose){
yua.define(this.cInit)
yua.scan(layerDom[this.init.$id][0])
}
}
document.body.appendChild(layerDom[this.init.$id][1])
yua.define(this.init)
yua.scan(layerDom[this.init.$id][1])
return this
},
show: function(){
var _this = this;
setTimeout(function(){
var style = {visibility: '', background: _this.init.background},
css = getComputedStyle(layerDom[_this.init.$id][1]);
if(_this.init.type === 5){
style.color = _this.init.color
var $elem = yua(_this.init.$elem),
ew = $elem.innerWidth(),
ol = $elem.offset().left - document.body.scrollLeft,
ot = $elem.offset().top - document.body.scrollTop;
style.left = ol + (ew * 0.7)
style.top = ot - parseInt(css.height) - 8
}else{
if(_this.init.offset){
style.top = fixOffset(_this.init.offset[0])
style.right = fixOffset(_this.init.offset[1])
style.bottom = fixOffset(_this.init.offset[2])
style.left = fixOffset(_this.init.offset[3])
}else{
style = yua.mix(style, {
marginLeft: -parseInt(css.width) / 2,
marginTop: -parseInt(css.height) / 2,
})
}
}
yua(layerDom[_this.init.$id][1]).css(style)
}, 4)
if(this.init.success && typeof this.init.success === 'function'){
//弹窗成功的回调
this.init.success(this.init.$id)
}
// loading类型,回调需要自动触发
if(this.init.type > 3) {
//大于0自动触发超时关闭
if(this.init.timeout > 0){
clearTimeout(this.timeout)
this.timeout = setTimeout(function(){
clearTimeout(_this.timeout)
__layer.close(_this.init.$id)
// 为loading类型时,自动关闭同时触发回调
if(_this.init.type === 6){
_this.init.yes(_this.init.$id)
}
}, this.init.timeout)
} else if(this.init.type === 6) {
// loading类型, 非自动关闭时, 主动触发回调
this.init.yes(this.init.$id)
}
}
},
ready: function(conf){
this.init = yua.mix({}, defconf, conf)
if(!this.init.$id){
this.init.$id = uuid();
}
if(this.init.icon > 17){
this.icon.icon = 17
}
//base版没有iframe类型
if(this.init.type === 4){
this.icon.type = 7
}
this.cInit = {
$id: this.init.$id + '-c',
close: this.init.shadeClose ? close : yua.noop
};
return this
}
}
yua.directive('layer', {
priority: 1400,
init: function(binding){
if(!binding.param){
binding.element.style.display = 'none'
}
},
update: function(val){
if(!val){
return console.error(new Error(':layer指令格式不正确或无效属性. [' + this.name + '="' + this.expr) + '"]')
}
var _this = this,
init = Object.assign({}, this.element.dataset);
if(!this.param){
init.type = 7;
init.$id = '$wrap-' + val;
if(!init.hasOwnProperty('menubar')){
init.menubar = false;
}
var tmp = new __constructor().ready(init);
tmp.init.content = this.element.cloneNode(true);
layerObj[tmp.init.$id] = {obj: tmp, parentElem: this.element.parentNode, wrap: this.element, show: false};
layerDom[tmp.init.$id] = tmp.create();
}else if(this.param === 'tips'){
var $elem = yua(this.element),
ew = $elem.innerWidth(),
ol = $elem.offset().left - document.body.scrollLeft,
ot = $elem.offset().top - document.body.scrollTop,
tipsBox = document.createElement('div'),
tipsArrow = document.createElement('i'),
tipsCont = document.createElement('div');
tipsBox.className = 'do-layer skin-def type-5'
tipsBox.style.left = ol + (ew * 0.7) + 'px'
if(init.background){
tipsBox.style.background = init.background
tipsArrow.style.borderTopColor = init.background
}
if(init.color){
tipsBox.style.color = init.color
}
tipsCont.className = 'layer-content'
tipsCont.textContent = val
tipsArrow.className = 'arrow'
tipsBox.appendChild(tipsCont)
tipsBox.appendChild(tipsArrow)
yua(document).bind('scroll', function(){
ol = $elem.offset().left - document.body.scrollLeft;
ot = $elem.offset().top - document.body.scrollTop;
tipsBox.style.left = ol + (ew * 0.7) + 'px'
tipsBox.style.top = (ot - tipsBox.offsetHeight - 8) + 'px'
})
$elem.bind('mouseenter', function(ev){
_this.element.parentNode.appendChild(tipsBox)
clearTimeout(_this.showTime)
clearTimeout(_this.hideTime)
_this.showTime = setTimeout(function(){
tipsBox.style.top = (ot - tipsBox.offsetHeight - 8) + 'px'
tipsBox.classList.add('active')
}, 4)
})
$elem.bind('mouseleave', function(){
_this.hideTime = setTimeout(function(){
clearTimeout(_this.hideTime)
try{
_this.element.parentNode.removeChild(tipsBox)
}catch(err){}
}, 150)
})
}
}
})
if(!window.layer)
window.layer = __layer
return __layer
})

View File

@ -6,22 +6,28 @@
* @version $Id$
*/
@import "../../../../css/var.scss";
@import "var.scss";
.do-layer {position:fixed;left:50%;top:50%;z-index:65535;width:auto;height:auto;
.do-layer {width:auto;height:auto;
a {text-decoration:none;}
&.mask {position:fixed;z-index:65534;left:0;top:0;width:100%;height:100%;background:rgba(0,0,0,.3);}
a {text-decoration:none;}
.layer-box {position:absolute;left:50%;top:50%;z-index:65535;
&.scale {transform:scale(1.02);transition:transform .1s linear;}
/* 默认皮肤 */
&.skin-def {color:#666;font-size:14px;box-shadow:0 0 10px rgba(0,0,0,.3);
&.skin-def {padding:15px 10px;border-radius:3px;color:#666;font-size:14px;box-shadow:0 5px 20px rgba(0,0,0,.3);
.icon-0::before {content:"\e62e";color:nth($cr, 1);} // question
.icon-0::before {content:"\e674";color:nth($cr, 1);} // question
.icon-1::before {content:"\e610";color:nth($ct, 1);} // get
.icon-2::before {content:"\e6f8";color:nth($cb, 1);} // happy
.icon-3::before {content:"\e6fd";color:nth($co, 1);} // sad
.icon-4::before {content:"\e6f6";color:nth($co, 1);} // warn
.icon-5::before {content:"\e630";color:nth($ct, 1);} // face
.icon-5::before {content:"\e673";color:nth($ct, 1);} // face
.icon-6::before {content:"\e636";color:nth($cgr, 1);} // time
.icon-7::before {content:"\e623";color:nth($co, 1);} // star
.icon-8::before {content:"\e604";color:nth($cr, 1);} // mute
@ -29,25 +35,13 @@
/* 弹层标题栏 */
.layer-title {width:100%;height:43px;padding:0 8px;line-height:43px;background:#f5f5f5;font-size:16px;color:nth($cgr, 1);}
.action-min,
.action-close {position:absolute;display:block;top:12px;width:20px;height:20px;line-height:20px;font-size:14px;text-align:center;cursor:pointer;color:nth($cgr, 2);
&:hover {color:nth($ct, 1);}
}
.action-min {right:40px;
&::before {content:"\e634"}
}
.action-close {right:10px;
&::before {content:"\e687"}
}
.layer-title {width:100%;height:43px;padding:0 10px;line-height:43px;font-size:16px;color:nth($cgr, 1);}
/* 弹层主体内容 */
.layer-content {position:relative;width:100%;height:auto;min-height:50px;padding:10px;
.msg-icon {position:absolute;left:10px;top:10px;width:50px;height:auto;line-height:40px;font-size:35px;text-align:center;}
.detail {width:auto;height:100%;margin:auto auto auto 60px;padding:5px 15px;word-break:break-all;word-wrap: break-word;
.detail {width:auto;height:100%;margin:auto auto auto 50px;padding:5px 15px;word-break:break-all;word-wrap: break-word;
.prompt-value {width: 230px;height: 30px;padding: 0 8px;border: 1px solid #ddd;border-radius: 3px;
@ -62,30 +56,34 @@
/* 弹层按钮部分 */
.layer-btns {width:100%;height:40px;padding:0 5px;line-height:30px;font-size:14px;color:#454545;text-align:right;
.layer-ctrl {width:100%;height:40px;padding:5px 0;line-height:30px;font-size:14px;color:#454545;text-align:right;
a {display:inline-block;width:auto;min-width:60px;height:30px;margin:0 5px;padding:0 10px;color:nth($cgr, 1);text-align:center;background:nth($cp, 1);@include ts();
a {overflow:hidden;position:relative;display:inline-block;width:auto;min-width:60px;height:30px;margin-left:5px;padding:0 10px;color:nth($ct, 1);text-align:center;
&:hover {background:nth($cp, 2)}
&:active {background:nth($cp, 3)}
}
&::before {position:absolute;left:-50%;top:-50%;z-index:-1;display:block;width:200%;height:200%;border-radius:50%;background:nth($cp, 2); content:"";opacity:0;transform: scale(0, .0); transition:opacity 1.3s cubic-bezier(0.23, 1, 0.32, 1),transform 1.3s cubic-bezier(0.23, 1, 0.32, 1);}
&:hover {
&::before {opacity:1;transform:scale(1, .8);}
}
&:active {background:nth($cp, 1)}
}
}
}
/* ;alert/confirm/prompt 3类弹层 */
&.type-1,
&.type-2,
&.type-3 {max-width:600px;min-width:230px;}
&.type-3 {max-width:600px;min-width:300px;}
/* tips类弹层(type 5) */
&.type-5 {visibility:hidden;min-width:75px;max-width:600px;line-height:1.5;color:#fff;background:rgba(0,0,0,.5);opacity:0;box-shadow:none;-webkit-transition:opacity .3s ease-in-out;-moz-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out;
&.active {visibility:visible;opacity:1;}
i.arrow {position:absolute;left:5px;bottom:-14px;width:0;height:0;border:6px solid transparent;border-top:8px solid rgba(0,0,0,.5);content: ""}
&.active {visibility:visible;opacity:1;}
i.arrow {position:absolute;left:5px;bottom:-14px;width:0;height:0;border:6px solid transparent;border-top:8px solid rgba(0,0,0,.5);content: ""}
.layer-content .detail {margin:0;padding:0}
.layer-content .detail {margin:0;padding:0}
}
@ -178,9 +176,15 @@
&:active {z-index:65536;}
}
}
.do-layer-cover {position:fixed;left:0;top:0;z-index:65534;width:100%;height:100%;background:rgba(255,255,255,.05);
.do-layer-cover {
&.type-6 {background:rgba(0,0,0,.3);}
}

1379
src/js/marked/index.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,359 +5,403 @@
*
*/
"use strict";
'use strict'
import 'layer/base'
define(['lib/layer/base'], function(){
function objArr(num) {
var arr = []
while (num > 0) {
arr.push({ v: 0 })
num--
}
return arr
}
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({
type: 7,
menubar: false,
shadeClose: true,
fixed: true,
$insert: function(level) {
wrap = wrap.replace(/^#{1,6} /, '')
wrap = ME.repeat('#', level) + ' ' + wrap
ME.insert(vm.$editor, wrap, true)
layer.close(h1ID)
},
offset: [
offset.top + 37 - ME.doc.scrollTop(),
'auto',
'auto',
offset.left - ME.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>'
})
},
quote: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本'
wrap = '> ' + wrap
function objArr(num){
var arr = []
while(num > 0){
arr.push({v: 0})
num--
ME.insert(vm.$editor, wrap, true)
},
bold: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '\\*\\*')
wrap = wrap === wraped ? '**' + wrap + '**' : wraped
ME.insert(vm.$editor, wrap, true)
},
italic: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '_')
wrap = wrap === wraped ? '_' + wrap + '_' : wraped
ME.insert(vm.$editor, wrap, true)
},
through: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '~~')
wrap = wrap === wraped ? '~~' + wrap + '~~' : wraped
ME.insert(vm.$editor, wrap, true)
},
unordered: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本'
wrap = '* ' + wrap
ME.insert(vm.$editor, wrap, false)
},
ordered: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本'
wrap = '1. ' + wrap
ME.insert(vm.$editor, wrap, false)
},
hr: function(elem, vm) {
ME.insert(vm.$editor, '\n\n---\n\n', false)
},
link: function(elem, vm) {
var offset = Anot(elem).offset(),
wrap = ME.selection(vm.$editor) || '',
layid = layer.open({
type: 7,
menubar: false,
shadeClose: true,
fixed: true,
link: '',
linkName: wrap,
linkTarget: 1,
$confirm: function() {
var lvm = Anot.vmodels[layid]
if (!lvm.link || !lvm.linkName) {
return layer.alert('链接文字和地址不能为空')
}
var val =
'[' +
lvm.linkName +
'](' +
lvm.link +
(lvm.linkTarget === 1 ? ' "target=_blank"' : '') +
')'
ME.insert(vm.$editor, val, false)
layer.close(layid)
},
offset: [
offset.top + 37 - ME.doc.scrollTop(),
'auto',
'auto',
offset.left - ME.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>'
})
},
time: function(elem, vm) {
ME.insert(vm.$editor, new Date().format(), false)
},
face: function(elem, vm) {
var offset = Anot(elem).offset(),
faceid = 0,
layid = 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()
],
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)
}
return arr
}
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
}
ME.addon = {
h1: function(elem, vm){
var offset = yua(elem).offset(),
wrap = ME.selection(vm.$editor, true) || '在此输入文本',
h1ID = layer.open({
type: 7,
menubar: false,
shadeClose: true,
fixed: true,
$insert: function(level){
wrap = wrap.replace(/^#{1,6} /, '')
wrap = ME.repeat('#', level) + ' ' + wrap
ME.insert(vm.$editor, wrap, true)
layer.close(h1ID)
},
offset: [offset.top + 37 - ME.doc.scrollTop(), 'auto', 'auto', offset.left - ME.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>'
})
},
quote: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本'
wrap = '> ' + wrap
ME.insert(vm.$editor, wrap, true)
},
bold: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '\\*\\*')
wrap = wrap === wraped ? ('**' + wrap + '**') : wraped
ME.insert(vm.$editor, wrap, true)
},
italic: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '_')
wrap = wrap === wraped ? ('_' + wrap + '_') : wraped
ME.insert(vm.$editor, wrap, true)
},
through: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '~~')
wrap = wrap === wraped ? ('~~' + wrap + '~~') : wraped
ME.insert(vm.$editor, wrap, true)
},
unordered: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本'
wrap = '* ' + wrap
ME.insert(vm.$editor, wrap, false)
},
ordered: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本'
wrap = '1. ' + wrap
ME.insert(vm.$editor, wrap, false)
},
hr: function(elem, vm){
ME.insert(vm.$editor, '\n\n---\n\n', false)
},
link: function(elem, vm){
var offset = yua(elem).offset(),
wrap = ME.selection(vm.$editor) || '',
layid = layer.open({
type: 7,
menubar: false,
shadeClose: true,
fixed: true,
link: '',
linkName: wrap,
linkTarget: 1,
$confirm: function(){
var lvm = yua.vmodels[layid]
if(!lvm.link || !lvm.linkName){
return layer.alert('链接文字和地址不能为空')
}
var val = '[' + lvm.linkName + ']('
+ lvm.link
+ (lvm.linkTarget === 1 ? ' "target=_blank"' : '')
+ ')'
ME.insert(vm.$editor, val, false)
layer.close(layid)
},
offset: [offset.top + 37 - ME.doc.scrollTop(), 'auto', 'auto', offset.left - ME.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>'
})
},
time: function(elem, vm){
ME.insert(vm.$editor, new Date().format(), false)
},
face: function(elem, vm){
var offset = yua(elem).offset(),
faceid = 0,
layid = 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()],
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)
}
})
},
table: function(elem, vm){
var offset = yua(elem).offset();
layer.open({
type: 7,
title: '0行 x 0列',
fixed: true,
shadeClose: true,
offset: [offset.top + 37 - ME.doc.scrollTop(), 'auto', 'auto', offset.left - ME.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 = yua.vmodels[id],
lastx,lasty;
yua(tb).bind('mousemove', function(ev){
if(ev.target.nodeName === 'SPAN'){
var x = ev.target.dataset.x - 0,
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
}
}
}
})
yua(tb).bind('mouseleave', function(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
}
}
})
yua(tb).bind('click', function(ev){
if(ev.target.nodeName === 'SPAN'){
var x = ev.target.dataset.x - 0 + 1,
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)
}
})
}
})
},
image: function(elem, vm){
var offset = yua(elem).offset(),
wrap = ME.selection(vm.$editor) || '',
layid = layer.open({
type: 7,
menubar: false,
shadeClose: true,
fixed: true,
img: '',
imgAlt: wrap,
$confirm: function(){
var lvm = yua.vmodels[layid]
if(!lvm.img || !lvm.imgAlt){
return layer.alert('图片描述和图片地址不能为空')
}
var val = '![' + lvm.imgAlt + '](' + lvm.img + ')'
ME.insert(vm.$editor, val, false)
layer.close(layid)
},
offset: [offset.top + 37 - ME.doc.scrollTop(), 'auto', 'auto', offset.left - ME.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>'
})
},
file: function(elem, vm){
this.link(elem, vm, false)
},
inlinecode: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '`');
wrap = wrap === wraped ? ('`' + wrap + '`') : wraped
ME.insert(vm.$editor, wrap, true)
},
blockcode: function(elem, vm){
var layid = layer.open({
type: 7,
title: '添加代码块',
$lang: [
{id: 'asp'},
{id: 'actionscript', name: 'ActionScript(3.0)/Flash/Flex'},
{id: 'bash', name: 'Bash/Shell/Bat'},
{id: 'css'},
{id: 'c', name: 'C'},
{id: 'cpp', name: 'C++'},
{id: 'csharp', name: 'C#'},
{id: 'coffeescript', name: 'CoffeeScript'},
{id: 'd', name: 'D'},
{id: 'dart'},
{id: 'delphi', name: 'Delphi/Pascal'},
{id: 'erlang'},
{id: 'go', name: 'Golang'},
{id: 'html'},
{id: 'java'},
{id: 'javascript'},
{id: 'json'},
{id: 'lua'},
{id: 'less'},
{id: 'markdown'},
{id: 'nginx'},
{id: 'objective-c'},
{id: 'php'},
{id: 'perl'},
{id: 'python'},
{id: 'r', name: 'R'},
{id: 'ruby'},
{id: 'sql'},
{id: 'sass', name: 'SASS/SCSS'},
{id: 'swift'},
{id: 'typescript'},
{id: 'xml'},
{id: 'yaml'},
{id: 'other', name: '其他语言'},
],
lang: 'javascript',
code: '',
$confirm: function(){
var lvm = yua.vmodels[layid]
var val = '\n```' + lvm.lang + '\n' + (lvm.code || '//在此输入代码') + '\n```\n'
ME.insert(vm.$editor, val, false)
layer.close(layid)
},
content: '<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>'
+ '</select>'
+ '</section>'
+ '<section>'
+ '<textarea :duplex="code" placeholder="在这里输入/粘贴代码"></textarea>'
+ '</section>'
+ '<section class="do-fn-cl">'
+ '<a href="javascript:;" class="submit" :click="$confirm">确定</a>'
+ '</section>'
+ '</div>'
})
},
preview: function(elem, vm){
vm.preview = !vm.preview
if(vm.preview){
vm.htmlTxt = vm.$htmlTxt
})
},
table: function(elem, vm) {
var offset = Anot(elem).offset()
layer.open({
type: 7,
title: '0行 x 0列',
fixed: true,
shadeClose: true,
offset: [
offset.top + 37 - ME.doc.scrollTop(),
'auto',
'auto',
offset.left - ME.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) {
if (ev.target.nodeName === 'SPAN') {
var x = ev.target.dataset.x - 0,
y = ev.target.dataset.y - 0
if (x === lastx && y === lasty) {
return
}
},
fullscreen: function(elem, vm){
vm.fullscreen = !vm.fullscreen
vm.$onFullscreen(vm.fullscreen)
},
about: function(elem){
var offset = yua(elem).offset()
layer.open({
type: 7,
title: '关于编辑器',
offset: [offset.top + 37 - ME.doc.scrollTop()],
content: '<div class="do-meditor-about do-meditor-font">'
+ '<pre>'
+ ' __ __ _____ _ _ _\n'
+ '| \\/ | ____|__| (_) |_ ___ _ __\n'
+ '| |\\/| | _| / _` | | __/ _ \\| \'__|\n'
+ '| | | | |__| (_| | | || (_) | |\n'
+ '|_| |_|_____\\__,_|_|\\__\\___/|_| '
+ 'v' + ME.version + '</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>'
})
}
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
}
}
}
})
Anot(tb).bind('mouseleave', function(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
}
}
})
Anot(tb).bind('click', function(ev) {
if (ev.target.nodeName === 'SPAN') {
var x = ev.target.dataset.x - 0 + 1,
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)
}
})
}
})
},
image: function(elem, vm) {
var offset = Anot(elem).offset(),
wrap = ME.selection(vm.$editor) || '',
layid = layer.open({
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.close(layid)
},
offset: [
offset.top + 37 - ME.doc.scrollTop(),
'auto',
'auto',
offset.left - ME.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>'
})
},
file: function(elem, vm) {
this.link(elem, vm, false)
},
inlinecode: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '`')
wrap = wrap === wraped ? '`' + wrap + '`' : wraped
ME.insert(vm.$editor, wrap, true)
},
blockcode: function(elem, vm) {
var layid = layer.open({
type: 7,
title: '添加代码块',
$lang: [
{ id: 'asp' },
{ id: 'actionscript', name: 'ActionScript(3.0)/Flash/Flex' },
{ id: 'bash', name: 'Bash/Shell/Bat' },
{ id: 'css' },
{ id: 'c', name: 'C' },
{ id: 'cpp', name: 'C++' },
{ id: 'csharp', name: 'C#' },
{ id: 'coffeescript', name: 'CoffeeScript' },
{ id: 'd', name: 'D' },
{ id: 'dart' },
{ id: 'delphi', name: 'Delphi/Pascal' },
{ id: 'erlang' },
{ id: 'go', name: 'Golang' },
{ id: 'html' },
{ id: 'java' },
{ id: 'javascript' },
{ id: 'json' },
{ id: 'lua' },
{ id: 'less' },
{ id: 'markdown' },
{ id: 'nginx' },
{ id: 'objective-c' },
{ id: 'php' },
{ id: 'perl' },
{ id: 'python' },
{ id: 'r', name: 'R' },
{ id: 'ruby' },
{ id: 'sql' },
{ id: 'sass', name: 'SASS/SCSS' },
{ id: 'swift' },
{ id: 'typescript' },
{ id: 'xml' },
{ id: 'yaml' },
{ id: 'other', name: '其他语言' }
],
lang: 'javascript',
code: '',
$confirm: function() {
var lvm = Anot.vmodels[layid]
var val =
'\n```' + lvm.lang + '\n' + (lvm.code || '//在此输入代码') + '\n```\n'
ME.insert(vm.$editor, val, false)
layer.close(layid)
},
content:
'<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>' +
'</select>' +
'</section>' +
'<section>' +
'<textarea :duplex="code" placeholder="在这里输入/粘贴代码"></textarea>' +
'</section>' +
'<section class="do-fn-cl">' +
'<a href="javascript:;" class="submit" :click="$confirm">确定</a>' +
'</section>' +
'</div>'
})
},
preview: function(elem, vm) {
vm.preview = !vm.preview
if (vm.preview) {
vm.htmlTxt = vm.$htmlTxt
}
},
fullscreen: function(elem, vm) {
vm.fullscreen = !vm.fullscreen
vm.$onFullscreen(vm.fullscreen)
},
about: function(elem) {
var offset = Anot(elem).offset()
layer.open({
type: 7,
title: '关于编辑器',
offset: [offset.top + 37 - ME.doc.scrollTop()],
content:
'<div class="do-meditor-about do-meditor-font">' +
'<pre>' +
' __ __ _____ _ _ _\n' +
'| \\/ | ____|__| (_) |_ ___ _ __\n' +
"| |\\/| | _| / _` | | __/ _ \\| '__|\n" +
'| | | | |__| (_| | | || (_) | |\n' +
'|_| |_|_____\\__,_|_|\\__\\___/|_| ' +
'v' +
ME.version +
'</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>'
})
}
}
})
export default addon

470
src/js/meditor/index.js Normal file
View File

@ -0,0 +1,470 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2017-04-17 16:37:12
*
*/
'use strict'
import 'prism/base'
import 'marked/index'
import addon from './addon/base'
import './skin/main.scss'
marked.setOptions({
highlight: function(code, lang) {
return Prism.highlight(code, Prism.languages[lang])
}
})
var editorVM = []
Anot.ui.meditor = '1.0.0'
//存放编辑器公共静态资源
window.ME = {
version: Anot.ui.meditor,
toolbar: {
//工具栏title
pipe: '',
h1: '标题',
quote: '引用文本',
bold: '粗体',
italic: '斜体',
through: '删除线',
unordered: '无序列表',
ordered: '有序列表',
link: '超链接',
hr: '横线',
time: '插入当前时间',
face: '表情',
table: '插入表格',
image: '插入图片',
file: '插入附件',
inlinecode: '行内代码',
blockcode: '代码块',
preview: '预览',
fullscreen: '全屏',
about: '关于编辑器'
},
addon, //已有插件
//往文本框中插入内容
insert: function(dom, val, isSelect) {
if (document.selection) {
dom.focus()
var 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
dom.value =
dom.value.slice(0, startPos) +
val +
dom.value.slice(endPos, dom.value.length)
dom.selectionStart = isSelect ? startPos : startPos + val.length
dom.selectionEnd = startPos + val.length
dom.scrollTop = scrollTop
dom.focus()
} else {
dom.value += val
dom.focus()
}
},
/**
* [selection 获取选中的文本]
* @param {[type]} dom [要操作的元素]
* @param {[type]} line [是否强制选取整行]
*/
selection: function(dom, line) {
if (document.selection) {
return document.selection.createRange().text
} else {
var startPos = dom.selectionStart,
endPos = dom.selectionEnd
if (endPos) {
//强制选择整行
if (line) {
startPos = dom.value.slice(0, startPos).lastIndexOf('\n')
var tmpEnd = dom.value.slice(endPos).indexOf('\n')
tmpEnd = tmpEnd < 0 ? 0 : tmpEnd
startPos += 1 //把\n加上
endPos += tmpEnd
dom.selectionStart = startPos
dom.selectionEnd = endPos
}
} else {
//强制选择整行
if (line) {
endPos = dom.value.indexOf('\n')
endPos = endPos < 0 ? dom.value.length : endPos
dom.selectionEnd = endPos
}
}
return dom.value.slice(startPos, endPos)
}
},
repeat: function(str, num) {
if (String.prototype.repeat) {
return str.repeat(num)
} else {
var result = ''
while (num > 0) {
result += str
num--
}
return result
}
},
get: function(id) {
if (id === void 0) {
id = editorVM.length - 1
}
var vm = editorVM[id]
if (vm) {
return {
id: vm.$id,
getVal: function() {
return vm.plainTxt.trim()
},
getHtml: function() {
return vm.$htmlTxt
},
setVal: function(txt) {
vm.plainTxt = txt || ''
},
show: function() {
vm.editorVisible = true
},
hide: function() {
vm.editorVisible = false
}
}
}
return null
},
doc: Anot(document)
}
//获取真实的引用路径,避免因为不同的目录结构导致加载失败的情况
for (var i in Anot.modules) {
if (/meditor/.test(i)) {
ME.path = i.slice(0, i.lastIndexOf('/'))
break
}
}
var elems = {
p: function(str, attr, inner) {
return inner ? '\n' + inner + '\n' : ''
},
br: '\n',
'h([1-6])': function(str, level, attr, inner) {
var h = ME.repeat('#', level)
return '\n' + h + ' ' + inner + '\n'
},
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'))
href = (href && href[1]) || ''
title = (title && title[1]) || ''
tar = (tar && tar[1]) || '_self'
href = href === 'javascript:void(0);' ? 'javascript:;' : href
return (
'[' +
(inner || href) +
'](' +
href +
' "title=' +
title +
';target=' +
tar +
'")'
)
},
em: function(str, attr, inner) {
return (inner && '_' + inner + '_') || ''
},
strong: function(str, attr, inner) {
return (inner && '**' + inner + '**') || ''
},
code: function(str, attr, inner) {
return (inner && '`' + inner + '`') || ''
},
pre: function(str, attr, inner) {
return '\n\n```\n' + inner + '\n```\n'
},
blockquote: function(str, attr, inner) {
return '> ' + inner.trim()
},
img: function(str, attr, inner) {
var src = attr.match(attrExp('src')),
alt = attr.match(attrExp('alt'))
src = (src && src[1]) || ''
alt = (alt && alt[1]) || ''
return '![' + alt + '](' + src + ')'
}
}
function attrExp(field) {
return new RegExp(field + '\\s?=\\s?["\']?([^"\']*)["\']?', 'i')
}
function tagExp(tag, open) {
var exp = ''
if (['br', 'hr', 'img'].indexOf(tag) > -1) {
exp = '<' + tag + '([^>]*)\\/?>'
} else {
exp = '<' + tag + '([^>]*)>([\\s\\S]*?)<\\/' + tag + '>'
}
return new RegExp(exp, 'gi')
}
function html2md(str) {
try {
str = decodeURIComponent(str)
} catch (err) {}
str = str.replace(/\t/g, ' ').replace(/<meta [^>]*>/, '')
for (var i in elems) {
var cb = elems[i],
exp = tagExp(i)
if (i === 'blockquote') {
while (str.match(exp)) {
str = str.replace(exp, cb)
}
} else {
str = str.replace(exp, cb)
}
if (i === 'em') {
exp = tagExp('i')
str = str.replace(exp, cb)
}
if (i === 'strong') {
exp = tagExp('b')
str = str.replace(exp, cb)
}
}
var liExp = /<(ul|ol)[^>]*>(?:(?!<ul|<ol)[\s\S])*?<\/\1>/gi
while (str.match(liExp)) {
str = str.replace(liExp, function(match) {
match = match.replace(/<(ul|ol)[^>]*>([\s\S]*?)<\/\1>/gi, function(
m,
t,
inner
) {
var li = inner.split('</li>')
li.pop()
for (var i = 0, len = li.length; i < len; i++) {
var pre = t === 'ol' ? i + 1 + '. ' : '* '
li[i] =
pre +
li[i]
.replace(/\s*<li[^>]*>([\s\S]*)/i, function(m, n) {
n = n.trim().replace(/\n/g, '\n ')
return n
})
.replace(/<[\/]?[\w]*[^>]*>/g, '')
}
return li.join('\n')
})
return '\n' + match.trim()
})
}
str = str
.replace(/<[\/]?[\w]*[^>]*>/g, '')
.replace(/```([\w\W]*)```/g, function(str, inner) {
inner = inner
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
return '```' + inner + '```'
})
return str
}
var defaultToolbar = [
'h1',
'quote',
'|',
'bold',
'italic',
'through',
'|',
'unordered',
'ordered',
'|',
'hr',
'link',
'time',
'face',
'|',
'table',
'image',
'file',
'inlinecode',
'blockcode',
'|',
'preview',
'fullscreen',
'|',
'about'
],
extraAddons = []
function tool(name) {
name = (name + '').trim().toLowerCase()
name = '|' === name ? 'pipe' : name
return (
'<span title="' +
ME.toolbar[name] +
'" class="icon-' +
name +
'" ' +
(name !== 'pipe' ? ':click="onToolClick(\'' + name + '\', $event)"' : '') +
'></span>'
)
}
Anot.component('meditor', {
render: function() {
var toolbar = (this.toolbar || defaultToolbar)
.map(function(it) {
return 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)
},
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
}
if (base.hasOwnProperty('$show')) {
base.editorVisible = base.$show
delete base.$show
}
return base
},
componentWillMount: function(vm) {},
componentDidMount: function(vm, elem) {
console.log(this)
// vm.$editor = elem.children[1]
// editorVM.push(vm)
// //自动加载额外的插件
// require(extraAddons, function() {
// var args = Array.prototype.slice.call(arguments, 0)
// args.forEach(function(addon) {
// addon && addon(vm)
// })
// })
// Anot(vm.$editor).bind('keydown', function(ev) {
// var wrap = ME.selection(vm.$editor) || '',
// select = !!wrap
// //tab键改为插入2个空格,阻止默认事件,防止焦点失去
// if (ev.keyCode === 9) {
// wrap = wrap
// .split('\n')
// .map(function(it) {
// return ev.shiftKey ? it.replace(/^\s\s/, '') : ' ' + it
// })
// .join('\n')
// ME.insert(this, wrap, select)
// ev.preventDefault()
// }
// //修复按退格键删除选中文本时,选中的状态不更新的bug
// if (ev.keyCode === 8) {
// if (select) {
// ME.insert(this, '', select)
// ev.preventDefault()
// }
// }
// })
// //编辑器成功加载的回调
// vm.$onSuccess(ME.get(), vm)
},
watch: {
plainTxt: function(val) {
this.$compile()
//只有开启实时预览,才会赋值给htmlTxt
if (this.preview) {
this.htmlTxt = this.$htmlTxt
}
this.$onUpdate(this.plainTxt, vm.$htmlTxt)
}
},
state: {
disabled: false, //禁用编辑器
fullscreen: false, //是否全屏
preview: false, //是否显示预览
$editor: null, //编辑器元素
editorVisible: true,
$htmlTxt: '', //临时储存html文本
htmlTxt: '', //用于预览渲染
plainTxt: '', //纯md文本
$safelyCompile: true
},
methods: {
onToolClick: function(name, ev) {
if (ME.addon[name]) {
ME.addon[name].call(ME, ev.target, this)
} else {
console.log('%c没有对应的插件%c[%s]', 'color:#f00;', '', name)
}
},
$onSuccess: Anot.noop,
$onUpdate: Anot.noop,
$onFullscreen: Anot.noop,
$paste: function(ev) {
ev.preventDefault()
var txt = ev.clipboardData.getData('text/plain').trim(),
html = ev.clipboardData.getData('text/html').trim()
html = html2md(html)
if (html) {
ME.insert(this, html)
} else if (txt) {
ME.insert(this, txt)
}
this.plainTxt = this.value
},
compile: function() {
var txt = this.plainTxt.trim()
if (this.$safelyCompile) {
txt = txt
.replace(/<script([^>]*?)>/g, '&lt;script$1&gt;')
.replace(/<\/script>/g, '&lt;/script&gt;')
}
//只解析,不渲染
this.$htmlTxt = marked(txt)
}
}
})

View File

@ -1,440 +0,0 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2017-04-17 16:37:12
*
*/
"use strict";
define([
'yua',
'lib/prism/base',
'lib/marked/main',
'css!./skin/main',
], function(yua){
marked.setOptions({
highlight: function(code, lang){
return Prism.highlight(code, Prism.languages[lang])
}
})
var editorVM = []
yua.ui.meditor = '1.0.0'
//存放编辑器公共静态资源
window.ME = {
version: yua.ui.meditor,
toolbar: { //工具栏title
pipe: '',
h1: '标题',
quote: '引用文本',
bold: '粗体',
italic: '斜体',
through: '删除线',
unordered: '无序列表',
ordered: '有序列表',
link: '超链接',
hr: '横线',
time: '插入当前时间',
face: '表情',
table: '插入表格',
image: '插入图片',
file: '插入附件',
inlinecode: '行内代码',
blockcode: '代码块',
preview: '预览',
fullscreen: '全屏',
about: '关于编辑器',
},
addon: {}, //已有插件
//往文本框中插入内容
insert: function(dom, val, isSelect){
if(document.selection){
dom.focus()
var 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;
dom.value = dom.value.slice(0, startPos)
+ val
+ dom.value.slice(endPos, dom.value.length);
dom.selectionStart = isSelect ? startPos : (startPos + val.length)
dom.selectionEnd = startPos + val.length
dom.scrollTop = scrollTop
dom.focus()
}else{
dom.value += val;
dom.focus()
}
},
/**
* [selection 获取选中的文本]
* @param {[type]} dom [要操作的元素]
* @param {[type]} line [是否强制选取整行]
*/
selection: function(dom, line){
if(document.selection){
return document.selection.createRange().text
}else{
var startPos = dom.selectionStart,
endPos = dom.selectionEnd;
if(endPos){
//强制选择整行
if(line) {
startPos = dom.value.slice(0, startPos).lastIndexOf('\n');
var tmpEnd = dom.value.slice(endPos).indexOf('\n');
tmpEnd = tmpEnd < 0 ? 0 : tmpEnd
startPos += 1 //把\n加上
endPos += tmpEnd;
dom.selectionStart = startPos
dom.selectionEnd = endPos
}
}else{
//强制选择整行
if(line) {
endPos = dom.value.indexOf('\n')
endPos = endPos < 0 ? dom.value.length : endPos
dom.selectionEnd = endPos
}
}
return dom.value.slice(startPos, endPos)
}
},
repeat: function(str, num){
if(String.prototype.repeat){
return str.repeat(num)
}else{
var result = ''
while(num > 0){
result += str;
num--
}
return result
}
},
get: function(id){
if(id === void 0){
id = editorVM.length - 1
}
var vm = editorVM[id]
if(vm){
return {
id: vm.$id,
getVal: function(){
return vm.plainTxt.trim()
},
getHtml: function(){
return vm.$htmlTxt
},
setVal: function(txt){
vm.plainTxt = txt || ''
},
show: function(){
vm.editorVisible = true
},
hide: function(){
vm.editorVisible = false
}
}
}
return null
},
doc: yua(document)
}
//获取真实的引用路径,避免因为不同的目录结构导致加载失败的情况
for(var i in yua.modules){
if(/meditor/.test(i)) {
ME.path = i.slice(0, i.lastIndexOf('/'))
break;
}
}
var elems = {
p: function(str, attr, inner){
return inner ? ('\n' + inner + '\n') : ''
},
br: '\n',
'h([1-6])': function(str, level, attr, inner){
var h = ME.repeat('#', level)
return '\n' + h + ' ' + inner + '\n'
},
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'));
href = href && href[1] || ''
title = title && title[1] || ''
tar = tar && tar[1] || '_self'
href = href === 'javascript:void(0);' ? 'javascript:;' : href
return '[' + (inner || href) + '](' + href + ' "title=' + title + ';target=' + tar + '")'
},
em: function(str, attr, inner){
return inner && ('_' + inner + '_') || ''
},
strong: function(str, attr, inner){
return inner && ('**' + inner + '**') || ''
},
code: function(str, attr, inner){
return inner && ('`' + inner + '`') || ''
},
pre: function(str, attr, inner){
return '\n\n```\n' + inner + '\n```\n'
},
blockquote: function(str, attr, inner){
return '> ' + inner.trim()
},
img: function(str, attr, inner){
var src = attr.match(attrExp('src')),
alt = attr.match(attrExp('alt'));
src = src && src[1] || ''
alt = alt && alt[1] || ''
return '![' + alt + '](' + src + ')'
}
}
function attrExp(field){
return new RegExp(field + '\\s?=\\s?["\']?([^"\']*)["\']?', 'i')
}
function tagExp(tag, open){
var exp = ''
if(['br', 'hr', 'img'].indexOf(tag) > -1){
exp = '<' + tag + '([^>]*)\\/?>'
}else{
exp = '<' + tag + '([^>]*)>([\\s\\S]*?)<\\/' + tag + '>'
}
return new RegExp(exp, 'gi')
}
function html2md(str){
try{
str = decodeURIComponent(str)
}catch(err){}
str = str.replace(/\t/g, ' ').replace(/<meta [^>]*>/, '')
for(var i in elems){
var cb = elems[i],
exp = tagExp(i);
if(i === 'blockquote'){
while(str.match(exp)){
str = str.replace(exp, cb)
}
}else{
str = str.replace(exp, cb)
}
if(i === 'em'){
exp = tagExp('i')
str = str.replace(exp, cb)
}
if(i === 'strong'){
exp = tagExp('b')
str = str.replace(exp, cb)
}
}
var liExp = /<(ul|ol)[^>]*>(?:(?!<ul|<ol)[\s\S])*?<\/\1>/gi
while(str.match(liExp)) {
str = str.replace(liExp, function(match){
match = match.replace(/<(ul|ol)[^>]*>([\s\S]*?)<\/\1>/gi, function(m, t, inner){
var li = inner.split('</li>')
li.pop()
for(var i = 0,len = li.length; i < len; i++){
var pre = t === 'ol' ? ((i + 1) + '. ') : '* '
li[i] = pre + li[i].replace(/\s*<li[^>]*>([\s\S]*)/i, function(m, n){
n = n.trim()
.replace(/\n/g, '\n ')
return n
}).replace(/<[\/]?[\w]*[^>]*>/g, '')
}
return li.join('\n')
})
return '\n' + match.trim()
})
}
str = str.replace(/<[\/]?[\w]*[^>]*>/g, '')
.replace(/```([\w\W]*)```/g, function(str, inner){
inner = inner.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>')
return '```' + inner + '```'
})
return str
}
require([
ME.path + '/addon/base'
], function(){
var defaultToolbar = ['h1', 'quote', '|',
'bold', 'italic', 'through', '|',
'unordered', 'ordered', '|',
'hr', 'link', 'time', 'face', '|',
'table','image', 'file','inlinecode', 'blockcode','|',
'preview', 'fullscreen', '|',
'about'
],
extraAddons = [];
function tool(name){
name = (name + '').trim().toLowerCase()
name = '|' === name ? 'pipe' : name
return '<span title="' + ME.toolbar[name] + '" class="icon-' + name+ '" '
+ (name !== 'pipe' ? (':click="$onToolbarClick(\'' + name + '\')"') : '')
+ '></span>'
}
yua.component('meditor', {
$template: '<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 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>',
$$template: function(txt){
var toolbar = (this.toolbar || defaultToolbar).map(function(it){
return tool(it)
}).join('')
delete this.toolbar
return txt.replace(/\{uuid\}/g, this.$id).replace(/\{toolbar\}/g, toolbar)
},
$construct: function(base, opt, attr){
yua.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(base.hasOwnProperty('$show')){
base.editorVisible = base.$show
delete base.$show
}
return base
},
$init: function(vm){
vm.$watch('plainTxt', function(val){
vm.$compile()
//只有开启实时预览,才会赋值给htmlTxt
if(vm.preview){
vm.htmlTxt = vm.$htmlTxt
}
vm.$onUpdate(vm.plainTxt, vm.$htmlTxt)
})
vm.$onToolbarClick = function(name){
if(ME.addon[name]){
ME.addon[name].call(ME.addon, this, vm)
}else{
console.log('%c没有对应的插件%c[%s]', 'color:#f00;', '',name)
}
}
vm.$paste = function(ev){
ev.preventDefault()
var txt = ev.clipboardData.getData('text/plain').trim(),
html = ev.clipboardData.getData('text/html').trim();
html = html2md(html)
if(html){
ME.insert(this, html)
}else if(txt) {
ME.insert(this, txt)
}
vm.plainTxt = this.value
}
},
$ready: function(vm, elem){
vm.$editor = elem.children[1]
editorVM.push(vm)
//自动加载额外的插件
require(extraAddons, function(){
var args = Array.prototype.slice.call(arguments, 0)
args.forEach(function(addon){
addon && addon(vm)
})
})
yua(vm.$editor).bind('keydown', function(ev){
var wrap = ME.selection(vm.$editor) || '',
select = !!wrap;
//tab键改为插入2个空格,阻止默认事件,防止焦点失去
if(ev.keyCode === 9){
wrap = wrap.split('\n').map(function(it){
return ev.shiftKey ? it.replace(/^\s\s/, '') : ' ' + it
}).join('\n')
ME.insert(this, wrap, select)
ev.preventDefault()
}
//修复按退格键删除选中文本时,选中的状态不更新的bug
if(ev.keyCode === 8){
if(select){
ME.insert(this, '', select)
ev.preventDefault()
}
}
})
//编辑器成功加载的回调
vm.$onSuccess(ME.get(), vm)
},
$paste: yua.noop,
$compile: function(){
var txt = this.plainTxt.trim()
if(this.$safelyCompile){
txt = txt.replace(/<script([^>]*?)>/g, '&lt;script$1&gt;')
.replace(/<\/script>/g, '&lt;/script&gt;')
}
//只解析,不渲染
this.$htmlTxt = marked(txt)
},
$onToolbarClick: yua.noop,
$onSuccess: yua.noop,
$onUpdate: yua.noop,
$onFullscreen: yua.noop,
$safelyCompile: true,
disabled: false, //禁用编辑器
fullscreen: false, //是否全屏
preview: false, //是否显示预览
$editor: null, //编辑器元素
editorVisible: true,
$htmlTxt: '', //临时储存html文本
htmlTxt: '', //用于预览渲染
plainTxt: '' //纯md文本
})
})
})

View File

@ -6,15 +6,15 @@
*
*/
@import "../../../../css/var.scss";
@import "var.scss";
.do-meditor {position:relative;width:100%;height:100%;min-height:180px;padding-top:43px;border:1px solid #ddd;background:#fff;color:#666;
::-webkit-scrollbar {width:5px;height:5px;background:#ebeeec;}
::-webkit-scrollbar:hover {background:rgba(0,0,0,.05);}
::-webkit-scrollbar-button {display:none;}
::-webkit-scrollbar-thumb {background:nth($ct, 1);}
::-webkit-scrollbar-thumb:hover {background:nth($ct, 3);}
::-webkit-scrollbar {width:5px;height:5px;background:#ebeeec;}
::-webkit-scrollbar:hover {background:rgba(0,0,0,.05);}
::-webkit-scrollbar-button {display:none;}
::-webkit-scrollbar-thumb {background:nth($ct, 1);}
::-webkit-scrollbar-thumb:hover {background:nth($ct, 3);}
}
.do-meditor-font {font-family:"PingFang SC","Helvetica Neue","Hiragino Sans GB","Segoe UI","Microsoft YaHei",sans-serif;}
@ -32,104 +32,104 @@
/*表格模块*/
.do-meditor-table {width:270px;height:270px;padding:10px;
li {width:100%;height:25px;
span {float:left;width:25px;height:25px;border:2px solid #fff;background:#f2f2f2;}
span.active {background:rgba(4,151,137,.2);}
}
li {width:100%;height:25px;
span {float:left;width:25px;height:25px;border:2px solid #fff;background:#f2f2f2;}
span.active {background:rgba(4,151,137,.2);}
}
}
/*表情模块*/
.do-meditor-face {float:left;;width:241px;height:241px;margin:10px;border-top:1px solid #e2e2e2;border-left:1px solid #e2e2e2;
li {float:left;width:40px;height:40px;padding:8px;border:1px solid #e2e2e2;border-top:0;border-left:0}
li img {width:100%;@include ts();}
li:hover img {-webkit-transform:scale(3);-moz-transform:scale(3);-ms-transform:scale(3);transform:scale(3);}
li {float:left;width:40px;height:40px;padding:8px;border:1px solid #e2e2e2;border-top:0;border-left:0}
li img {width:100%;@include ts();}
li:hover img {-webkit-transform:scale(3);-moz-transform:scale(3);-ms-transform:scale(3);transform:scale(3);}
}
/*段落模块*/
.do-meditor-h1 {width:150px;height:auto;padding:5px 0;
li {width:100%;height:auto;padding:0 10px;line-height:1.5;font-size:18px;cursor:default;}
li:hover {background:#f2f2f2;}
li::before {font-family:"ui font" !important;-webkit-font-smoothing: antialiased;-webkit-text-stroke-width: 0.2px;-moz-osx-font-smoothing: grayscale;}
li.h1 {font-size:23px;}
li.h2 {font-size:21px;}
li.h1::before {content:"\e62b "}
li.h2::before {content:"\e625 "}
li.h3::before {content:"\e626 "}
li.h4::before {content:"\e629 "}
li.h5::before {content:"\e62a "}
li.h6::before {content:"\e624 "}
li {width:100%;height:auto;padding:0 10px;line-height:1.5;font-size:18px;cursor:default;}
li:hover {background:#f2f2f2;}
li::before {font-family:"ui font" !important;-webkit-font-smoothing: antialiased;-webkit-text-stroke-width: 0.2px;-moz-osx-font-smoothing: grayscale;}
li.h1 {font-size:23px;}
li.h2 {font-size:21px;}
li.h1::before {content:"\e62b "}
li.h2::before {content:"\e625 "}
li.h3::before {content:"\e626 "}
li.h4::before {content:"\e629 "}
li.h5::before {content:"\e62a "}
li.h6::before {content:"\e624 "}
}
/*通用输入模块, 链接/图片插入/文件插入/代码块插入*/
.do-meditor-common {width:360px;height:auto;padding:15px 20px;
section {width:100%;height: 35px;margin:10px 0;line-height:35px;
section {width:100%;height: 35px;margin:10px 0;line-height:35px;
&.input {line-height:33px;border:1px solid #e9e9e9;}
.label {float: left;width:30%;text-align:center;background:#f7f7f7;}
label {float: left;width:50%;}
.txt {float: left;width:70%;height:33px;padding:0 8px;border:0;border-left:1px solid #e9e9e9;background:#fff;color:#666;}
.submit {float:right;width:30%;height:35px;background:#ddd;color:#666;text-align:center;}
}
&.input {line-height:33px;border:1px solid #e9e9e9;}
.label {float: left;width:30%;text-align:center;background:#f7f7f7;}
label {float: left;width:50%;}
.txt {float: left;width:70%;height:33px;padding:0 8px;border:0;border-left:1px solid #e9e9e9;background:#fff;color:#666;}
.submit {float:right;width:30%;height:35px;background:#ddd;color:#666;text-align:center;}
}
}
.do-meditor-codeblock {width:780px;height:auto;padding:15px 20px;background:#fafafa;
section {display:block;width:100%;height:auto;margin:10px 0;line-height:35px;
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-bottom:1px solid #e7e7e7;background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAMAAABV0m3JAAAADFBMVEUAAAD///+Pj4+JiYkxcGihAAAABHRSTlMAABBwqVQF9wAAADNJREFUeNqlzjEOACAMw8DQ/v/PSE5FFhaEx5usdekBuzRVH0RtCqJYELUFrVjQigX/5jdvzgDh9izlMQAAAABJRU5ErkJggg==) no-repeat right 8px;color:nth($cgr, 1);outline:none;-webkit-appearance:none;-moz-appearance: none;@include ts;
.label {float: left;width:80px;}
select {float:left;width:200px;height:35px;padding:0 30px 0 10px;border:0;border-bottom:1px solid #e7e7e7;background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAMAAABV0m3JAAAADFBMVEUAAAD///+Pj4+JiYkxcGihAAAABHRSTlMAABBwqVQF9wAAADNJREFUeNqlzjEOACAMw8DQ/v/PSE5FFhaEx5usdekBuzRVH0RtCqJYELUFrVjQigX/5jdvzgDh9izlMQAAAABJRU5ErkJggg==) no-repeat right 8px;color:nth($cgr, 1);outline:none;-webkit-appearance:none;-moz-appearance: none;@include ts;
&::-ms-expand {display:none;}
&::-ms-expand {display:none;}
&:focus {border-color:nth($ct, 1);}
}
textarea {width:100%;height:300px;padding:5px 10px;border:1px solid #ddd;background:#fff;resize:none;outline:none;}
.submit {float:right;width:80px;height:35px;background:#ddd;color:#666;text-align:center;}
&:focus {border-color:nth($ct, 1);}
}
textarea {width:100%;height:300px;padding:5px 10px;border:1px solid #ddd;background:#fff;resize:none;outline:none;}
.submit {float:right;width:80px;height:35px;background:#ddd;color:#666;text-align:center;}
}
}
.do-meditor {
.tool-bar {overflow:hidden;position:absolute;top:0;left:0;z-index:99;width:100%;height:43px;padding:5px 10px;border-bottom:1px solid #ddd;background:#f5f5f5;color:#666;
.tool-bar {overflow:hidden;position:absolute;top:0;left:0;z-index:99;width:100%;height:43px;padding:5px 10px;border-bottom:1px solid #ddd;background:#f5f5f5;color:#666;
span {display:inline-block;width:30px;height:32px;line-height:32px;text-align:center;font-size:20px;}
span:hover {background:#e5e5e5;}
.icon-pipe {width:20px;}
.icon-pipe:hover {background:none;}
.icon-pipe::before {content:"\e62c"}
.icon-h1::before {content:"\e62b"}
.icon-bold::before {content:"\e62f"}
.icon-italic::before {content:"\e639"}
.icon-through::before {content:"\e619"}
.icon-link::before {content:"\e61c"}
.icon-inlinecode::before {content:"\e63a"}
.icon-blockcode::before {content:"\e632"}
.icon-quote::before {content:"\e61b"}
.icon-hr::before {content:"\e614"}
.icon-time::before {content:"\e636"}
.icon-face::before {content:"\e630"}
.icon-image::before {content:"\e637"}
.icon-file::before {content:"\e618"}
.icon-preview::before {content:"\e61f"}
.icon-fullscreen::before {content:"\e621"}
.icon-table::before {content:"\e617"}
.icon-ordered::before {content:"\e638"}
.icon-unordered::before {content:"\e633"}
.icon-about::before {content:"\e700"}
}
span {display:inline-block;width:32px;height:32px;line-height:32px;text-align:center;font-size:28px;}
span:hover {background:#e5e5e5;}
.icon-pipe {width:20px;color:nth($cp, 3)}
.icon-pipe:hover {background:none;}
.icon-pipe::before {content:"\e677"}
.icon-h1::before {content:"\e65c"}
.icon-bold::before {content:"\e66c"}
.icon-italic::before {content:"\e670"}
.icon-through::before {content:"\e66d"}
.icon-link::before {content:"\e667"}
.icon-inlinecode::before {content:"\e67a"}
.icon-blockcode::before {content:"\e67b"}
.icon-quote::before {content:"\e66a"}
.icon-hr::before {content:"\e676"}
.icon-time::before {content:"\e675"}
.icon-face::before {content:"\e673"}
.icon-image::before {content:"\e682"}
.icon-file::before {content:"\e66b"}
.icon-preview::before {content:"\e67d"}
.icon-fullscreen::before {content:"\e67e"}
.icon-table::before {content:"\e65a"}
.icon-ordered::before {content:"\e664"}
.icon-unordered::before {content:"\e663"}
.icon-about::before {content:"\e672"}
}
.editor-body{overflow:hidden;overflow-y:auto;float:left;width:100%;height:100%;padding:5px 5px 50px;border:0;outline:none;resize:none;color:#666;background:#fff;}
.md-preview {float:right;overflow:hidden;overflow-y:auto;display:block;width:50%;height:100%;padding:10px 10px 50px;line-height:2;border-left:1px solid #ddd;color:#666;font-size:14px;background:#fff;}
.editor-body{overflow:hidden;overflow-y:auto;float:left;width:100%;height:100%;padding:5px 5px 50px;border:0;outline:none;resize:none;color:#666;background:#fff;}
.md-preview {float:right;overflow:hidden;overflow-y:auto;display:block;width:50%;height:100%;padding:10px 10px 50px;line-height:2;border-left:1px solid #ddd;color:#666;font-size:14px;background:#fff;}
/*全屏模式*/
&.fullscreen {position:fixed;left:0;top:0;z-index:999;}
/*全屏模式*/
&.fullscreen {position:fixed;left:0;top:0;z-index:999;}
&.preview .editor-body {width:50%}
&.preview .editor-body {width:50%}
}

View File

@ -22,10 +22,10 @@
.button,.page {display:inline-block;border:0;color: nth($cgr, 1);text-decoration:none;cursor:pointer;vertical-align:top;font-size:14px;font-weight:100;
&.home::after {content:"\e652";font-size:18px;}
&.prev::after {content:"\e659";font-size:18px;}
&.next::after {content:"\e658";font-size:18px;}
&.end::after {content:"\e653";font-size:18px;}
&.home::after {content:"\e691";font-size:18px;}
&.prev::after {content:"\e67c";font-size:18px;}
&.next::after {content:"\e66e";font-size:18px;}
&.end::after {content:"\e693";font-size:18px;}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1876
src/js/prism/index.js Normal file

File diff suppressed because one or more lines are too long