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

新增meditor;优化框架及组件的结构

old
宇天 2017-04-25 15:25:16 +08:00
parent ec07a3ed23
commit 4758fb26b5
73 changed files with 3056 additions and 911 deletions

View File

@ -33,7 +33,7 @@ q:before, q:after {content: '';content: none;}
table {border-collapse: collapse;border-spacing: 0;}
.do-fn-cl { *zoom: 1; }
.do-fn-cl:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; overflow:hidden;}
.do-fn-cl:after {visibility: hidden;overflow:hidden; display: block;height: 0;content: "."; clear: both;}
.do-fn-clear {clear:both;display:inline;}
.do-fn-show{display:block;}

View File

@ -1,4 +1,4 @@
define(["./codemirror", 'css!./codemirror'], function(CodeMirror) {
define(["./codemirror", 'css!./theme-dark'], function(CodeMirror) {
CodeMirror.defineMode("htmlmixed", function(config) {
var htmlMode = CodeMirror.getMode(config, {
name: "xml",

1
js/lib/codemirror/theme-light.css vendored Normal file
View File

@ -0,0 +1 @@
.CodeMirror{height:100%;line-height:1.5;font-family:monospace;position:relative;overflow:hidden;background:#272822;color:#f8f8f2}.CodeMirror-scroll{overflow:auto;height:100%;width:100%;position:relative;outline:0}.CodeMirror-scrollbar{position:absolute;right:0;top:0;overflow-x:hidden;overflow-y:scroll;z-index:5}.CodeMirror-scrollbar-inner{width:1px}.CodeMirror-scrollbar.cm-sb-overlap{position:absolute;z-index:1;float:none;right:0;min-width:12px}.CodeMirror-scrollbar.cm-sb-nonoverlap{min-width:12px}.CodeMirror-scrollbar.cm-sb-ie7{min-width:18px}.CodeMirror-gutter{position:absolute;left:0;top:0;z-index:10;background-color:transparent;border-right:1px solid #454545;min-width:2em;height:100%}.CodeMirror-gutter-text{color:#aaa;text-align:right;padding:.4em .2em .4em .4em;white-space:pre!important;cursor:default}.CodeMirror-lines{padding:.4em;white-space:pre;cursor:text}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;-o-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;padding:0;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;overflow:visible}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-wrap .CodeMirror-scroll{overflow-x:hidden}.CodeMirror textarea{outline:0!important}.CodeMirror pre.CodeMirror-cursor{z-index:10;position:absolute;visibility:hidden;border-left:1px solid #9effff;border-right:none;width:0}.cm-keymap-fat-cursor pre.CodeMirror-cursor{width:auto;border:0;background:0 0;background:rgba(0,200,0,.4);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800)}.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id){filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.CodeMirror-focused pre.CodeMirror-cursor{visibility:visible}.CodeMirror-focused div.CodeMirror-selected,div.CodeMirror-selected{background:#49483E}.CodeMirror-searching{background:#ffa;background:rgba(255,255,0,.4)}.cm-s-default span.cm-keyword{color:#f92672}.cm-s-default span.cm-atom{color:#ae81ff}.cm-s-default span.cm-number{color:#f30}.cm-s-default span.cm-def{color:#fd971f}.cm-s-default span.cm-variable{color:#f8f8f2}.cm-s-default span.cm-variable-2{color:#9effff}.cm-s-default span.cm-property,.cm-s-default span.cm-variable-3{color:#66d9ef}.cm-s-default span.cm-operator{color:#9effff}.cm-s-default span.cm-comment{color:#75715e}.cm-s-default span.cm-string{color:#e6db74}.cm-s-default span.cm-string-2{color:#f50}.cm-s-default span.cm-meta{color:#555}.cm-s-default span.cm-error{background:#f92672;color:#f8f8f0}.cm-s-default span.cm-qualifier{color:#75d908}.cm-s-default span.cm-builtin{color:#66d9ef}.cm-s-default span.cm-bracket{color:#f8f8f2}.cm-s-default span.cm-tag{color:#f92672}.cm-s-default span.cm-attribute{color:#a6e22e}.cm-s-default span.cm-header{color:#ae81ff}.cm-s-default span.cm-quote{color:#090}.cm-s-default span.cm-hr{color:#999}.cm-s-default span.cm-link{color:#ae81ff}span.cm-header,span.cm-strong{font-weight:700}span.cm-em{font-style:italic}span.cm-emstrong{font-style:italic;font-weight:700}span.cm-link{text-decoration:underline}span.cm-invalidchar{color:red}div.CodeMirror span.CodeMirror-matchingbracket{text-decoration:underline;color:#fff!important}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}@media print{.CodeMirror pre.CodeMirror-cursor{visibility:hidden}}

View File

@ -19,7 +19,7 @@ define(['yua'], function(){
}
}
}
yua.ui.drag = '0.0.1'
// 元素拖动
yua.directive('drag', {
priority: 1500,

Binary file not shown.

View File

@ -1,3 +1,14 @@
v0.0.4-base / 2017-04-20
==================
+ 优化offset的处理
+ 优化样式
v0.0.3-base / 2017-04-15
==================
+ 重构wrap方式创建弹窗实例的实现
v0.0.2-base / 2017-04-13
==================
+ 修复:layer方式创建实例时,漏掉自身的bug;

View File

@ -13,6 +13,8 @@ define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){
if(window.layer){
return window.layer
}
yua.ui.layer = '0.0.4-base'
var layerDom = {},
layerObj = {},
unique = null, //储存当前打开的1/2/3类型的弹窗
@ -55,6 +57,7 @@ define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){
return
}
layerObj[id].parentElem.replaceChild(layerObj[id].wrap, layerDom[id][1])
layerObj[id].wrap.style.display = 'none'
layerObj[id].show = false
}catch(err){}
@ -220,20 +223,21 @@ define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){
if(!yua.vmodels[conf]){
yua(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)
layerDom[conf][1].querySelector('.detail').appendChild(layerObj[conf].wrap)
layerObj[conf].wrap.style.display = ''
yua.scan(layerDom[conf][1])
layerObj[conf].obj.show()
return conf
}
}else{
return new __constructor(conf).init.$id
}
},
version: '0.0.2-base'
version: yua.ui.layer
};
/*type: { // 弹窗类型对应的id值
1: 'alert',
@ -295,7 +299,7 @@ define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){
}
layBox.innerHTML = this.getMenubar()
+ '<div class="layer-content do-fn-cl '
+ '<div class="layer-content do-layer-cl '
+ (this.init.icon === 0 && 'none-icon' || '')
+ '" style="'
+ boxcss
@ -306,7 +310,7 @@ define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){
+ (this.init.type === 5 && '<i class="arrow" style="border-top-color: '
+ this.init.background
+ '"></i>' || '')
delete this.init.wrap
return [this.init.shade ? coverBox : null, layBox]
},
getCont: function(){
@ -314,7 +318,9 @@ define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){
return this.getLoading(this.init.load)
}else{
return this.getIcon()
+ '<div class="detail" :html="content"></div>'
+ '<div class="detail" '
+ (this.init.wrap ? '' : ':html="content"')
+ '></div>'
}
},
getLoading: function(style){
@ -337,7 +343,7 @@ define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){
}
html += '>{{title}}'
+ '<a class="action-close deficon" :click="no(\'' + this.init.$id + '\')"></a>'
+ '<a class="action-close def-font" :click="no(\'' + this.init.$id + '\')"></a>'
+ '</div>'
}
return html
@ -348,7 +354,7 @@ define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){
return ''
}
if(this.init.type < 4 || this.init.type === 5 || this.init.specialMode){
return '<span class="deficon icon-' + this.init.icon + '"></span>'
return '<span class="def-font msg-icon icon-' + this.init.icon + '"></span>'
}
return ''
},
@ -422,6 +428,16 @@ define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){
style.right = fixOffset(_this.init.offset[1])
style.bottom = fixOffset(_this.init.offset[2])
style.left = fixOffset(_this.init.offset[3])
//左右都为auto时,改为居中
if(style.left === 'auto' && style.right === 'auto'){
style.left = '50%'
style.marginLeft = -parseInt(css.width) / 2;
}
//上下都为auto时,同样改为居中
if(style.top === 'auto' && style.bottom === 'auto'){
style.top = '50%'
style.marginTop = -parseInt(css.height) / 2;
}
}else{
style = yua.mix(style, {
marginLeft: -parseInt(css.width) / 2,
@ -515,18 +531,19 @@ define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){
}
if(!this.param){
init.wrap = true
init.type = 7;
init.$id = '$wrap-' + val;
if(!init.hasOwnProperty('menubar')){
init.menubar = false;
}
var tmp = new __constructor().ready(init),
elem = this.element.cloneNode(true);
var tmp = new __constructor().ready(init);
// 去掉隐藏之后,再放入content中
elem.style.display = ''
tmp.init.content = elem.outerHTML;
//去掉data-*属性
for(var i in this.element.dataset){
delete this.element.dataset[i]
}
layerObj[tmp.init.$id] = {obj: tmp, parentElem: this.element.parentNode, wrap: this.element, show: false};
layerDom[tmp.init.$id] = tmp.create();

View File

@ -6,16 +6,16 @@
*
*/
.do-fn-cl { *zoom: 1; }
.do-fn-cl:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; overflow:hidden;}
.do-layer, .do-layer * {margin: 0;padding: 0;vertical-align: baseline;box-sizing:border-box;}
.do-layer, .do-layer * {vertical-align: baseline;box-sizing:border-box;}
.do-layer a {text-decoration:none;}
@font-face {font-family: "deficon";
@font-face {font-family: "def-font";
src: url('def.eot'); /* IE9*/
src: url('def.ttf') format('truetype'); /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
}
.do-layer-cl::after {visibility:hidden;overflow:hidden;display:block;height: 0;content: ".";clear: both;}
.do-layer-cover {position:fixed;left:0;top:0;z-index:65534;width:100%;height:100%;background:rgba(255,255,255,.05);}
.do-layer {position:fixed;left:50%;top:50%;z-index:65535;width:auto;height:auto;}
.do-layer:active {z-index:65536;}
@ -23,7 +23,7 @@
/*默认皮肤样式*/
.do-layer.skin-def {color:#666;font-size:14px;box-shadow:0 0 10px rgba(0,0,0,.3);}
.do-layer.skin-def .deficon {display: inline-block;font-family:"deficon" !important;font-style:normal;-webkit-font-smoothing: antialiased;-webkit-text-stroke-width: 0.2px;-moz-osx-font-smoothing: grayscale;}
.do-layer.skin-def .def-font {display: inline-block;font-family:"def-font" !important;font-style:normal;-webkit-font-smoothing: antialiased;-webkit-text-stroke-width: 0.2px;-moz-osx-font-smoothing: grayscale;}
.do-layer.skin-def .icon-1:before {content:"\e6f1";color:#11b330;}/*discover*/
.do-layer.skin-def .icon-2:before {content:"\e6fa";color:#f30;}/*position*/
.do-layer.skin-def .icon-3:before {content:"\e6f0";color:#f30;}/*del*/
@ -53,7 +53,7 @@
.do-layer.skin-def .action-close:before {content:"\e659";}
.do-layer.skin-def .layer-content {position:relative;width:100%;height:auto;min-height:50px;padding:10px;}
.do-layer.skin-def .layer-content .deficon {position:absolute;left:10px;top:10px;width:50px;height:auto;line-height:40px;font-size:40px;text-align:center;}
.do-layer.skin-def .layer-content .msg-icon {position:absolute;left:10px;top:10px;width:50px;height:auto;line-height:40px;font-size:40px;text-align:center;}
.do-layer.skin-def .layer-content .detail {width:auto;height:100%;margin:auto auto auto 60px;padding:5px 15px;word-break:break-all;word-wrap: break-word;}
.do-layer.skin-def .layer-content.none-icon .detail {margin:0 auto;}
.do-layer.skin-def .layer-content .detail .prompt-value {width: 230px;height: 30px;padding: 0 8px;border: 1px solid #ddd;border-radius: 3px;}

View File

@ -827,9 +827,11 @@ Renderer.prototype.heading = function(text, level, raw) {
+ level
+ ' class="md-hd" id="'
+ raw
+ '"><a href="#'
+ raw
+ '">'
+ text
+ '</h'
+ '</a></h'
+ level
+ '>\n';
};
@ -1027,7 +1029,7 @@ Parser.prototype.tok = function() {
}
case 'code': {
return this.renderer.code(this.token.text,
this.token.lang,
this.token.lang || 'other',
this.token.escaped);
}
case 'table': {
@ -1124,7 +1126,7 @@ Parser.prototype.tok = function() {
*/
function escape(html, encode) {
return html
return (html)
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')

View File

@ -0,0 +1,57 @@
@charset "UTF-8";
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2017-04-20 19:13:24
*
*/
.do-meditor-attach {width:630px;height:auto;background:#f7f7f7;cursor:default;}
.do-meditor-attach .attach-wrap {width:100%;height:auto;}
.do-meditor-attach .tab-box {width:100%;height:50px;line-height:49px;border-bottom:1px solid #e2e2e2;text-align:center;}
.do-meditor-attach .tab-box .item {position:relative;float:left;width:100px;height:49px;border-right:1px solid #ddd;cursor:pointer;}
.do-meditor-attach .tab-box .item.active {background:#fff;}
.do-meditor-attach .tab-box .item.active::after {position:absolute;left:0;bottom:-1px;width:100%;height:1px;background:#fff;content:""}
.do-meditor-attach .tab-box a.action-close {top:5px;width:40px;height:40px;line-height:40px;font-size:20px;}
.do-meditor-attach .tab-box a.action-close:hover {line-height:40px;border:0;}
.do-meditor-attach .cont-box {position:relative;width:100%;height:auto;min-height:200px;background:#fff;}
.do-meditor-attach .cont-box .remote,
.do-meditor-attach .cont-box .local {position:relative;width:60%;height:auto;margin:0 auto;padding:15px 0 30px;}
.do-meditor-attach .cont-box .local {width:96%;}
.do-meditor-attach .cont-box .hide {display:none;}
.do-meditor-attach .cont-box .section {display:block;width:100%;height:auto;margin:15px 0;line-height:35px;}
.do-meditor-attach .cont-box .section::after {visibility: hidden;overflow:hidden; display: block;height: 0;content: "."; clear: both;}
.do-meditor-attach .cont-box .section .label {float: left;width:30%;text-align:center;background:#e2e2e2;}
.do-meditor-attach .cont-box .section label {float: left;width:50%;}
.do-meditor-attach .cont-box .section .input {float: left;width:70%;height:35px;padding:0 8px;border:1px solid #e2e2e2;border-left:0;background:#fff;color:#666;}
.do-meditor-attach .cont-box .section .submit {float:right;width:30%;height:35px;border:1px solid #ddd;background:#f7f7f7;color:#666;text-align:center;}
.do-meditor-attach .cont-box .section .submit:hover {border:1px solid #049789;}
.do-meditor-attach .cont-box .select-file {width:100%;height:35px;line-height:33px}
.do-meditor-attach .cont-box .select-file span.file {float:left;width:100px;height:35px;border:1px solid #ddd;background:#f7f7f7;color:#666;text-align:center;cursor:pointer;}
.do-meditor-attach .cont-box .upload-box {width:100%;height:auto;min-height:190px;margin:10px 0;border:1px solid #e2e2e2;}
.do-meditor-attach .cont-box .upload-box .tr {width:100%;height:35px;line-height:35px;text-align:center;}
.do-meditor-attach .cont-box .upload-box .tr:hover {background:#fafafa}
.do-meditor-attach .cont-box .upload-box .thead {line-height:34px;border-bottom:1px solid #e2e2e2;background:#f7f7f7;}
.do-meditor-attach .cont-box .upload-box .td {float:left;}
.do-meditor-attach .cont-box .upload-box .td.name {width:50%;}
.do-meditor-attach .cont-box .upload-box .td.progress {width:20%;}
.do-meditor-attach .cont-box .upload-box .td.option {width:30%;}
.do-meditor-attach .cont-box .upload-box .td.option a {display:inline-block;padding:3px 5px;line-height:13px;border:1px solid #e2e2e2;background:#f7f7f7;color:#666;}
.do-meditor-attach .cont-box .manager {overflow:hidden;overflow-y:auto;width:100%;height:320px;padding:10px;}
.do-meditor-attach .cont-box .manager .item {float:left;width:22%;height:130px;margin:10px 1.5%;}
.do-meditor-attach .cont-box .manager .item:hover {background:#f7f7f7;}
.do-meditor-attach .cont-box .manager .thumb {display:block;width:100%;height:100px;}
.do-meditor-attach .cont-box .manager .name {overflow:hidden;line-height:30px;text-align:center;}
.do-meditor-attach .cont-box .manager img {width:100%;height:100%;}
.do-meditor-attach .cont-box .manager .attac-icon {display:inline-block;width:100%;height:100px;text-align:center;font:50px/100px "edicon" !important;-webkit-font-smoothing: antialiased;-webkit-text-stroke-width: 0.2px;-moz-osx-font-smoothing: grayscale;}

View File

@ -0,0 +1,331 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2017-04-19 21:17:26
*
*/
"use strict";
define([
'lib/layer/base',
'css!./attach'
], function(){
var Uploader = function(url){
this.url = url || ''
this.init()
}
Uploader.prototype = {
init: function(){
this.xhr = new XMLHttpRequest()
this.form = new FormData()
return this
},
field: function(key, val){
if(typeof key === 'object'){
for(var i in key){
this.form.append(i, key[i])
}
}else{
this.form.append(key, val)
}
return this
},
start: function(){
var _this = this
this.xhr.open('POST', this.url, true)
var startTime = Date.now()
this.xhr.upload.addEventListener('progress', function(evt){
if(evt.lengthComputable && _this.progress){
var res = Math.round(evt.loaded * 100 / evt.total)
_this.progress(res)
}
}, false)
this.xhr.onreadystatechange = function(){
if(_this.xhr.readyState === 4){
if(_this.xhr.status >= 200 && _this.xhr.status < 205){
var res = _this.xhr.responseText
try{
res = JSON.parse(res)
}catch(err){}
_this.end && _this.end(res)
}else{
console.error(_this.xhr)
}
}
}
this.xhr.send(this.form)
},
onProgress: function(fn){
this.progress = fn
return this
},
onEnd: function(fn){
this.end = fn
return this
}
}
var $init = function(vm){
if(!vm.uploadUrl && !ME.uploadUrl){
console.error('使用附件上传,必须先设置uploadUrl;\n可以给vm增加uploadUrl属性,也可以通过ME.uploadUrl设置')
}
if(!vm.manageUrl && !ME.manageUrl){
console.error('使用附件管理功能,必须先设置manageUrl;\n可以给vm增加manageUrl属性,也可以通过ME.manageUrl设置')
}
// ME.addon.image()
vm.$editor.addEventListener('paste', function(ev){
var txt = ev.clipboardData.getData('text/plain').trim(),
html = ev.clipboardData.getData('text/html').trim();
//文本类型直接默认处理
if(txt || html){
return
}
if(ev.clipboardData.items){
var items = ev.clipboardData.items,
len = items.length,
blob = null;
for(var i = 0,it; it = items[i++];){
if(it.type.indexOf('image') > -1){
blob = it.getAsFile()
}
}
if(blob !== null) {
var upload = new Uploader(vm.uploadUrl || ME.uploadUrl)
upload.field('image', blob)
.onEnd(function(json){
ME.insert(vm.$editor, '![截图](' + json.data.url + ')')
}).start()
}
}
ev.preventDefault()
})
},
lang = {
image: ['远程图片', '图片管理', '图片描述', '图片地址'],
file: ['远程附件', '附件管理', '附件描述', '附件地址']
},
opened = false, //记录是否已经打开
openType = 'image', //打开类型, 图片/附件
cache = { //缓存附件列表
image: [],
file: []
},
fixCont = function(){
return '<div class="do-meditor-attach meditor-font">'
+ '<dl class="attach-wrap">'
+ '<dt class="tab-box">'
+ '<span class="item" :class="active:tab === 1" :click="$switch(1)">' + lang[openType][0] +'</span>'
+ '<span class="item" :class="active:tab === 2" :click="$switch(2)">本地上传</span>'
+ '<span class="item" :class="active:tab === 3" :click="$switch(3)">' + lang[openType][1] + '</span>'
+ '<a href="javascript:;" :click="no" class="action-close def-font"></a>'
+ '</dt>'
+ '<dt class="cont-box">'
+ '<div class="remote" :visible="tab === 1">'
+ '<section class="section"><span class="label">'+ lang[openType][2] + '</span>'
+ '<input class="input" :duplex="attachAlt" />'
+ '</section>'
+ '<section class="section"><span class="label">'+ lang[openType][3] + '</span>'
+ '<input class="input" :duplex="attach" />'
+ '</section>'
+ '<section class="section">'
+ '<a href="javascript:;" class="submit" :click="$confirm">确定</a>'
+ '</section>'
+ '</div>'
+ '<div class="local" :visible="tab === 2">'
+ '<div class="select-file"><input id="meditor-attch" multiple :change="$change" type="file" class="hide" /><span class="file" :click="$select">选择文件</span></div>'
+ '<ul class="upload-box">'
+ '<li class="tr thead"><span class="td name">文件名</span><span class="td progress">上传进度</span><span class="td option">操作</span></li>'
+ '<li class="tr" :repeat="uploadFile">'
+ '<span class="td name" :text="el.name"></span>'
+ '<span class="td progress" :text="el.progress"></span>'
+ '<span class="td option"><a href="javascript:;" :click="$insert(el)">插入</a></span>'
+ '</li>'
+ '</ul>'
+ '</div>'
+ '<ul class="manager" :visible="tab === 3">'
+ '<li class="item" :repeat="attachList" :click="$insert(el)">'
+ '<span class="thumb" :html="el.thumb"></span>'
+ '<p class="name" :text="el.name"></p>'
+ '</li>'
+ '</ul>'
+ '</dt>'
+ '</dl>'
+ '</div>'
};
/**
* [uploadFile 文件上传]
* @param {[type]} files [文件列表]
* @param {[type]} vm [vm对象]
* @param {[type]} type [image/file]
*/
function uploadFile(files, vm){
for(var i = 0, it; it = files[i++];){
if(openType === 'image' && !/image/.test(it.type)){
continue
}
var idx = vm.uploadFile.length,
upload = new Uploader(vm.uploadUrl || ME.uploadUrl)
vm.uploadFile.push({name: it.name, progress: '0%', url: ''})
upload.field(openType, it)
.onProgress(function(val){
vm.uploadFile[idx].progress = val + '%'
}).onEnd(function(json){
vm.uploadFile[idx].url = json.data.url
}).start()
}
}
function getAttach(vm, cb){
var xhr = new XMLHttpRequest(),
url = vm.manageUrl || ME.manageUrl;
if(/\?/.test(url)){
url += '&type=' + openType
}else{
url += '?type=' + openType
}
url += '&t=' + Math.random()
xhr.open('GET', url, true)
xhr.onreadystatechange = function(){
if(this.readyState === 4 &&
this.status === 200 &&
this.responseText !== ''){
var res = this.responseText
try{
res = JSON.parse(res)
}catch(err){}
cb(res)
}else{
if(this.status !== 200 && this.responseText)
console.error(this.responseText)
}
}
xhr.send()
}
function showDialog(elem, vm){
opened = true
var offset = yua(elem).offset(),
layid = layer.open({
type: 7,
menubar: false,
shade: false,
offset: [offset.top + 37],
tab: 2,
attach: '',
attachAlt: '',
uploadFile: [], //当前上传的列表
attachList: [], //附件管理列表
$switch: function(id){
var lvm = yua.vmodels[layid]
lvm.tab = id
if(id === 3){
lvm.attachList.clear()
if(cache[openType].length){
lvm.attachList = cache[openType]
}else{
getAttach(vm, function(json){
if(json){
cache[openType] = json.data.list.map(function(it){
it.thumb = openType === 'image' ? '<img src="' + it.url + '"/>' : '<em class="attac-icon">&#xe603;</em>'
return it
})
lvm.attachList = json.data.list
}
})
}
}
},
$select: yua.noop,
$change: yua.noop,
$insert: function(it){
var val = (openType === 'image' ? '!' : '')
+ '[' + it.name + '](' + it.url + ')'
ME.insert(vm.$editor, val)
},
$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)
lvm.no()
},
success: function(id){
var _this = yua.vmodels[id],
$file = document.body.querySelector('#meditor-attch')
_this.no = function(){
layer.close(id)
opened = false
}
_this.$select = function(){
var ev = document.createEvent('MouseEvent')
ev.initEvent('click', false, false)
$file.dispatchEvent(ev);
}
_this.$change = function(){
uploadFile(this.files, _this)
}
},
content: fixCont()
})
}
ME.addon.image = function(elem, vm){
if(opened){
return
}
openType = 'image'
showDialog(elem, vm)
}
ME.addon.file = function(elem, vm){
if(opened){
return
}
openType = 'file'
showDialog(elem, vm)
}
return $init
})

View File

@ -0,0 +1,366 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2017-04-17 21:41:48
*
*/
"use strict";
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
}
ME.addon = {
h1: function(elem, vm){
var offset = yua(elem).offset(),
wrap = ME.selection(vm.$editor, true) || '在此输入文本',
h1Obj = 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)
layer.close(h1Obj)
},
offset: [offset.top + 37, 'auto', 'auto', offset.left],
content: '<ul class="do-meditor-h1 do-fn-noselect 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)
},
bold: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '\\*\\*')
wrap = wrap === wraped ? ('**' + wrap + '**') : wraped
ME.insert(vm.$editor, wrap)
},
italic: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '_')
wrap = wrap === wraped ? ('_' + wrap + '_') : wraped
ME.insert(vm.$editor, wrap)
},
through: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '~~')
wrap = wrap === wraped ? ('~~' + wrap + '~~') : wraped
ME.insert(vm.$editor, wrap)
},
unordered: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本'
wrap = '* ' + wrap
ME.insert(vm.$editor, wrap)
},
ordered: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本'
wrap = '1. ' + wrap
ME.insert(vm.$editor, wrap)
},
hr: function(elem, vm){
ME.insert(vm.$editor, '\n\n---\n\n')
},
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)
layer.close(layid)
},
offset: [offset.top + 37, 'auto', 'auto', offset.left],
content: '<div class="do-meditor-common meditor-font">'
+ '<section><span class="label">链接文字</span>'
+ '<input class="input" :duplex="linkName" />'
+ '</section>'
+ '<section><span class="label">链接地址</span>'
+ '<input class="input" :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())
},
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, 'auto', 'auto', offset.left],
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 + ')')
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, 'auto', 'auto', offset.left],
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)
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)
layer.close(layid)
},
offset: [offset.top + 37, 'auto', 'auto', offset.left],
content: '<div class="do-meditor-common meditor-font">'
+ '<section><span class="label">图片描述</span>'
+ '<input class="input" :duplex="imgAlt" />'
+ '</section>'
+ '<section><span class="label">图片地址</span>'
+ '<input class="input" :duplex="img"/>'
+ '</section>'
+ '<section>'
+ '<a href="javascript:;" class="submit" :click="$confirm">确定</a>'
+ '</section>'
+ '</div>'
})
},
file: function(elem, vm){
this.link(elem, vm)
},
inlinecode: function(elem, vm){
var wrap = ME.selection(vm.$editor) || '在此输入文本'
wrap = '`' + wrap + '`'
ME.insert(vm.$editor, wrap)
},
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)
layer.close(layid)
},
content: '<div class="do-meditor-codeblock meditor-font">'
+ '<section><span class="label">语言类型</span>'
+ '<select :duplex="lang">'
+ '<option :ME.repeat="$lang" :attr-value="el.id">{{el.name || el.id}}</option>'
+ '</select>'
+ '</section>'
+ '<section>'
+ '<textarea :duplex="code" placeholder="在这里输入/粘贴代码"></textarea>'
+ '</section>'
+ '<section>'
+ '<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
if(vm.fullscreen){
vm.preview = true
vm.htmlTxt = vm.$htmlTxt
}else{
vm.preview = false
}
},
about: function(elem){
var offset = yua(elem).offset()
layer.open({
type: 7,
title: '关于编辑器',
offset: [offset.top + 37],
content: '<div class="do-meditor-about 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>'
})
}
}
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

383
js/lib/meditor/main.js Normal file
View File

@ -0,0 +1,383 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2017-04-17 16:37:12
*
*/
"use strict";
var log = console.log;
define([
'yua',
'lib/prism/main',
'lib/marked',
'css!./skin/main',
], function(yua){
marked.setOptions({
highlight: function(code, lang){
return Prism.highlight(code, Prism.languages[lang])
}
})
yua.ui.meditor = '0.0.1'
//存放编辑器公共静态资源
window.ME = {
version: yua.ui.meditor,
toolbar: { //工具栏title
pipe: '',
h1: '标题',
bold: '粗体',
italic: '斜体',
through: '删除线',
unordered: '无序列表',
ordered: '有序列表',
hr: '横线',
time: '插入当前时间',
face: '表情',
table: '插入表格',
image: '插入图片',
file: '插入附件',
inlinecode: '行内代码',
blockcode: '代码块',
preview: '预览',
fullscreen: '全屏',
about: '关于编辑器',
},
addon: {}, //已有插件
//往文本框中插入内容
insert: function(dom, val){
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 = startPos
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
}
}
}
//获取真实的引用路径,避免因为不同的目录结构导致加载失败的情况
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){
str = decodeURIComponent(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')
})
log(match)
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="edicon icon-' + name+ '" '
+ (name !== 'pipe' ? (':click="$onToolbarClick(\'' + name + '\')"') : '')
+ '></span>'
}
yua.component('meditor', {
$template: '<div class="do-meditor meditor-font" :class="{fullscreen: fullscreen}">'
+ '<div class="tool-bar do-fn-noselect">{toolbar}</div>'
+ '<div class="editor-body">'
+ '<textarea spellcheck="false" :duplex="plainTxt" :attr="{disabled: disabled}" :on-paste="$paste($event)" id="{uuid}"></textarea>'
+ '</div>'
+ '<div class="editor-md-preview" :visible="preview">'
+ '<content class="preview" :html="htmlTxt"></content>'
+ '</div>'
+ '</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
}
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)
}
}
},
$ready: function(vm){
vm.$editor = document.querySelector('#' + vm.$id)
//自动加载额外的插件
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){
//tab键改为插入4个空格,阻止默认事件,防止焦点失去
if(ev.keyCode === 9){
var wrap = ME.selection(vm.$editor) || ''
wrap = wrap.split('\n').map(function(it){
return ev.shiftKey ? it.replace(/^\s\s/, '') : ' ' + it
}).join('\n')
ME.insert(this, wrap)
ev.preventDefault()
}
})
},
$paste: function(ev){
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)
}
ev.preventDefault()
},
$compile: function(){
//只解析,不渲染
this.$htmlTxt = marked(this.plainTxt.trim())
},
$onToolbarClick: yua.noop,
$onUpdate: yua.noop,
disabled: false, //禁用编辑器
fullscreen: true, //是否全屏
preview: false, //是否显示预览
$editor: null, //编辑器元素
$htmlTxt: '', //临时储存html文本
htmlTxt: '', //用于预览渲染
plainTxt: '' //纯md文本
})
})
})

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,152 @@
@charset "UTF-8";
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2017-04-17 16:43:22
*
*/
@font-face {font-family: "edicon";
src: url('iconfont.eot'); /* IE9*/
src: url('iconfont.ttf') format('truetype'); /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
}
::-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:#cad5d5;}
::-webkit-scrollbar-thumb:hover {background:#9bacac;}
.do-meditor {position:relative;width:100%;height:100%;min-height:180px;border:1px solid #ddd;background:#fff;color:#666;}
.meditor-font {font-family:"PingFang SC","Helvetica Neue","Hiragino Sans GB","Segoe UI","Microsoft YaHei",sans-serif;}
/* 关于编辑器模块*/
.do-meditor-about {width:400px;padding:10px 20px;}
.do-meditor-about pre {padding-bottom:15px}
.do-meditor-about a {color:#049789}
.do-meditor-about p {margin:0 auto 5px;}
/*表格模块*/
.do-meditor-table {width:270px;height:270px;padding:10px;}
.do-meditor-table li {width:100%;height:25px;}
.do-meditor-table li span {float:left;width:25px;height:25px;border:2px solid #fff;background:#f2f2f2;}
.do-meditor-table li 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;}
.do-meditor-face li {float:left;width:40px;height:40px;padding:8px;border:1px solid #e2e2e2;border-top:0;border-left:0}
.do-meditor-face li img {width:100%;}
.do-meditor-face 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;}
.do-meditor-h1 li {width:100%;height:auto;padding:0 10px;line-height:1.5;font-size:18px;cursor:default;}
.do-meditor-h1 li:hover {background:#f2f2f2;}
.do-meditor-h1 li::before {font-family:"edicon" !important;-webkit-font-smoothing: antialiased;-webkit-text-stroke-width: 0.2px;-moz-osx-font-smoothing: grayscale;}
.do-meditor-h1 li.h1 {font-size:23px;}
.do-meditor-h1 li.h2 {font-size:21px;}
.do-meditor-h1 li.h1::before {content:"\e611 "}
.do-meditor-h1 li.h2::before {content:"\e60d "}
.do-meditor-h1 li.h3::before {content:"\e60e "}
.do-meditor-h1 li.h4::before {content:"\e60f "}
.do-meditor-h1 li.h5::before {content:"\e610 "}
.do-meditor-h1 li.h6::before {content:"\e60c "}
/*通用输入模块, 链接/图片插入/文件插入/代码块插入*/
.do-meditor-common {width:360px;height:auto;padding:15px 20px;}
.do-meditor-common section {width:100%;height: 35px;margin:10px 0;line-height:35px;}
.do-meditor-common section .label {float: left;width:30%;text-align:center;background:#ddd;}
.do-meditor-common section label {float: left;width:50%;}
.do-meditor-common section .input {float: left;width:70%;height:35px;padding:0 8px;border:1px solid #ddd;border-left:0;background:#fff;color:#666;}
.do-meditor-common section .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;}
.do-meditor-codeblock section {display:block;width:100%;height:auto;margin:10px 0;line-height:35px;}
.do-meditor-codeblock section::after {visibility: hidden;overflow:hidden; display: block;height: 0;content: "."; clear: both;}
.do-meditor-codeblock section .label {float: left;width:80px;}
.do-meditor-codeblock section select {float:left;width:200px;height:35px;border:1px solid #ddd;border-radius:5px;background:#fff}
.do-meditor-codeblock section textarea {width:100%;height:300px;padding:5px 10px;border:1px solid #ddd;background:#fff;resize:none;}
.do-meditor-codeblock section .submit {float:right;width:80px;height:35px;background:#ddd;color:#666;text-align:center;}
.do-meditor .tool-bar {position:relative;z-index:99;width:100%;height:auto;min-height:43px;padding:5px 10px;border-bottom:1px solid #ddd;background:#f5f5f5;color:#666;}
.do-meditor .tool-bar .edicon {display:inline-block;width:30px;height:32px;text-align:center;font:20px/32px "edicon" !important;-webkit-font-smoothing: antialiased;-webkit-text-stroke-width: 0.2px;-moz-osx-font-smoothing: grayscale;}
.do-meditor .tool-bar .edicon:hover {background:#e5e5e5;}
.do-meditor .tool-bar .icon-pipe {width:20px;}
.do-meditor .tool-bar .icon-pipe:hover {background:none;}
.do-meditor .tool-bar .icon-pipe::before {content:"\e612"}
.do-meditor .tool-bar .icon-h1::before {content:"\e611"}
.do-meditor .tool-bar .icon-bold::before {content:"\e615"}
.do-meditor .tool-bar .icon-italic::before {content:"\e61d"}
.do-meditor .tool-bar .icon-through::before {content:"\e604"}
.do-meditor .tool-bar .icon-link::before {content:"\e606"}
.do-meditor .tool-bar .icon-inlinecode::before {content:"\e61e"}
.do-meditor .tool-bar .icon-blockcode::before {content:"\e617"}
.do-meditor .tool-bar .icon-quote::before {content:"\e607"}
.do-meditor .tool-bar .icon-hr::before {content:"\e619"}
.do-meditor .tool-bar .icon-time::before {content:"\e61a"}
.do-meditor .tool-bar .icon-face::before {content:"\e616"}
.do-meditor .tool-bar .icon-image::before {content:"\e61b"}
.do-meditor .tool-bar .icon-file::before {content:"\e603"}
.do-meditor .tool-bar .icon-preview::before {content:"\e60a"}
.do-meditor .tool-bar .icon-fullscreen::before {content:"\e608"}
.do-meditor .tool-bar .icon-table::before {content:"\e601"}
.do-meditor .tool-bar .icon-ordered::before {content:"\e61c"}
.do-meditor .tool-bar .icon-unordered::before {content:"\e618"}
.do-meditor .tool-bar .icon-about::before {content:"\e613"}
.do-meditor .tool-bar .icon-help::before {content:"\e614"}
.do-meditor .editor-body {float:left;position:absolute;z-index:89;left:0;top:0;width:100%;height:100%;padding-top:43px;}
.do-meditor .editor-body>textarea {overflow:hidden;overflow-y:auto;width:100%;height:100%;padding:5px;border:0;outline:none;resize:none;color:#666;}
.do-meditor .editor-md-preview {position:absolute;z-index:90;right:0;top:0;width:100%;height:100%;padding-top:43px;}
.do-meditor .editor-md-preview>content.preview {overflow:hidden;overflow-y:auto;display:block;width:100%;height:100%;padding:10px;color:#666;font-size:14px;background:#fff;}
.do-meditor .editor-md-preview .md-hd {position:relative;margin:15px 0;padding-left:30px;font-weight:normal;font-size:17px;}
.do-meditor .editor-md-preview h1.md-hd {padding-left:0;}
.do-meditor .editor-md-preview .md-hd a {position:relative;display:inline-block;padding:0 8px;background:#fff;color:#454545}
.do-meditor .editor-md-preview h1.md-hd a {padding-left:0;color:#000;}
.do-meditor .editor-md-preview h2.md-hd a {color:#000;}
.do-meditor .editor-md-preview h1.md-hd {margin:0 0 30px;font-size:25px;}
.do-meditor .editor-md-preview h2.md-hd {margin:20px 0;font-size:23px;}
.do-meditor .editor-md-preview h3.md-hd {margin:20px 0 15px;font-size:20px;}
.do-meditor .editor-md-preview h1:after {display:block;width:100%;content:" ";border-bottom:1px solid #ddd;}
.do-meditor .editor-md-preview h2:before,
.do-meditor .editor-md-preview h3:before,
.do-meditor .editor-md-preview h4:before,
.do-meditor .editor-md-preview h5:before,
.do-meditor .editor-md-preview h6:before {display:block;position:absolute;left:0;top:50%;width:100%;content:" ";border-bottom:1px solid #ddd;}
.do-meditor .editor-md-preview a {text-decoration:none;}
.do-meditor .editor-md-preview blockquote {margin:10px 0;padding:5px 10px;border-left:5px solid #6bb294;background:#f7f7f7}
.do-meditor .editor-md-preview table thead tr {background:#f2f2f2}
.do-meditor .editor-md-preview table thead th {padding:0 8px;border:1px solid #ddd}
.do-meditor .editor-md-preview table tbody td {padding:0 8px;border:1px solid #ddd}
.do-meditor .editor-md-preview hr {margin:30px 0;}
.do-meditor .editor-md-preview ol {list-style:decimal inside none;}
.do-meditor .editor-md-preview ul {list-style:disc inside none;}
.do-meditor .editor-md-preview li ol {margin-left:2em;}
.do-meditor .editor-md-preview li ul {margin-left:2em;list-style-type: circle;}
.do-meditor .editor-md-preview li ol ul,
.do-meditor .editor-md-preview li ul ul {list-style-type: square;}
/*全屏模式*/
.do-meditor.fullscreen {position:fixed;left:0;top:0;z-index:999;}
.do-meditor.fullscreen .editor-body {width:50%}
.do-meditor.fullscreen .editor-md-preview {width:50%;border-left:1px solid #ddd;}

View File

@ -1,6 +1,7 @@
"use strict";
define(["yua","text!./pages.htm", "css!./pages"], function(yua, tpl) {
define(["yua","text!./main.htm", "css!./main"], function(yua, tpl) {
yua.ui.pages = '0.0.1'
//计算页码列表
function calculate(vm){
if (vm.total < 2)

View File

View File

View File

@ -0,0 +1,32 @@
@charset "UTF-8";
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2017-02-13 13:53:38
*
*/
/*代码块*/
.do-ui-blockcode {position:relative;border:1px solid #ddd;margin:15px 0;}
.do-ui-blockcode::before {position:relative;display:block;width:100%;height:25px;padding:0 8px;background:#eee;border-bottom:1px solid #ddd;line-height:25px;content:"代码示例";box-sizing: border-box;}
.do-ui-blockcode section {position:relative;}
.do-ui-blockcode .linenum {display:block;position:absolute;z-index:1;left:0;top:0;width:40px;height:100%;background:#eee;border-right:1px solid #ddd;text-align:center;}
/*语法高亮*/
.do-ui-blockcode .lang {position:relative;display:block;overflow-x:auto;z-index:0;padding:0 8px 0 50px;color:#383a42;background:#fafafa;word-wrap:break-word;white-space:pre-wrap;}
.do-ui-blockcode .lang .c-comment{color: #8e908c;font-style:italic;}
.do-ui-blockcode .lang .c-smartyx {color: #607d8b;}
.do-ui-blockcode .lang .c-important {color: #f5871f;font-style:italic;}
.do-ui-blockcode .lang .c-punctuation {color: #986756;}
.do-ui-blockcode .lang .c-regex {color: #c82829;}
.do-ui-blockcode .lang .c-boolean,.do-ui-blockcode .lang .c-number {color: #f5871f;}
.do-ui-blockcode .lang .c-function {color:#009688;}
.do-ui-blockcode .lang .c-class-name,.do-ui-blockcode .lang .c-build-in {color:#3aa9f3;}
.do-ui-blockcode .lang .c-class-name,.do-ui-blockcode .lang .c-build-in {font-style:italic;font-weight:bold;}
.do-ui-blockcode .lang .c-attr-name {color: #eab700;}
.do-ui-blockcode .lang .c-string,.do-ui-blockcode .lang .c-attr-value {color: #5ab302;}
.do-ui-blockcode .lang .c-tag,.do-ui-blockcode .lang .c-keyword,.do-ui-blockcode .lang .c-operator {color: #d81406;}
.do-ui-blockcode .lang .c-keyword {font-style:italic;}
/*行内代码*/
.do-ui-inlinecode {margin:0 2px;padding:0 5px;color:#d14;border:1px solid #ddd;border-radius:3px;}

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,7 @@
*/
"use strict";
define(function(){
define(['yua'], function(yua){
var _request = function(url, protocol){
this.transport = true
protocol = (protocol + '').trim().toUpperCase()
@ -53,37 +53,7 @@ define(function(){
// ------------------- 几个解释方法 -----------------------
var Format = function(){
this.tagHooks = new function(){
this.option = doc.createElement('select')
this.thead = doc.createElement('table')
this.td = doc.createElement('tr')
this.area = doc.createElement('map')
this.tr = doc.createElement('tbody')
this.col = doc.createElement('colgroup')
this.legend = doc.createElement('fieldset')
this._default = doc.createElement('div')
this.g = doc.createElementNS('http://www.w3.org/2000/svg', 'svg')
this.optgroup = this.option
this.tbody = this.tfoot = this.colgroup = this.caption = this.thead
this.th = this.td
};
var _this = this
'circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use'.replace(/,/g, function(m){
_this.tagHooks[m] = _this.tagHooks.g //处理svg
})
this.rtagName = /<([\w:]+)/
this.rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig
this.scriptTypes = {
'text/javascript': 1,
'text/ecmascript': 1,
'application/ecmascript': 1,
'application/javascript': 1
}
this.rhtml = /<|&#?\w+;/
}
function serialize(p, obj, q){
var k
@ -109,6 +79,8 @@ define(function(){
}
var Format = function(){}
Format.prototype = {
parseJS: function(code){
code = (code + '').trim()
@ -141,42 +113,7 @@ define(function(){
return xml
},
parseHTML: function (html){
var fragment = (doc.createDocumentFragment()).cloneNode(false)
if(typeof html !== 'string')
return fragment
if(!this.rhtml.test(html)){
fragment.appendChild(document.createTextNode(html))
return fragment
}
html = html.replace(this.rxhtml, '<$1></$2>').trim()
var tag = (this.rtagName.exec(html) || ['', ''])[1].toLowerCase()
var wrap = this.tagHooks[tag] || this.tagHooks._default
var firstChild = null
//使用innerHTML生成的script节点不会触发请求与执行text属性
wrap.innerHTML = html
var script = wrap.getElementsByTagName('script')
if(script.length){
for(var i = 0, el; el = script[i++];){
if(this.scriptTypes[el.type]){
var tmp = (doc.createElement("script")).cloneNode(false)
el.attributes.forEach(function(attr){
tmp.setAttribute(attr.name, attr.value)
})
tmp.text = el.text
el.parentNode.replaceChild(tmp, el)
}
}
}
while(firstChild = wrap.firstChild){
fragment.appendChild(firstChild)
}
return fragment
return yua.parseHTML(html)
},
param: function(obj){
if(!obj || typeof obj === 'string' || typeof obj === 'number')
@ -731,9 +668,9 @@ define(function(){
},
cache: {},
cid: 0,
version: '1.0.0',
release: 'request ES5 version/1.0.0'
version: '0.0.1-es5',
}
yua.ui.request = '0.0.1-es5'
}
return request

View File

@ -0,0 +1,740 @@
/**
* Request组件, modern版, 支持IE9+,chrome,FF
* @authors yutent (yutent@doui.cc)
* @date 2016-11-27 13:08:40
*
*/
"use strict";
define(function(){
var _request = function(url, protocol){
this.transport = true
protocol = (protocol + '').trim().toUpperCase()
this.xhr = Xhr()
this.opt = {
url: (url + '').trim(),
type: protocol || 'GET',
form: '',
data: {},
headers: {},
timeoutID: 0,
uuid: Math.random().toString(16).substr(2)
}
},
_requestp = _request.prototype,
toS = Object.prototype.toString,
win = window,
doc = win.document,
encode = encodeURIComponent,
decode = decodeURIComponent,
noop = function(e, res){
if(e)
throw new Error(e + '')
};
// -----------------------------
// 本地协议判断正则
var rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/
var isLocal = false
try{
isLocal = rlocalProtocol.test(location.protocol)
}catch(e){}
var rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg
// ----------------- 一些兼容性预处理 --------------------
win.Xhr = function(){
return new XMLHttpRequest()
}
// var supportCors = 'withCredentials' in Xhr()
// ------------------- 几个解释方法 -----------------------
var Format = function(){
this.tagHooks = new function(){
this.option = doc.createElement('select')
this.thead = doc.createElement('table')
this.td = doc.createElement('tr')
this.area = doc.createElement('map')
this.tr = doc.createElement('tbody')
this.col = doc.createElement('colgroup')
this.legend = doc.createElement('fieldset')
this._default = doc.createElement('div')
this.g = doc.createElementNS('http://www.w3.org/2000/svg', 'svg')
this.optgroup = this.option
this.tbody = this.tfoot = this.colgroup = this.caption = this.thead
this.th = this.td
};
var _this = this
'circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use'.replace(/,/g, function(m){
_this.tagHooks[m] = _this.tagHooks.g //处理svg
})
this.rtagName = /<([\w:]+)/
this.rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig
this.scriptTypes = {
'text/javascript': 1,
'text/ecmascript': 1,
'application/ecmascript': 1,
'application/javascript': 1
}
this.rhtml = /<|&#?\w+;/
}
function serialize(p, obj, q){
var k
if(Array.isArray(obj)){
obj.forEach(function(it, i){
k = p ? (p + '[' + (Array.isArray(it) ? i : '') + ']') : i
if(typeof it === 'object'){
serialize(k, it, q)
}else{
q(k, it)
}
})
}else{
for(var i in obj){
k = p ? (p + '[' + i + ']') : i
if(typeof obj[i] === 'object'){
serialize(k, obj[i], q)
}else{
q(k, obj[i])
}
}
}
}
Format.prototype = {
parseJS: function(code){
code = (code + '').trim()
if(code){
if(code.indexOf('use strict') === 1){
var script = doc.createElement('script')
script.text = code
doc.head
.appendChild(script)
.parentNode
.removeChild(script)
}else{
eval(code)
}
}
},
parseXML: function(data, xml, tmp){
try{
tmp = new DOMParser();
xml = tmp.parseFromString(data, 'text/xml');
}catch(e){
xml = void 0;
}
if(!xml ||
!xml.documentElement ||
xml.getElementsByTagName('parsererror').length){
console.error('Invalid XML: ' + data)
}
return xml
},
parseHTML: function (html){
var fragment = (doc.createDocumentFragment()).cloneNode(false)
if(typeof html !== 'string')
return fragment
if(!this.rhtml.test(html)){
fragment.appendChild(document.createTextNode(html))
return fragment
}
html = html.replace(this.rxhtml, '<$1></$2>').trim()
var tag = (this.rtagName.exec(html) || ['', ''])[1].toLowerCase()
var wrap = this.tagHooks[tag] || this.tagHooks._default
var firstChild = null
//使用innerHTML生成的script节点不会触发请求与执行text属性
wrap.innerHTML = html
var script = wrap.getElementsByTagName('script')
if(script.length){
for(var i = 0, el; el = script[i++];){
if(this.scriptTypes[el.type]){
var tmp = (doc.createElement("script")).cloneNode(false)
el.attributes.forEach(function(attr){
tmp.setAttribute(attr.name, attr.value)
})
tmp.text = el.text
el.parentNode.replaceChild(tmp, el)
}
}
}
while(firstChild = wrap.firstChild){
fragment.appendChild(firstChild)
}
return fragment
},
param: function(obj){
if(!obj || typeof obj === 'string' || typeof obj === 'number')
return obj
var arr = []
var q = function(k, v){
if(/native code/.test(v))
return
v = (typeof v === 'function') ? v() : v
v = (toS.call(v) !== '[object File]') ? encode(v) : v
arr.push(encode(k) + '=' + v)
}
if(typeof obj === 'object')
serialize('', obj, q)
return arr.join('&')
},
parseForm: function(form){
var data = {}
for(var i = 0,field; field = form.elements[i++];){
switch(field.type){
case 'select-one':
case 'select-multiple':
if(field.name.length && !field.disabled){
for(var j = 0, opt;opt = field.options[j++];){
if(opt.selected){
data[field.name] = opt.value || opt.text
}
}
}
break;
case 'file':
if(field.name.length && !field.disabled){
data[field.name] = field.files[0]
}
break;
case undefined:
case 'submit':
case 'reset':
case 'button':
break; //按钮啥的, 直接忽略
case 'radio':
case 'checkbox':
// 只处理选中的
if(!field.checked)
break;
default:
if(field.name.length && !field.disabled){
data[field.name] = field.value
}
}
}
return data
},
merge: function(a, b){
if(typeof a !== 'object' || typeof b !== 'object')
throw new TypeError('argument must be an object')
if(Object.assign)
return Object.assign(a, b)
for(var i in b){
a[i] = b[i]
}
return a
}
}
var F = new Format()
// ---------------------------------------------------------
// -------------------- request 模块开始 --------------------
// ---------------------------------------------------------
var requestConvert = {
text: function(val){
return val
},
xml: function(val, xml){
return xml !== undefined ? xml : F.parseXML(val)
},
html: function(val){
return F.parseHTML(val)
},
json: function(val){
return JSON.parse(val)
},
script: function(val){
return F.parseJS(val)
},
jsonp: function(name){
var json = request.cache[name]
delete request.cache[name];
return json
}
}
var requestExtend = {
formData: function(){
if(this.opt.form){
var data = F.parseForm(this.opt.form)
F.merge(this.opt.data, data)
}
var form = new FormData()
for(var i in this.opt.data){
var el = this.opt.data[i]
if(Array.isArray(el)){
el.forEach(function(it){
form.append(i + '[]', it)
})
}else{
form.append(i, this.opt.data[i])
}
}
return form
},
jsonp: function(jsonpcallback){
win[jsonpcallback] = function(val){
delete win[jsonpcallback]
request.cache[jsonpcallback] = val
}
},
dispatch: function(self){
if(!this.transport)
return
var _this = this,
result = {
response: {
url: this.opt.url,
headers: {'content-type': ''}
},
request: {
url: this.opt.url,
headers: _this.opt.headers
},
status: self === null ? 504 : 200,
statusText: self === null ? 'Connected timeout' : 'ok',
text: '',
body: '',
error: null
};
//状态为4,既已成功, 则清除超时
clearTimeout(_this.opt.timeoutID);
if(typeof this.transport === 'object'
&& this.opt.type === 'JSONP'){
//移除script
// this.transport.parentNode.removeChild(this.transport);
//超时返回
if(self !== null){
var exec = !this.transport.readyState
|| this.transport.readyState === 'loaded'
|| this.transport.readyState === 'complete';
if(exec){
result.body = requestConvert.jsonp(this.opt.data.callback)
result.text = JSON.stringify(result.body)
}
}
this.callback(result.error, result)
}else{
//成功的回调
var isSucc = self ? ((self.status >= 200 && self.status < 300) || self.status === 304) : false,
headers = self && self.getAllResponseHeaders().split('\n') || [];
//处理返回的Header
headers.forEach(function(it, i){
it = it.trim()
if(it){
it = it.split(':')
result.response.headers[it.shift().toLowerCase()] = it.join(':').trim()
}
});
if(isSucc){
result.status = self.status
if(result.status === 204){
result.statusText = 'no content'
}else if(result.status === 304){
result.statusText = 'not modified'
}
}else{
result.status = self === null ? 504 : (self.status || 500)
result.statusText = self === null ? 'Connected timeout' : (self.statusText || 'Internal Server Error')
result.error = F.merge(new Error(result.statusText), {status: result.status})
}
try{
//处理返回的数据
var dataType = result.response.headers['content-type'].match(/json|xml|script|html/i) || ['text']
dataType = dataType[0].toLowerCase()
result.text = self && (self.responseText || self.responseXML) || ''
result.body = requestConvert[dataType](result.text, self && self.responseXML)
}catch(err){
result.error = err
result.statusText = 'parse error'
}
_this.callback(result.error, result)
}
delete _this.transport;
delete _this.opt
delete _this.xhr
}
}
// 设置表单类型, 支持2种, form/json
_requestp.type = function(t){
if(this.opt.formType === 'form-data')
return this
this.opt.formType = t || 'form'
if(t === 'form' || this.opt.type === 'GET')
this.set('content-type', 'application/x-www-form-urlencoded; charset=UTF-8')
else
this.set('content-type', 'application/json; charset=UTF-8')
return this
}
//设置头信息
_requestp.set = function(k, val){
if(!this.transport)
return
if(typeof k === 'object'){
for(var i in k){
i = i.toLowerCase()
this.opt.headers[i] = k[i]
}
}else if(typeof k === 'string'){
if(arguments.length < 2)
throw new Error('2 arguments required')
// 全转小写,避免重复写入
k = k.toLowerCase()
if(val === undefined)
delete this.opt.headers[k]
else
this.opt.headers[k] = val
}else{
throw new Error('arguments must be string/object, but [' + (typeof k) + '] given')
}
return this
}
//设置请求参数
_requestp.send = function(k, val){
if(!this.transport)
return
// 1. send方法可以多次调用, 但必须保证格式一致
// 2. 2次圴提交纯字符串也会抛出异常
if(typeof k === 'object'){
if(this.opt.data && (typeof this.opt.data === 'string'))
throw new Error('param can not be string and object at the same time')
if(!this.opt.data)
this.opt.data = {}
F.merge(this.opt.data, k)
}else{
if(typeof k === 'string'){
if(arguments.length === 1){
if(this.opt.data)
throw new Error('invalid param in function send')
this.opt.data = k
}else{
if(this.opt.data && (typeof this.opt.data === 'string'))
throw new Error('param can not be string and object at the same time')
if(!this.opt.data)
this.opt.data = {}
this.opt.data[k] = val
}
}else{
throw new Error('argument of send must be string/object, but [' + (typeof k) + '] given')
}
}
return this
}
//该方法用于 form-data类型的post请求的参数设置
_requestp.field = function(k, val){
if(!this.transport)
return
// 此类型优先级最高
this.opt.formType = 'form-data'
if(!this.opt.data || (this.opt.data && typeof this.opt.data !== 'object'))
this.opt.data = {}
if(arguments.length === 1 && typeof k === 'object'){
F.merge(this.opt.data, k)
}else if(arguments.length === 2){
this.opt.data[k] = val
}else{
throw new TypeError('argument must be an object, but ' + (typeof k) + ' given')
}
return this
}
//设置缓存
_requestp.cache = function(t){
if(!this.transport)
return
if(this.opt.type === 'GET')
this.opt.cache = !!t
return this
}
//取消网络请求
_requestp.abort = function(){
delete this.transport
if(!this.opt.form)
this.xhr.abort()
return this
}
//超时设置, 单位毫秒
_requestp.timeout = function(time){
if(typeof time !== 'number' || time < 1)
return this
this.opt.timeout = time
return this
}
_requestp.form = function(form){
if(typeof form === 'object' && form.nodeName === 'FORM'){
this.opt.type = 'POST'
this.opt.form = form
}
return this
}
var originAnchor = doc.createElement('a');
originAnchor.href = location.href;
_requestp.end = function(callback){
var _this = this;
// 回调已执行, 或已取消, 则直接返回, 防止重复执行
if(!this.transport)
return
if(!this.opt.url)
throw new Error('Invalid request url')
F.merge(this, requestExtend)
this.callback = callback || noop
// 1. url规范化
this.opt.url = this.opt.url.replace(/#.*$/, '').replace(/^\/\//, location.protocol + '//')
// 2. 处理跨域
if(typeof this.opt.crossDomain !== 'boolean'){
var anchor = doc.createElement('a')
try{
anchor.href = this.opt.url
// IE7及以下浏览器 '1'[0]的结果是 undefined
// IE7下需要获取绝对路径
var absUrl = !'1'[0] ? anchor.getAttribute('href', 4) : anchor.href
anchor.href = absUrl
anchor.async = true
this.opt.crossDomain = (originAnchor.protocol !== anchor.protocol) || (originAnchor.host !== anchor.host)
}catch(e){
this.opt.crossDomain = true
}
}
// 2.1 进一步处理跨域配置
if(this.opt.type === 'JSONP'){
//如果没有跨域自动转回xhr GET
if(!this.opt.crossDomain){
this.opt.type = 'GET';
}else{
this.opt.data['callback'] = this.opt.data['callback'] || ('jsonp' + request.cid++);
this.jsonp(this.opt.data['callback']); //创建临时处理方法
}
}
// 2.2 如果不是跨域请求则自动加上一条header信息用以标识这是ajax请求
if(!this.opt.crossDomain){
this.set('X-Requested-With', 'XMLHttpRequest')
}
// 3. data转字符串
this.opt.param = F.param(this.opt.data)
// 4. 设置Content-Type类型, 默认x-www-form-urlencoded
if(!this.opt.formType)
this.type('form')
// 5.处理GET请求
this.opt.hasContent = this.opt.type === 'POST' //是否为post请求
if(!this.opt.hasContent){
//GET请求直接把参数拼接到url上
if(this.opt.param){
this.opt.url += (/\?/.test(this.opt.url) ? '&' : '?') + this.opt.param
}
//加随机值,避免缓存
if(this.opt.cache === false)
this.opt.url += (/\?/.test(this.opt.url) ? '&' : '?') + '_=' + Math.random()
}else{
if(this.opt.formType === 'form-data'){
delete this.opt.headers['content-type']
this.opt.param = this.formData()
}else if(this.opt.formType !== 'form'){
this.opt.param = JSON.stringify(this.opt.data)
}
}
//jsonp
if(this.opt.type === 'JSONP'){
this.transport = doc.createElement('script')
this.transport.onerror = this.transport.onload = function(){
_this.dispatch(_this.transport)
}
this.transport.src = this.opt.url
doc.head.insertBefore(this.transport, doc.head.firstChild)
//6. 超时处理
if(this.opt.timeout && this.opt.timeout > 0){
this.opt.timeoutID = setTimeout(function(){
_this.transport.onerror = _this.transport.onload = null
_this.dispatch(null)
}, this.opt.timeout)
}
}else{
this.xhr.onreadystatechange = function(ev){
if(_this.opt.timeout && _this.opt.timeout > 0){
_this.opt['time' + this.readyState] = ev.timeStamp
if(this.readyState === 4){
_this.opt.isTimeout = _this.opt.time4 - _this.opt.time1 > _this.opt.timeout
}
}
if(this.readyState !== 4){
return
}
_this.dispatch(_this.opt.isTimeout ? null : _this.xhr)
}
// 6. 初始化xhr提交
this.xhr.open(this.opt.type, this.opt.url, true)
// 7. 设置头信息
for(var i in this.opt.headers){
if(this.opt.headers[i])
this.xhr.setRequestHeader(i, this.opt.headers[i])
}
// 8. 发起网络请求
_this.xhr.send(_this.opt.param)
//超时处理
if(this.opt.timeout && this.opt.timeout > 0){
this.xhr.timeout = this.opt.timeout;
}
}
}
// ---------------------- end ------------------------
if(!win.request){
win.request = {
get: function(url){
if(!url)
throw new Error('argument url is required')
return new _request(url, 'GET')
},
post: function(url){
if(!url)
throw new Error('argument url is required')
return new _request(url, 'POST')
},
jsonp: function(url){
if(!url)
throw new Error('argument url is required')
return new _request(url, 'JSONP')
},
cache: {},
cid: 0,
version: '1.0.0',
release: 'request ES5 version/1.0.0'
}
}
return request
})

View File

@ -159,5 +159,7 @@ define(['yua'], function(){
return false
}
yua.ui.router = '0.0.1'
return yua.router = new Router;
})

View File

@ -1 +0,0 @@
define(["yua"],function(){function t(){this.table={get:[]},this.errorFn=null,this.history=null,this.hash="",this.started=!1,this.init={}}function e(t){return!t||t===window.name||"_self"===t||"top"===t&&window==window.top?!0:!1}var r={prefix:/^(#!|#)[\/]?/,historyOpen:!0,allowReload:!0},i=!0,a=/(:id)|(\{id\})|(\{id:([A-z\d\,\[\]\{\}\-\+\*\?\!:\^\$]*)\})/g;return t.prototype={error:function(t){this.errorFn=t},config:function(t){return this.started?console.error("Router config has been set"):(this.started=!0,t.allowReload||(t.historyOpen=!0),void(this.init=yua.mix({},r,t)))},_getRegExp:function(t,e){var r=t.replace(a,function(t,e,r,i,a){var n="([\\w.-]";return e||r?n+"+)":(/^\{[\d\,]+\}$/.test(a)||(n="("),n+a+")")});return r=r.replace(/(([^\\])([\/]+))/g,"$2\\/").replace(/(([^\\])([\.]+))/g,"$2\\.").replace(/(([^\\])([\-]+))/g,"$2\\-").replace(/(\(.*)(\\[\-]+)(.*\))/g,"$1-$3"),r="^"+r+"$",e.regexp=new RegExp(r),e},_add:function(t,e,r){this.started||this.config({});var i=this.table[t.toLowerCase()];if("/"!==e.charAt(0))return void console.error('char "/" must be in front of router rule');e=e.replace(/^[\/]+|[\/]+$|\s+/g,"");var a={};a.rule=e,a.callback=r,yua.Array.ensure(i,this._getRegExp(e,a))},_route:function(t,e){var e=e.trim(),r=this.table[t],i=this.init;if(i.allowReload||e!==this.history){i.historyOpen&&(this.history=e,yua.ls&&yua.ls("lastHash",e));for(var a,n=0;a=r[n++];){var o=e.match(a.regexp);if(o)return o.shift(),a.callback.apply(a,o)}this.errorFn&&this.errorFn(e)}},on:function(t,e){this._add("get",t,e)}},yua.bind(window,"load",function(){if(yua.router.started){var t=yua.router.init.prefix,e=location.hash;e=e.replace(t,"").trim(),yua.router._route("get",e)}}),"onhashchange"in window&&window.addEventListener("hashchange",function(){if(i){var t=yua.router.init.prefix,e=location.hash.replace(t,"").trim();yua.router._route("get",e)}}),yua.bind(document,"mousedown",function(t){var r="defaultPrevented"in t?t.defaultPrevented:t.returnValue===!1;if(!(r||t.ctrlKey||t.metaKey||2===t.which)){for(var a=t.target;"A"!==a.nodeName;)if(a=a.parentNode,!a||"BODY"===a.tagName)return;if(e(a.target)){if(!yua.router.started)return;var n=a.getAttribute("href")||a.getAttribute("xlink:href"),o=yua.router.init.prefix;if(null===n||!o.test(n))return;yua.router.hash=n.replace(o,"").trim(),t.preventDefault(),location.hash=n,i=!1}}}),yua.bind(document,"mouseup",function(){i||(yua.router._route("get",yua.router.hash),i=!0)}),yua.router=new t});

2
js/lib/tree/Readme.md Normal file
View File

@ -0,0 +1,2 @@
# Tree树型菜单
> 顾名思义,就是

83
js/lib/tree/main.js Normal file
View File

@ -0,0 +1,83 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2017-04-14 21:04:50
*
*/
"use strict";
define(['yua', 'css!./skin/def.css'], function(){
//储存版本信息
yua.ui.tree = '0.0.1'
var box = '<ul class="do-tree skin-{skin}">{li}</ul>',
ul = '<ul :class="{open: {it}.open}">{li}</ul>',
li = '<li :class="{open: {it}.open, dir: {it}.children}">'
+ '<em :click="$toggle({it})"></em><span '
+ ':click="$click({it})" '
+ ':text="{it}.name"></span>{child}</li>';
function repeat(arr, name){
var html = ''
arr.forEach(function(it, i){
var from = name + '[' + i + ']',
child = '';
html += li.replace(/\{it\}/g, from);
if(it.children){
child += repeat(it.children, from +'.children')
child = ul.replace('{li}', child).replace('{it}', from)
}
if(child){
}
html = html.replace(/\{child\}/, child)
})
return html
}
return yua.component('tree', {
$template: '',
$construct: function(base, opt, attr){
if(!opt.from && !attr.from){
throw new Error('tree组件必须传入「from」属性')
}
var from = attr.from || opt.from,
arr = base.$up[from].$model,
tpl = repeat(arr, from)
delete attr.from
delete opt.from
yua.mix(base, opt, attr)
base.skin = base.skin || 'def'
tpl = box.replace('{li}', tpl).replace('{skin}', base.skin)
base.$template = tpl
return base
},
$init: function(vm){
vm.$click = function(obj){
if(vm.$onClick){
vm.$onClick(obj)
}
}
},
$click: yua.noop,
$toggle: function(obj){
obj.open = !obj.open
}
})
})

46
js/lib/tree/skin/def.css Normal file
View File

@ -0,0 +1,46 @@
@charset "UTF-8";
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2017-04-14 21:18:53
*
*/
.do-fn-cl:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; overflow:hidden;}
.do-tree, .do-tree * {margin: 0;padding: 0;vertical-align: baseline;box-sizing:border-box;}
@font-face {font-family: "iconfont";
src: url('iconfont.eot'); /* IE9*/
src: url('iconfont.ttf') format('truetype'); /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
}
.do-tree {width:100%;height:auto;line-height:28px;}
.do-tree li {overflow:hidden; white-space:nowrap; text-overflow:ellipsis}
.do-tree li ul {display:none;margin-left:20px;}
.do-tree li ul.open {display:block;}
.do-tree li em,
.do-tree li span {display:block;cursor:pointer;}
.do-tree li em {float:left;padding:0 5px;color:#000;font-family:"iconfont" !important;font-style:normal;-webkit-font-smoothing: antialiased;-webkit-text-stroke-width: 0.2px;-moz-osx-font-smoothing: grayscale;}
.do-tree li span:hover {color:#6bb294;}
.do-tree.skin-def li>em::before {content:"\e610";}
.do-tree.skin-def li.dir>em::before {content:"\e622";}
.do-tree.skin-def li.dir.open>em::before {content:"\e8ea";}
.do-tree.skin-light li>em::before {content:"\e73e";}
.do-tree.skin-light li.dir>em::before {content:"\e635";}
.do-tree.skin-light li.dir.open>em::before {content:"\e8ea";}
.do-tree.skin-line li>em::before {content:"\e60e";}
.do-tree.skin-line li.dir>em::before {content:"\e608";font-weight:bold;}
.do-tree.skin-line li.dir.open>em::before {content:"\e662";}
.do-tree.skin-arrow li>em::before {content:"\e73e";}
.do-tree.skin-arrow li.dir>em::before {content:"\e616";font-weight:bold;}
.do-tree.skin-arrow li.dir.open>em::before {content:"\e607";}

Binary file not shown.

Binary file not shown.

View File

@ -353,7 +353,7 @@ if(!String.prototype.splice){
Object.defineProperty(String.prototype,
'splice',
{
value: function(start, len, sub){
value: function(start, len, fill){
var length = this.length,
argLen = arguments.length;
@ -497,6 +497,7 @@ yua.mix({
subscribers: subscribers,
version: '1.0.0',
log: log,
ui: {}, //仅用于存放组件版本信息等
slice: function (nodes, start, end) {
return aslice.call(nodes, start, end)
},
@ -3349,7 +3350,7 @@ yua.component = function (name, opts) {
delete elemOpts.config
delete elemOpts.$id
delete elemOpts.identifier
var componentDefinition = {}
var componentDefinition = {$up: host.vmodels[0], $ups: host.vmodels}
yua.mix(true, componentDefinition, hooks)
@ -3384,6 +3385,14 @@ yua.component = function (name, opts) {
// 组件所使用的标签是temlate,所以必须要要用子元素替换掉
var child = elem.content.firstChild
if(!child || serialize.call(child) === '[object Text]'){
var tmpDom = document.createElement('div')
if(child){
tmpDom.appendChild(child)
}
child = tmpDom
tmpDom = null
}
elem.parentNode.replaceChild(child, elem)
child.msResolved = 1
var cssText = elem.style.cssText

View File

@ -353,7 +353,7 @@ if(!String.prototype.splice){
Object.defineProperty(String.prototype,
'splice',
{
value: function(start, len, sub){
value: function(start, len, fill){
var length = this.length,
argLen = arguments.length;
@ -497,6 +497,7 @@ yua.mix({
subscribers: subscribers,
version: '1.0.0',
log: log,
ui: {}, //仅用于存放组件版本信息等
slice: function (nodes, start, end) {
return aslice.call(nodes, start, end)
},
@ -3349,7 +3350,7 @@ yua.component = function (name, opts) {
delete elemOpts.config
delete elemOpts.$id
delete elemOpts.identifier
var componentDefinition = {}
var componentDefinition = {$up: host.vmodels[0], $ups: host.vmodels}
yua.mix(true, componentDefinition, hooks)
@ -3384,12 +3385,23 @@ yua.component = function (name, opts) {
// 组件所使用的标签是temlate,所以必须要要用子元素替换掉
var child = elem.content.firstChild
if(!child || serialize.call(child) === '[object Text]'){
var tmpDom = document.createElement('div')
if(child){
tmpDom.appendChild(child)
}
child = tmpDom
tmpDom = null
}
elem.parentNode.replaceChild(child, elem)
child.msResolved = 1
var cssText = elem.style.cssText
var className = elem.className
elem = host.element = child
elem.style.cssText += ";"+ cssText
if (className) {
yua(elem).addClass(className)
}