init js folder
parent
1b79262cc0
commit
b8d2daf02c
|
@ -0,0 +1,92 @@
|
|||
/**
|
||||
*
|
||||
* @authors yutent (yutent@doui.cc)
|
||||
* @date 2017-03-17 20:55:57
|
||||
*
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
// 1216fc0c668c09ade029ceae6db87f97cf560e21
|
||||
define(function(){
|
||||
|
||||
var Avatar = function(){
|
||||
this.sum = function(arr){
|
||||
var sum = 0;
|
||||
arr.forEach(function(it){
|
||||
sum -= -it
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Avatar.prototype = {
|
||||
get: function(hash, size){
|
||||
if(!hash)
|
||||
return this.defafultImg;
|
||||
|
||||
if(!size || size < 100){
|
||||
size = 100
|
||||
}
|
||||
|
||||
var cv = document.createElement('canvas'),
|
||||
ct = cv.getContext('2d'),
|
||||
bg = hash.slice(-3),
|
||||
color = hash.slice(-9, -6),
|
||||
fixColor = color,
|
||||
lens = hash.slice(0, 8).match(/([\w]{1})/g),
|
||||
pos1 = hash.slice(8, 16).match(/([\w]{1})/g),
|
||||
pos2 = hash.slice(16, 24).match(/([\w]{1})/g),
|
||||
step = size / 10;
|
||||
|
||||
|
||||
|
||||
cv.width = size;
|
||||
cv.height = size;
|
||||
|
||||
lens = lens.map(c => {
|
||||
c = parseInt(c, 16);
|
||||
return c % 8
|
||||
})
|
||||
pos1 = pos1.map(c => {
|
||||
c = parseInt(c, 16);
|
||||
return c % 4
|
||||
})
|
||||
pos2 = pos2.map(c => {
|
||||
c = parseInt(c, 16);
|
||||
return c % 4
|
||||
})
|
||||
fixColor = this.sum(lens) > 32 ? bg : color;
|
||||
|
||||
ct.fillStyle = '#' + bg;
|
||||
ct.fillRect(0, 0, size, size)
|
||||
|
||||
for(var i = 1; i < 9; i++){
|
||||
|
||||
var xl = lens[i-1],
|
||||
xp1 = pos1[i-1],
|
||||
xp2 = pos2[i-1];
|
||||
|
||||
if(xl + xp1 > 8){
|
||||
xl = 8 - xp1
|
||||
}
|
||||
ct.fillStyle = '#' + color;
|
||||
ct.fillRect((xp1 + 1) * step, i * step, xl * step, step)
|
||||
|
||||
ct.fillStyle = '#' + color;
|
||||
ct.fillRect((9 - xp1 - xl) * step, i * step, xl * step, step)
|
||||
|
||||
ct.fillStyle = '#' + fixColor;
|
||||
ct.fillRect((xp2 + 1) * step, i * step, step, step)
|
||||
|
||||
ct.fillStyle = '#' + fixColor;
|
||||
ct.fillRect((8 - xp2) * step, i * step, step, step)
|
||||
}
|
||||
|
||||
return cv.toDataURL()
|
||||
}
|
||||
}
|
||||
|
||||
return new Avatar()
|
||||
|
||||
})
|
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,153 @@
|
|||
/**
|
||||
*
|
||||
* @authors yutent (yutent@doui.cc)
|
||||
* @date 2016-08-19 10:38:25
|
||||
*
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
define(['avalon'], function(av){
|
||||
|
||||
|
||||
|
||||
av.component('do:count', {
|
||||
$replace: true,
|
||||
$template: '<ul class="do-ui-count"><li class="num-box" ms-repeat-obj="list" ms-class="split:obj.opt === 0"><span class="num" ms-repeat="obj.val">{{el}}</span></li></ul>',
|
||||
maxLen: 8,
|
||||
speed: 1,
|
||||
update: av.noop,
|
||||
list: [],
|
||||
$list: [],
|
||||
total: 0,
|
||||
style: 2,
|
||||
$construct: function(opt, a, b){
|
||||
var vm = av.mix(a, b)
|
||||
document.head.insertAdjacentHTML('afterBegin', '<style>' +
|
||||
'.do-ui-count {width: 100%;height: 50px;text-align:center;}' +
|
||||
'.do-ui-count li.num-box {overflow:hidden;display: inline-block;position: relative;width: 40px;height: 50px;margin:0 15px;line-height: 50px;background: #09f;font-size: 30px;}' +
|
||||
'.do-ui-count li.num-box .num {display: block;width: 100%;height: 50px;margin-top: 0;transition: .3s ease-in-out}' +
|
||||
'.do-ui-count li.num-box.split {width: auto;margin:0;background: none;}' +
|
||||
'</style>')
|
||||
|
||||
vm.total = vm.total >> 0
|
||||
vm.maxLen = vm.maxLen || 8
|
||||
|
||||
return av.mix(opt, vm)
|
||||
},
|
||||
$ready: function(vm, ele){
|
||||
|
||||
function updateList(val){
|
||||
val = numberFormat(val, vm.maxLen)
|
||||
|
||||
vm.$list = []
|
||||
vm.$list = val.split('')
|
||||
if(vm.style === 2){
|
||||
vm.$list = vm.$list.reverse()
|
||||
val = vm.$list.join('').replace(/([\d,]{3})/g, '$1,')
|
||||
val = val.replace(/^,|,$/g, '')
|
||||
vm.$list = val.split('').reverse()
|
||||
}
|
||||
|
||||
vm.$list.forEach(function(it, i){
|
||||
|
||||
if(it === ','){
|
||||
if(!vm.list[i])
|
||||
vm.list.push({opt: 0, val: [it]})
|
||||
|
||||
}else{
|
||||
if(vm.list[i]){
|
||||
if(it !== vm.list[i].last){
|
||||
vm.list[i].last = it
|
||||
vm.list[i].val.push(it)
|
||||
var curr = ele.querySelectorAll('.num-box')[i]
|
||||
curr.querySelector('.num').style.marginTop = vm.speed * 50 + 'px'
|
||||
setTimeout(function(){
|
||||
vm.list[i].val.shift()
|
||||
}, 300)
|
||||
}
|
||||
}else{
|
||||
vm.list.push({opt: 1, last: it, val: [it]})
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
updateList(vm.total)
|
||||
|
||||
vm.update = function(val){
|
||||
if(val < 0) //确定滚动方向
|
||||
vm.speed = 1
|
||||
else
|
||||
vm.speed = -1
|
||||
|
||||
|
||||
vm.total = (vm.total - 0) + val
|
||||
|
||||
}
|
||||
|
||||
|
||||
vm.$watch('total', function(n, o){
|
||||
|
||||
if(n === o)
|
||||
return
|
||||
|
||||
updateList(n)
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//数字长度补全(前面加0)
|
||||
function numberFormat(num, len){
|
||||
num += ''
|
||||
if(num.length >= len)
|
||||
return num
|
||||
|
||||
while(num.length < len)
|
||||
num = '0' + num
|
||||
return num
|
||||
}
|
||||
|
||||
|
||||
|
||||
return av
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
})
|
|
@ -0,0 +1 @@
|
|||
"use strict";define(["avalon"],function(t){function e(t,e){if(t+="",t.length>=e)return t;for(;t.length<e;)t="0"+t;return t}return t.component("do:count",{$replace:!0,$template:'<ul class="do-ui-count"><li class="num-box" ms-repeat-obj="list" ms-class="split:obj.opt === 0"><span class="num" ms-repeat="obj.val">{{el}}</span></li></ul>',maxLen:8,speed:1,update:t.noop,list:[],$list:[],total:0,style:2,$construct:function(e,i,l){var n=t.mix(i,l);return document.head.insertAdjacentHTML("afterBegin","<style>.do-ui-count {width: 100%;height: 50px;text-align:center;}.do-ui-count li.num-box {overflow:hidden;display: inline-block;position: relative;width: 40px;height: 50px;margin:0 15px;line-height: 50px;background: #09f;font-size: 30px;}.do-ui-count li.num-box .num {display: block;width: 100%;height: 50px;margin-top: 0;transition: .3s ease-in-out}.do-ui-count li.num-box.split {width: auto;margin:0;background: none;}</style>"),n.total=n.total>>0,n.maxLen=n.maxLen||8,t.mix(e,n)},$ready:function(t,i){function l(l){l=e(l,t.maxLen),t.$list=[],t.$list=l.split(""),2===t.style&&(t.$list=t.$list.reverse(),l=t.$list.join("").replace(/([\d,]{3})/g,"$1,"),l=l.replace(/^,|,$/g,""),t.$list=l.split("").reverse()),t.$list.forEach(function(e,l){if(","===e)t.list[l]||t.list.push({opt:0,val:[e]});else if(t.list[l]){if(e!==t.list[l].last){t.list[l].last=e,t.list[l].val.push(e);var n=i.querySelectorAll(".num-box")[l];n.querySelector(".num").style.marginTop=50*t.speed+"px",setTimeout(function(){t.list[l].val.shift()},300)}}else t.list.push({opt:1,last:e,val:[e]})})}l(t.total),t.update=function(e){t.speed=0>e?1:-1,t.total=t.total-0+e},t.$watch("total",function(t,e){t!==e&&l(t)})}}),t});
|
|
@ -0,0 +1,46 @@
|
|||
# 日历组件文档
|
||||
|
||||
## 配置说明
|
||||
|
||||
```json
|
||||
{
|
||||
showTime: false, //对话框上显示时间
|
||||
showCalendar: false, //显示日历对话框
|
||||
disabled: false, //是否禁用
|
||||
exclass: '', //输入框拓展样式, 用于外部调整输入框样式以适配各种场景
|
||||
duplex: '',
|
||||
format: '', // 日期显示格式
|
||||
radius: 0, //日历输入框边框圆角半径
|
||||
border: 1, //日历输入框边框大小
|
||||
btns: { //切换年份/月份的按钮上的字符
|
||||
prevYear: '<<',
|
||||
nextYear: '>>',
|
||||
prevMonth: '<',
|
||||
nextMonth: '>'
|
||||
},
|
||||
callback: function(date){/*...*/}, //日期被修改后的回调,参数是被修改后的值
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## 用法
|
||||
|
||||
```html
|
||||
<!-- 把do:datepicker 标签放到想要放的地方即可 -->
|
||||
<section>
|
||||
<span class="label">示例1:</span>
|
||||
<do:datepicker config="dp" duplex="ex1" border="1" class="date" radius="3"></do:datepicker>
|
||||
</section>
|
||||
<!--
|
||||
其中config属性是指定日历组件的配置,会自动从上一层controller里找,如果该属性为空,则自动从上层controller中找与组件同名的属性(找不到则使用组件默认配置);
|
||||
其他的属性(除$id, config, id, class, tabindex, style, ms-*属性,data-*属性外,也可以用以配置组件,且优先级最高);
|
||||
$id或identifier属性可以设定组件的$id值,方便各模块之间进行通讯
|
||||
-->
|
||||
<!-- 引入分页组件 -->
|
||||
<script>
|
||||
require(['存放路径/doui.datepicker'], function(){
|
||||
|
||||
})
|
||||
</script>
|
||||
```
|
|
@ -0,0 +1,40 @@
|
|||
@charset "UTF-8";
|
||||
/**
|
||||
*
|
||||
* @authors yutent (yutent@doui.cc)
|
||||
* @date 2016-02-14 14:00:06
|
||||
*
|
||||
*/
|
||||
.do-ui-datepicker {position:relative;z-index:65534;width:100%;height:100%;}
|
||||
.do-ui-datepicker a {text-decoration:none;}
|
||||
.do-ui-datepicker .date-input {float:left;width:100%;height:100%;border:1px solid #ddd;line-height:18px;padding:0 5px;}
|
||||
|
||||
.do-ui-datepicker .calendar {position:absolute;z-index:65534;left:0;top:98%;width:230px;height:auto;min-height:60px;padding:10px;border:1px solid #ddd;background:#fff;font-size:13px;box-shadow:0 0 5px rgba(0,0,0,.1)}
|
||||
|
||||
.do-ui-datepicker .calendar-hd {width:100%;height:30px;line-height:30px;background:#f3f3f3;color:#666;text-align:center;}
|
||||
.do-ui-datepicker .calendar-contrl {position:relative;width:90%;height:30px;margin:0 5%;line-height:30px;border-bottom:1px solid #eee;color:#09f;text-align:center;}
|
||||
.do-ui-datepicker .calendar-contrl a {position:absolute;top:0;left:0;width:30px;color:#09f;}
|
||||
.do-ui-datepicker .calendar-contrl .prev-month {left:30px;}
|
||||
.do-ui-datepicker .calendar-contrl .next-month {left:auto;right:30px;}
|
||||
.do-ui-datepicker .calendar-contrl .next-year {left:auto;right:0;}
|
||||
|
||||
.do-ui-datepicker .calendar-table {position:relative;width:90%;height:auto;margin:0 5%;line-height:25px;color:#888;text-align:center;}
|
||||
.do-ui-datepicker .calendar-table .tr {width:100%;height:auto;min-height:25px;}
|
||||
.do-ui-datepicker .calendar-table .tr.tr-hd {border-bottom:1px solid #eee;margin-bottom:3px;}
|
||||
.do-ui-datepicker .calendar-table .tr .td {float:left;width:14.28%;height:25px;}
|
||||
.do-ui-datepicker .calendar-table .tr .do-st-hand:hover {background:#b6def9;}
|
||||
.do-ui-datepicker .calendar-table .tr .td.weeken {color:#f30;}
|
||||
.do-ui-datepicker .calendar-table .tr .td.selected {background:#09f;color:#fff;}
|
||||
.do-ui-datepicker .calendar-table .tr .td.disabled {color:#ddd;cursor:default;}
|
||||
|
||||
.do-ui-datepicker .time-contrl {position:relative;width:90%;height:30px;margin:5px 5%;line-height:30px;border-top:1px solid #eee;color:#888;}
|
||||
.do-ui-datepicker .time-contrl label {float:left;height:20px;margin:5px 5px 5px 0;}
|
||||
.do-ui-datepicker .time-contrl input {float:left;width:25px;height:20px;padding:0 3px;line-height:17px;outline:none;}
|
||||
.do-ui-datepicker .time-contrl label:after {float:right;height:20px;line-height:20px;font-size:12px;}
|
||||
.do-ui-datepicker .time-contrl .hours:after {content:"时"}
|
||||
.do-ui-datepicker .time-contrl .minutes:after {content:"分"}
|
||||
.do-ui-datepicker .time-contrl .seconds:after {content:"秒"}
|
||||
.do-ui-datepicker .time-contrl .now {float:right;width:40px;height:20px;margin:5px;border:1px solid #ddd;border-radius:3px;line-height:20px;background:#f7f7f7;color:#888;text-align:center;}
|
||||
.do-ui-datepicker .time-contrl .now:hover {background:#eee;}
|
||||
.do-ui-datepicker .time-contrl .now:active {background:#e7e7e7;}
|
||||
.do-ui-datepicker .calendar-tips {position:absolute;z-index:65535;left:25%;top:40%;width:50%;height:30px;line-height:30px;background:rgba(0,0,0,.7);color:#fff;font-size:12px;text-align:center;}
|
|
@ -0,0 +1,375 @@
|
|||
/**
|
||||
*
|
||||
* @authors yutent (yutent@doui.cc)
|
||||
* @date 2016-02-14 13:58:39
|
||||
*
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
define(['avalon',
|
||||
'css!./doui.datepicker.min'
|
||||
],
|
||||
function(av){
|
||||
//父级vm
|
||||
var parentVm = null
|
||||
|
||||
av.component('do:datepicker', {
|
||||
$replace: true,
|
||||
$template: '<div class="do-ui-datepicker do-fn-noselect"><input class="date-input" type="text" ms-duplex="dateVal" ms-on-focus="$focus" ms-click="$cancelBubble" ms-attr-disabled="disabled" ms-css="{borderWidth: border, borderRadius: radius}"><div class="calendar" ms-if="showCalendar" ms-click="$cancelBubble"><div class="calendar-hd">请选择日期</div><div class="calendar-contrl"><a href="javascript:;" ms-click="$turn(1, -1)" class="prev-year">{{btns.prevYear}}</a><a href="javascript:;" ms-click="$turn(0, -1)" class="prev-month">{{btns.prevMonth}}</a><a href="javascript:;" ms-click="$turn(0, 1)" class="next-month">{{btns.nextMonth}}</a><a href="javascript:;" ms-click="$turn(1, 1)" class="next-year">{{btns.nextYear}}</a><span class="date-display">{{calendar.year + \'-\' + calendar.month}}</span></div><ul class="calendar-table"><li class="tr tr-hd"><span class="td">日</span><span class="td">一</span><span class="td">二</span><span class="td">三</span><span class="td">四</span><span class="td">五</span><span class="td">六</span></li><li class="tr list do-fn-cl"><span class="td" ms-class="{weeken:el.weeken, \'do-st-hand\': !el.disable, disabled: el.disable, selected: el.selected}" ms-repeat="calendar.list" ms-click="$getDate(el.disable, el.day)">{{el.day}}</span></li></ul><div class="time-contrl" ms-if="showTime"><label class="hours"><input type="text" ms-duplex-time="calendar.hour" data-format="hour"></label><label class="minutes"><input type="text" ms-duplex-time="calendar.minute" data-format="minute"></label><label class="seconds"><input type="text" ms-duplex-time="calendar.second" data-format="second"></label><a href="javascript:;" class="now" ms-click="$now">现在</a></div><span class="calendar-tips" ms-if="tips">{{tips}}</span></div></div>',
|
||||
$construct: function(opts, b, c){
|
||||
var vm = av.mix(b, c)
|
||||
/********** 获取上一级vm ***********/
|
||||
var pctrl = vm.duplex.slice(0, vm.duplex.indexOf('.'))
|
||||
parentVm = av.vmodels[pctrl]
|
||||
/**********************************/
|
||||
//获取初始值
|
||||
vm.duplex = vm.duplex.slice(vm.duplex.indexOf('.') + 1)
|
||||
var defaultVal = (new Function('v', 'return v.' + vm.duplex))(parentVm)
|
||||
|
||||
//日期格式化, 默认会调用过滤器的格式'Y-m-d H:i:s'
|
||||
if(!vm.showTime && !vm.format){
|
||||
vm.format = 'Y-m-d';
|
||||
}
|
||||
|
||||
if(defaultVal === undefined){
|
||||
if(vm.minDate){
|
||||
defaultVal = vm.minDate, vm.format;
|
||||
}else if(opts.maxDate){
|
||||
defaultVal = vm.maxDate, vm.format;
|
||||
}
|
||||
}
|
||||
opts.dateVal = defaultVal && av.filters.date(defaultVal, vm.format)
|
||||
opts.calendar = {
|
||||
list: [],
|
||||
year: av.filters.date(opts.dateVal, 'Y'),
|
||||
month: av.filters.date(opts.dateVal, 'm'),
|
||||
day: av.filters.date(opts.dateVal, 'd') || 0,
|
||||
hour: av.filters.date(opts.dateVal, 'H') || 0,
|
||||
minute: av.filters.date(opts.dateVal, 'i') || 0,
|
||||
second: av.filters.date(opts.dateVal, 's') || 0,
|
||||
minYear: vm.minDate && av.filters.date(vm.minDate, 'Y') >> 0,
|
||||
minMonth: vm.minDate && av.filters.date(vm.minDate, 'm') >> 0,
|
||||
minDay: vm.minDate && av.filters.date(vm.minDate, 'd') >> 0 || 1,
|
||||
maxYear: vm.maxDate && av.filters.date(vm.maxDate, 'Y') >> 0,
|
||||
maxMonth: vm.maxDate && av.filters.date(vm.maxDate, 'm') >> 0,
|
||||
maxDay: vm.maxDate && av.filters.date(vm.maxDate, 'd') >> 0
|
||||
}
|
||||
//移除部分属性
|
||||
delete vm.minDate;
|
||||
delete vm.maxDate;
|
||||
|
||||
return av.mix(opts, vm)
|
||||
},
|
||||
$init: function(vm, ele){
|
||||
// av.log(vm)
|
||||
var lastDate = {
|
||||
year: vm.calendar.year >> 0,
|
||||
month: vm.calendar.month >> 0,
|
||||
day: vm.calendar.day >> 0
|
||||
}
|
||||
var timer
|
||||
|
||||
getCalendar() //初始化日历显示
|
||||
|
||||
//日历按钮,未超出限制时切换日历
|
||||
vm.$turn = function(type, step){
|
||||
var year = vm.calendar.year >> 0,
|
||||
month = vm.calendar.month >> 0;
|
||||
|
||||
if(type === 1){
|
||||
year += step;
|
||||
}else{
|
||||
month += step;
|
||||
if(month < 1){
|
||||
month = 12;
|
||||
year--
|
||||
}
|
||||
if(month > 12){
|
||||
month = 1;
|
||||
year++
|
||||
}
|
||||
}
|
||||
if(isLimited(year, month) === true){
|
||||
vm.tips = '日期超出限制';
|
||||
return;
|
||||
}
|
||||
vm.calendar.year = year;
|
||||
vm.calendar.month = numberFormat(month, 2);
|
||||
}
|
||||
|
||||
//选择日期
|
||||
vm.$getDate = function(disabled, day){
|
||||
if(disabled)
|
||||
return;
|
||||
|
||||
vm.calendar.day = day;
|
||||
|
||||
changeStyle(day);
|
||||
updateTime();
|
||||
vm.showCalendar = !1;
|
||||
}
|
||||
|
||||
//输入框获取焦点时,显示日历
|
||||
vm.$focus = function(){
|
||||
vm.showCalendar = !0;
|
||||
}
|
||||
|
||||
//获取当前时间
|
||||
vm.$now = function(){
|
||||
var year = av.filters.date(null, 'Y') >> 0,
|
||||
month = av.filters.date(null, 'm') >> 0,
|
||||
day = av.filters.date(null, 'd') >> 0;
|
||||
|
||||
var isLimitYM = isLimited(year, month),
|
||||
disabled = disabledDay(day, isLimitYM);
|
||||
|
||||
if(disabled){
|
||||
vm.tips = '今天超出了限制日期';
|
||||
return;
|
||||
}
|
||||
|
||||
vm.calendar.year = year;
|
||||
vm.calendar.month = month;
|
||||
vm.calendar.day = day;
|
||||
vm.calendar.hour = av.filters.date(null, 'H');
|
||||
vm.calendar.minute = av.filters.date(null, 'i');
|
||||
vm.calendar.second = av.filters.date(null, 's');
|
||||
|
||||
changeStyle(day);
|
||||
updateTime();
|
||||
|
||||
vm.showCalendar = !1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
//计算日历数组
|
||||
function getCalendar(){
|
||||
var year = vm.calendar.year >> 0
|
||||
var month = vm.calendar.month >> 0
|
||||
var nums = getNumsOfYearMonth(year, month)
|
||||
var numsFixed = -getDayByYearMonth(year, month) + 1
|
||||
var isLimitYM = isLimited(year, month)
|
||||
|
||||
vm.calendar.list.clear();
|
||||
|
||||
for(var i = numsFixed; i <= nums; i++){
|
||||
|
||||
var day = {
|
||||
weeken: !1,
|
||||
day: '',
|
||||
selected: !1,
|
||||
disable: !0
|
||||
}
|
||||
if(i > 0){
|
||||
var d = getDayByYearMonth(year, month, i)
|
||||
day = {
|
||||
weeken: d == 0 || d == 6,
|
||||
day: i,
|
||||
selected: isSelected(i),
|
||||
disable: disabledDay(i, isLimitYM)
|
||||
}
|
||||
}
|
||||
vm.calendar.list.push(day)
|
||||
}
|
||||
}
|
||||
|
||||
//判断当前年/月是否超出限制
|
||||
function isLimited(year, month){
|
||||
var limit = {
|
||||
Y: vm.calendar.minYear,
|
||||
M: vm.calendar.minMonth,
|
||||
mY: vm.calendar.maxYear,
|
||||
mM: vm.calendar.maxMonth,
|
||||
}
|
||||
var res = ''
|
||||
|
||||
if((!limit.Y && !limit.mY) || (!limit.M && !limit.mM))
|
||||
return false
|
||||
|
||||
if(year){
|
||||
if((limit.Y && year < limit.Y) || (limit.mY && year > limit.mY))
|
||||
return true
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
|
||||
if(month){
|
||||
if(year === limit.Y){
|
||||
if(limit.M && month < limit.M)
|
||||
return true
|
||||
|
||||
if(month == limit.M)
|
||||
res += '-'
|
||||
}
|
||||
|
||||
if(year === limit.mY){
|
||||
if(limit.mM && month > limit.mM)
|
||||
return true
|
||||
|
||||
if(month == limit.mM)
|
||||
res += '+'
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
//判断指定天数是否有效
|
||||
function disabledDay(day, limitedYM){
|
||||
var minD = vm.calendar.minDay
|
||||
var maxD = vm.calendar.maxDay
|
||||
|
||||
if(limitedYM === '-')
|
||||
return day < minD
|
||||
|
||||
if(limitedYM === '+')
|
||||
return maxD && day > maxD
|
||||
|
||||
if(limitedYM === '-+')
|
||||
return day < minD || (maxD && day > maxD)
|
||||
|
||||
return limitedYM
|
||||
}
|
||||
|
||||
//判断指定天数是否被选中
|
||||
function isSelected(day){
|
||||
var year = vm.calendar.year >> 0
|
||||
var month = vm.calendar.month >> 0
|
||||
|
||||
return !(lastDate.year !== year || lastDate.month !== month || lastDate.day !== day)
|
||||
}
|
||||
|
||||
//修改当前选中日期的样式
|
||||
function changeStyle(day){
|
||||
vm.calendar.list.forEach(function(item){
|
||||
if(item.day != day){
|
||||
item.selected = !1
|
||||
}else{
|
||||
item.selected = !0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//更新时间
|
||||
function updateTime(){
|
||||
var cal = vm.calendar
|
||||
var year = cal.year
|
||||
var month = cal.month
|
||||
var day = cal.day
|
||||
var hour = cal.hour
|
||||
var minute = cal.minute
|
||||
var second = cal.second
|
||||
var date = year + '-' + month + '-' + day
|
||||
|
||||
if(vm.showTime){
|
||||
date += ' ' + hour + ':' + minute + ':' + second
|
||||
}
|
||||
lastDate = {
|
||||
year: year >> 0,
|
||||
month: month >> 0,
|
||||
day: day >> 0
|
||||
}
|
||||
vm.dateVal = av.filters.date(date, vm.format)
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vm.$watch('calendar.year', function(){
|
||||
getCalendar();
|
||||
})
|
||||
|
||||
vm.$watch('calendar.month', function(){
|
||||
getCalendar();
|
||||
})
|
||||
vm.$watch('calendar.hour', function(v){
|
||||
vm.calendar.hour = v
|
||||
updateTime()
|
||||
})
|
||||
vm.$watch('calendar.minute', function(v){
|
||||
vm.calendar.minute = v
|
||||
updateTime()
|
||||
})
|
||||
vm.$watch('calendar.second', function(v){
|
||||
vm.calendar.second = v
|
||||
updateTime()
|
||||
})
|
||||
|
||||
vm.$watch('showCalendar', function(v){
|
||||
if(v || !vm.duplex)
|
||||
return;
|
||||
|
||||
eval('parentVm.' + vm.duplex + ' = "' + vm.dateVal + '"');
|
||||
vm.callback && vm.callback(vm.dateVal);
|
||||
})
|
||||
|
||||
vm.$watch('tips', function(v){
|
||||
if(!v)
|
||||
return;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function(){
|
||||
vm.tips = '';
|
||||
}, 1500)
|
||||
})
|
||||
|
||||
document.addEventListener('click', function(){
|
||||
vm.showCalendar = !1;
|
||||
})
|
||||
|
||||
},
|
||||
showTime: false, //对话框上显示时间
|
||||
showCalendar: false, //显示日历对话框
|
||||
disabled: false, //是否禁用
|
||||
exclass: '', //输入框拓展样式, 用于外部调整输入框样式以适配各种场景
|
||||
tips: '',
|
||||
duplex: '',
|
||||
format: '', // 日期显示格式
|
||||
dateVal: '',
|
||||
radius: 0, //日历输入框边框圆角半径
|
||||
border: 1, //日历输入框边框大小
|
||||
btns: { //切换年份/月份的按钮上的字符
|
||||
prevYear: '<<',
|
||||
nextYear: '>>',
|
||||
prevMonth: '<',
|
||||
nextMonth: '>'
|
||||
},
|
||||
$focus: av.noop,
|
||||
$turn: av.noop,
|
||||
$getDate: av.noop,
|
||||
$now: av.noop,
|
||||
$cancelBubble: function(event){
|
||||
event.stopPropagation && event.stopPropagation() || (event.cancelBubble = true);
|
||||
},
|
||||
callback: null, //日期被修改后的回调
|
||||
})
|
||||
|
||||
|
||||
//获取今年的年份/月份,返回的是数组
|
||||
function getThisYearMonth(){
|
||||
var oDate = new Date()
|
||||
return [oDate.getFullYear(), oDate.getMonth() + 1]
|
||||
}
|
||||
|
||||
//根据年份获取指定月份天数
|
||||
function getNumsOfYearMonth(year, month){
|
||||
return new Date(year, month, 0).getDate()
|
||||
}
|
||||
|
||||
//判断指定年月第一天是星期几
|
||||
function getDayByYearMonth(year, month, day){
|
||||
day = day || 1
|
||||
return new Date(year, month - 1, day).getDay()
|
||||
}
|
||||
//数字长度补全(前面加0)
|
||||
function numberFormat(num, len){
|
||||
num += ''
|
||||
if(num.length === len)
|
||||
return num
|
||||
|
||||
while(num.length < len)
|
||||
num = '0' + num
|
||||
return num
|
||||
}
|
||||
|
||||
return av
|
||||
})
|
|
@ -0,0 +1 @@
|
|||
@charset "UTF-8";.do-ui-datepicker{position:relative;z-index:65534;width:100%;height:100%}.do-ui-datepicker a{text-decoration:none}.do-ui-datepicker .date-input{float:left;width:100%;height:100%;border:1px solid #ddd;line-height:18px;padding:0 5px}.do-ui-datepicker .calendar{position:absolute;z-index:65534;left:0;top:98%;width:230px;height:auto;min-height:60px;padding:10px;border:1px solid #ddd;background:#fff;font-size:13px;box-shadow:0 0 5px rgba(0,0,0,.1)}.do-ui-datepicker .calendar-hd{width:100%;height:30px;line-height:30px;background:#f3f3f3;color:#666;text-align:center}.do-ui-datepicker .calendar-contrl{position:relative;width:90%;height:30px;margin:0 5%;line-height:30px;border-bottom:1px solid #eee;color:#09f;text-align:center}.do-ui-datepicker .calendar-contrl a{position:absolute;top:0;left:0;width:30px;color:#09f}.do-ui-datepicker .calendar-contrl .prev-month{left:30px}.do-ui-datepicker .calendar-contrl .next-month{left:auto;right:30px}.do-ui-datepicker .calendar-contrl .next-year{left:auto;right:0}.do-ui-datepicker .calendar-table{position:relative;width:90%;height:auto;margin:0 5%;line-height:25px;color:#888;text-align:center}.do-ui-datepicker .calendar-table .tr{width:100%;height:auto;min-height:25px}.do-ui-datepicker .calendar-table .tr.tr-hd{border-bottom:1px solid #eee;margin-bottom:3px}.do-ui-datepicker .calendar-table .tr .td{float:left;width:14.28%;height:25px}.do-ui-datepicker .calendar-table .tr .do-st-hand:hover{background:#b6def9}.do-ui-datepicker .calendar-table .tr .td.weeken{color:#f30}.do-ui-datepicker .calendar-table .tr .td.selected{background:#09f;color:#fff}.do-ui-datepicker .calendar-table .tr .td.disabled{color:#ddd;cursor:default}.do-ui-datepicker .time-contrl{position:relative;width:90%;height:30px;margin:5px 5%;line-height:30px;border-top:1px solid #eee;color:#888}.do-ui-datepicker .time-contrl label{float:left;height:20px;margin:5px 5px 5px 0}.do-ui-datepicker .time-contrl input{float:left;width:25px;height:20px;padding:0 3px;line-height:17px;outline:0}.do-ui-datepicker .time-contrl label:after{float:right;height:20px;line-height:20px;font-size:12px}.do-ui-datepicker .time-contrl .hours:after{content:"时"}.do-ui-datepicker .time-contrl .minutes:after{content:"分"}.do-ui-datepicker .time-contrl .seconds:after{content:"秒"}.do-ui-datepicker .time-contrl .now{float:right;width:40px;height:20px;margin:5px;border:1px solid #ddd;border-radius:3px;line-height:20px;background:#f7f7f7;color:#888;text-align:center}.do-ui-datepicker .time-contrl .now:hover{background:#eee}.do-ui-datepicker .time-contrl .now:active{background:#e7e7e7}.do-ui-datepicker .calendar-tips{position:absolute;z-index:65535;left:25%;top:40%;width:50%;height:30px;line-height:30px;background:rgba(0,0,0,.7);color:#fff;font-size:12px;text-align:center}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<title>测试1</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<link href="../../css/base.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.do-mod-test {width:800px;height:100px;margin:30px;padding:30px;border:1px solid #ddd;}
|
||||
.do-mod-test section {float:left;;;;width:35%;height:35px;margin:0 3%;line-height:35px;}
|
||||
.do-mod-test section:nth-child(2) {border:1px solid #ddd;}
|
||||
.do-mod-test section .label {float:left;width:35%;height:35px;text-align:center;}
|
||||
.do-mod-test section .date {float:left;width:65%;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<div class="do-mod-test" ms-controller="test">
|
||||
|
||||
<section>
|
||||
<span class="label">示例1:</span>
|
||||
<do:datepicker config="dp" duplex="test.ex1" border="1" class="date" radius="3"></do:datepicker>
|
||||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<span class="label">示例2:</span>
|
||||
<do:datepicker config="dp" duplex="test.ex2" border="0" show-time="true" class="date"></do:datepicker>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<script src="../../avalon.modern.min.js"></script>
|
||||
<script>
|
||||
;(function(av){
|
||||
|
||||
require(['./datepicker/doui.datepicker'], function(){
|
||||
|
||||
|
||||
var test = av.define({
|
||||
$id: 'test',
|
||||
ex1: '2016-01-02',
|
||||
ex2: '2015-12-06 20:22:12',
|
||||
dp: {
|
||||
callback: function(d){
|
||||
console.log(d)
|
||||
},
|
||||
maxDate: '2017-02-05',
|
||||
format: 'Y 第W周'
|
||||
}
|
||||
});
|
||||
|
||||
av.scan()
|
||||
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
||||
|
||||
})(avalon)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,85 @@
|
|||
# 拖拽插件
|
||||
> 该插件可以让任意一个元素可以被拖拽,而不需要该元素是否具有定位属性。
|
||||
> 使用时,在目标元素上添加`:drag`属性即可以实现拖拽功能。
|
||||
|
||||
## 依赖
|
||||
> 依赖`yua`框架
|
||||
|
||||
## 浏览器兼容性
|
||||
+ chrome
|
||||
+ firefox
|
||||
+ safari
|
||||
+ IE10+
|
||||
|
||||
|
||||
## 用法
|
||||
> 只需要在要拖拽的元素上添加`:drag`即可;
|
||||
> 如果要拖拽的元素不是当前元素,只需要给该属性增加一个值为想要拖拽元素的类名或ID。
|
||||
> 具体请看示例:
|
||||
> **注意:** `拖拽的元素不是本身时,只会往父级一级一级找相匹配的`
|
||||
|
||||
```html
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
* {margin:0;padding:0}
|
||||
.box {width:100px;height:100px;background:#f30;}
|
||||
</style>
|
||||
</head>
|
||||
<body :controller="test">
|
||||
|
||||
<div class="box" :drag></div>
|
||||
|
||||
<script src="/js/yua.js"></script>
|
||||
<script>
|
||||
|
||||
require(['tool/drag/drag.min'], function(){
|
||||
|
||||
yua.define({
|
||||
$id: 'test'
|
||||
})
|
||||
yua.scan()
|
||||
})
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
|
||||
```html
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
* {margin:0;padding:0}
|
||||
.box {width:200px;height:100px;background:#aaa;}
|
||||
.box .handle {width:200px;height:30px;background:#f30;}
|
||||
</style>
|
||||
</head>
|
||||
<body :controller="test">
|
||||
|
||||
<div class="box">
|
||||
<div class="handle" :drag="box"></div>
|
||||
</div>
|
||||
|
||||
<script src="/js/yua.js"></script>
|
||||
<script>
|
||||
|
||||
require(['tool/drag/drag.min'], function(){
|
||||
|
||||
yua.define({
|
||||
$id: 'test'
|
||||
})
|
||||
yua.scan()
|
||||
})
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
|
@ -0,0 +1,217 @@
|
|||
/**
|
||||
*
|
||||
* @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.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 = !!binding.element.dataset.overflow
|
||||
|
||||
//方向,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
|
||||
delete binding.element.dataset.limit
|
||||
}
|
||||
|
||||
// 如果不限制,则允许溢出
|
||||
if(binding.limit === false) {
|
||||
binding.overflow = true
|
||||
}
|
||||
|
||||
delete binding.element.dataset.overflow
|
||||
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,
|
||||
parent = 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'){
|
||||
parent = target.parentNode
|
||||
}
|
||||
|
||||
|
||||
var dx,dy,mx,my,ox,oy,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 = document.body.scrollTop
|
||||
bsl = document.body.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){
|
||||
_this.beforedrag.call(_this.vmodels, target, ox, oy)
|
||||
}
|
||||
|
||||
//限制区域, 4个值依次是: 上, 下, 左, 右
|
||||
var limit = [0, wh - th, 0, ww - tw]
|
||||
|
||||
if(_this.limit === 'parent') {
|
||||
var pgcs = getComputedStyle(parent),
|
||||
pcst = pgcs.transform.replace(/matrix\((.*)\)/, '$1'),
|
||||
poffset = yua(parent).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 + parent.clientHeight - th, pox, pox + parent.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
|
||||
}
|
||||
|
||||
|
||||
var 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)
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
})
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<title>Examples</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<link href="../css/base.min.css" rel="stylesheet">
|
||||
<style type="text/css">
|
||||
body {background:url(/123.png) no-repeat;}
|
||||
.a {display:inline-block;min-width:80px;height:32px;margin:10px;padding:0 10px;text-decoration:none;border:1px solid #ddd;line-height:30px;}
|
||||
</style>
|
||||
</head>
|
||||
<body ms-controller="test">
|
||||
|
||||
<a class="a" href="javascript:;" ms-click="layer.alert('测试alert内容')">alert层</a>
|
||||
<a class="a" href="javascript:;" ms-click="layer.confirm('测试confirm内容')">confirm层</a>
|
||||
<a class="a" href="javascript:;" ms-click="layer.msg('测试msg内容')">msg层</a>
|
||||
<a class="a" href="javascript:;" ms-click="layer.prompt('测试prompt内容')">prompt层</a>
|
||||
<a class="a" href="javascript:;" ms-click="layer.loading('测试loading内容')">loading层</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="../avalon.modern.min.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
require(['layer/layer.js'], function(lay){
|
||||
|
||||
avalon.define({
|
||||
$id: 'test'
|
||||
})
|
||||
|
||||
layer.alert('测试loading内容blabla')
|
||||
layer.confirm('测试loading内容blabla测试loading内容blabla测试loading内容blabla', {offset: {x: '550px', y: '690px'}})
|
||||
layer.open({content: '测试loading内容blabla', offset: {x: '350px', y: '390px'}})
|
||||
|
||||
avalon.scan()
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
*
|
||||
* @authors yutent (yutent@doui.cc)
|
||||
* @date 2016-09-21 01:36:29
|
||||
*
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
define(['avalon', 'css!./skin/def'], function(av){
|
||||
|
||||
|
||||
|
||||
var prep = {
|
||||
type: {
|
||||
1: 'alert',
|
||||
2: 'confirm',
|
||||
3: 'msg',
|
||||
4: 'loading',
|
||||
5: 'iframe',
|
||||
6: 'tips',
|
||||
7: 'prompt'
|
||||
},
|
||||
init: {
|
||||
type: 1,
|
||||
shade: true,
|
||||
shadeClose: false,
|
||||
move: '.do-ui-layer-move',
|
||||
title: '温馨提示',
|
||||
content: '',
|
||||
offset: {x: '300px', y: '200px'},
|
||||
btns: ['确定', '取消'],
|
||||
yes: av.noop,
|
||||
no: av.noop,
|
||||
success: av.noop
|
||||
}
|
||||
}
|
||||
|
||||
function uuid(type){
|
||||
type = type || 1
|
||||
return prep.type[type] + Math.round(Date.now()/1000).toString(16) + Math.random().toString(16).slice(2, 6)
|
||||
}
|
||||
|
||||
|
||||
|
||||
var layer = {
|
||||
alert: function(msg, conf){
|
||||
conf = conf || {}
|
||||
return layer.open(av.mix({content: msg}, conf))
|
||||
},
|
||||
confirm: function(msg, conf){
|
||||
conf = conf || {}
|
||||
return layer.open(av.mix({content: msg}, conf))
|
||||
},
|
||||
msg: function(msg, conf){
|
||||
av.log(msg)
|
||||
},
|
||||
loading: function(msg, conf){
|
||||
av.log(msg)
|
||||
},
|
||||
iframe: function(url, conf){
|
||||
av.log(url)
|
||||
},
|
||||
tips: function(msg, conf){
|
||||
av.log(msg)
|
||||
},
|
||||
prompt: function(callback){
|
||||
av.log('23456')
|
||||
},
|
||||
use: function(conf, callback){
|
||||
require(['css!./skin/' + conf.skin], callback)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var FN = function(conf){
|
||||
this.ready(conf)
|
||||
}
|
||||
|
||||
|
||||
FN.prototype = {
|
||||
init: {},
|
||||
create: function(){
|
||||
var layBox = document.createElement('div')
|
||||
layBox.className = 'do-ui-layer skin-def'
|
||||
layBox.style.left = this.init.offset.x
|
||||
layBox.style.top = this.init.offset.y
|
||||
layBox.setAttribute('ms-controller', this.init.$id)
|
||||
layBox.innerHTML = '<div class="layer-title">{{title}}<a class="layer-min deficon"></a><a class="layer-close deficon"></a></div>' +
|
||||
'<div class="layer-content">' +
|
||||
'<span class="deficon icon-1"></span>' +
|
||||
'<div class="detail" ms-html="content"></div>' +
|
||||
'</div>' +
|
||||
'<div class="layer-btns">' +
|
||||
'<a href="javascript:;" class="layer-yes" ms-text="btns[0]"></a>' +
|
||||
'<a href="javascript:;" class="layer-no" ms-text="btns[1]"></a>' +
|
||||
'</div>'
|
||||
return layBox
|
||||
},
|
||||
show: function(){
|
||||
|
||||
var layBox = this.create()
|
||||
document.body.appendChild(layBox)
|
||||
|
||||
av.define(this.init)
|
||||
av.scan(layBox)
|
||||
},
|
||||
ready: function(conf){
|
||||
this.init = av.mix({$id: uuid()}, prep.init, conf)
|
||||
this.show()
|
||||
},
|
||||
close: function(){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
layer.open = function(conf){
|
||||
av.log(conf)
|
||||
return new FN(conf).init
|
||||
}
|
||||
|
||||
|
||||
if(!window.layer)
|
||||
window.layer = layer
|
||||
|
||||
|
||||
|
||||
return layer
|
||||
|
||||
|
||||
})
|
|
@ -0,0 +1,49 @@
|
|||
@charset "UTF-8";
|
||||
/**
|
||||
*
|
||||
* @authors yutent (yutent@doui.cc)
|
||||
* @date 2016-09-21 01:36:22
|
||||
*
|
||||
*/
|
||||
|
||||
.do-ui-layer, .do-ui-layer * {margin: 0;padding: 0;vertical-align: baseline;box-sizing:border-box;}
|
||||
.do-ui-layer a {text-decoration:none;}
|
||||
|
||||
@font-face {font-family: "deficon";
|
||||
src: url('def.eot?t=1474609176'); /* IE9*/
|
||||
src: url('def.woff?t=1474609176') format('woff'), /* chrome, firefox */
|
||||
url('def.ttf?t=1474609176') format('truetype'); /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
|
||||
}
|
||||
|
||||
.do-ui-layer-shade {position:fixed;left:0;top:0;z-index:65534;width:100%;height:100%;background:rgba(255,255,255,.05);}
|
||||
.do-ui-layer {position:fixed;left:50%;top:230px;z-index:65535;width:auto;height:auto;}
|
||||
|
||||
|
||||
.do-ui-layer.skin-def {min-width:300px;background:#fff;color:#666;font-size:13px;box-shadow:0 0 10px rgba(0,0,0,.3);}
|
||||
.do-ui-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-ui-layer.skin-def .icon-1:before {content:"\e605";color:#11b330;}
|
||||
.do-ui-layer.skin-def .icon-2:before {content:"\e602";color:#f30;}
|
||||
.do-ui-layer.skin-def .icon-3:before {content:"\e603";color:#f30;}
|
||||
.do-ui-layer.skin-def .icon-4:before {content:"\e604";color:#f30;}
|
||||
.do-ui-layer.skin-def .icon-5:before {content:"\e608";color:#09f;}
|
||||
.do-ui-layer.skin-def .icon-6:before {content:"\e609";color:#ee0}
|
||||
.do-ui-layer.skin-def .icon-7:before {content:"\e60a";color:#63e2c2}
|
||||
.do-ui-layer.skin-def .icon-8:before {content:"\e606";color:#ee0}
|
||||
.do-ui-layer.skin-def .icon-9:before {content:"\e607";color:#f30;}
|
||||
|
||||
|
||||
|
||||
.do-ui-layer.skin-def .layer-title {width:100%;height:40px;padding:0 8px;line-height:40px;background:#f3f3f3;font-size:14px;color:#454545;}
|
||||
.do-ui-layer.skin-def .layer-min,.do-ui-layer.skin-def .layer-close {position:absolute;display:block;top:10px;width:20px;height:20px;line-height:20px;border:0;text-align:center;cursor:pointer;}
|
||||
.do-ui-layer.skin-def .layer-min {right:40px;}
|
||||
.do-ui-layer.skin-def .layer-close {right:10px;}
|
||||
.do-ui-layer.skin-def .layer-close:hover,.do-ui-layer.skin-def .layer-min:hover {border: 1px solid #ddd;line-height: 18px;}
|
||||
.do-ui-layer.skin-def .layer-min:before {content:"\e600";}
|
||||
.do-ui-layer.skin-def .layer-close:before {content:"\e601";}
|
||||
|
||||
.do-ui-layer.skin-def .layer-content {width:100%;height:auto;min-height:100px;padding:10px;}
|
||||
.do-ui-layer.skin-def .layer-content .deficon {float:left;width:60px;height:100%;line-height:50px;font-size:40px;text-align:center;}
|
||||
.do-ui-layer.skin-def .layer-content .detail {float:left;width:auto;height:100%;margin-top:10px;padding:5px 15px;word-break:break-all;word-wrap: break-word;}
|
||||
|
||||
.do-ui-layer.skin-def .layer-btns {width:100%;height:40px;padding:0 5px;line-height:28px;font-size:14px;color:#454545;text-align:right;}
|
||||
.do-ui-layer.skin-def .layer-btns a {display:inline-block;width:auto;min-width:60px;height:30px;margin:0 5px;padding:0 10px;line-height:28px;border:1px solid #ddd;color:#454545;text-align:center;background:#f3f3f3;}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,27 @@
|
|||
# md5 加密组件
|
||||
|
||||
可对普通字符串和文件计算其对应的md5值。
|
||||
|
||||
|
||||
组件符合AMD规范, 可使用require引入
|
||||
|
||||
|
||||
### demo:
|
||||
|
||||
```javascript
|
||||
require(['./md5'], function(SparkMD5){
|
||||
var Spark = new SparkMD5()
|
||||
var md5 = function(cont){
|
||||
return Spark.sign.call(Spark, cont)
|
||||
}
|
||||
|
||||
var file = /*...*/ //文件表单获取
|
||||
var fs = new FileReader() // Chrome, IE9+, FF, Safari
|
||||
fs.readAsBinaryString(file)
|
||||
|
||||
fs.onload = function(){ // 计算该文件的md5签名
|
||||
var sign = md5(this.result)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<title>Examples-1</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<link href="../css/base.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.do-mod-test {width:800px;height:100px;margin:30px;padding:30px;border:1px solid #ddd;}
|
||||
.do-mod-test .date-start {width:100%;height:35px;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<div class="do-mod-test" ms-controller="test">
|
||||
|
||||
<div class="pages" ms-widget="pages" data-pages-skin="red"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script src="../avalon.modern.min.js"></script>
|
||||
<script>
|
||||
|
||||
;(function(A){
|
||||
|
||||
require(['./pages/pages'], function(){
|
||||
|
||||
var test = A.define({
|
||||
$id: 'test',
|
||||
aa: '112233',
|
||||
pages: {
|
||||
callback: function(id){
|
||||
console.log(id);
|
||||
},
|
||||
total: 30
|
||||
}
|
||||
});
|
||||
|
||||
A.scan();
|
||||
|
||||
})
|
||||
|
||||
|
||||
})(avalon);
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,34 @@
|
|||
.widget-pages .do-ui-pages {width:100%;height:30px;text-align:center;}
|
||||
.widget-pages.h20 .do-ui-pages {height:20px;}
|
||||
.widget-pages .do-ui-pages a {display:inline-block;width:auto;min-width:20px;height:30px;padding:0 10px;margin:0 3px;line-height:28px;}
|
||||
.widget-pages .do-ui-pages .curr,.widget-pages .do-ui-pages .more {line-height:30px;padding:0;border:none!important;background:none!important;color:#666!important;cursor:default}
|
||||
.widget-pages.h20 .do-ui-pages a {min-width:10px;height:20px;line-height:18px;}
|
||||
.widget-pages.h20 .do-ui-pages .curr,.widget-pages.h20 .do-ui-pages .more {line-height:20px;}
|
||||
|
||||
.widget-pages .do-ui-pages .page-jump {display:inline-block;}
|
||||
.widget-pages .do-ui-pages .page-jump span,.widget-pages .do-ui-pages .page-jump input{display:inline-block;}
|
||||
.widget-pages .do-ui-pages .page-jump input {width:25px;height:18px;padding:0 3px;background:none;border:1px solid #ddd;}
|
||||
|
||||
.widget-pages.skin-default .do-ui-pages a {border:1px solid #ddd;background:#f3f3f3;color:#666;}
|
||||
.widget-pages.skin-default .do-ui-pages a:hover {border:1px solid #e3e3e3;background:#e3e3e3;color:#666;}
|
||||
.widget-pages.skin-default .do-ui-pages a:active {border:1px solid #ccc;background:#ccc;color:#666;}
|
||||
|
||||
.widget-pages.skin-blue .do-ui-pages a {border:1px solid #1b9af7;background:#1b9af7;color:#fff;}
|
||||
.widget-pages.skin-blue .do-ui-pages a:hover {border:1px solid #13b5ff;background:#13b5ff;color:#fff;}
|
||||
.widget-pages.skin-blue .do-ui-pages a:active {border:1px solid #1682cf;background:#1682cf;color:#fff;}
|
||||
|
||||
.widget-pages.skin-red .do-ui-pages a {border:1px solid #ff4351;background:#ff4351;color:#fff;}
|
||||
.widget-pages.skin-red .do-ui-pages a:hover {border:1px solid #ff7680;background:#ff7680;color:#fff;}
|
||||
.widget-pages.skin-red .do-ui-pages a:active {border:1px solid #f64c59;background:#f64c59;color:#fff;}
|
||||
|
||||
.widget-pages.skin-yellow .do-ui-pages a {border:1px solid #feae1b;background:#feae1b;color:#fff;}
|
||||
.widget-pages.skin-yellow .do-ui-pages a:hover {border:1px solid #fec04e;background:#fec04e;color:#fff;}
|
||||
.widget-pages.skin-yellow .do-ui-pages a:active {border:1px solid #f3ab26;background:#f3ab26;color:#fff;}
|
||||
|
||||
.widget-pages.skin-green .do-ui-pages a {border:1px solid #a5de37;background:#a5de37;color:#fff;}
|
||||
.widget-pages.skin-green .do-ui-pages a:hover {border:1px solid #b9e563;background:#b9e563;color:#fff;}
|
||||
.widget-pages.skin-green .do-ui-pages a:active {border:1px solid #a1d243;background:#a1d243;color:#fff;}
|
||||
|
||||
.widget-pages.skin-purple .do-ui-pages a {border:1px solid #7b72e9;background:#7b72e9;color:#fff;}
|
||||
.widget-pages.skin-purple .do-ui-pages a:hover {border:1px solid #a49ef0;background:#a49ef0;color:#fff;}
|
||||
.widget-pages.skin-purple .do-ui-pages a:active {border:1px solid #827ae1;background:#827ae1;color:#fff;}
|
|
@ -0,0 +1,127 @@
|
|||
define(["avalon","text!./pages.tpl","css!./pages.css"], function (av, tpl) {
|
||||
|
||||
var widget = av.ui.pages = function(ele, data, vms){
|
||||
|
||||
var opts = av.mix({}, data.pagesOptions);
|
||||
var height = opts.height || '',
|
||||
skin = opts.skin || 'default';
|
||||
|
||||
delete opts.skin;
|
||||
delete opts.height;
|
||||
opts.pages = []; //无论是否定义,都会清掉,有点暴力
|
||||
|
||||
opts.$id = data.pagesId;
|
||||
opts.$init = function(scan){
|
||||
ele.classList.add('widget-pages', 'skin-' + skin, 'do-fn-noselect');
|
||||
height && ele.classList.add(height);//非空时才添加,避免报错
|
||||
ele.innerHTML = tpl;
|
||||
calPages(Pager);
|
||||
scan()
|
||||
};
|
||||
opts.$remove = function() {
|
||||
ele.innerHTML = ''
|
||||
};
|
||||
opts.setUrl = function(id){
|
||||
if(!Pager.url || id === '...' || Pager.curr === id || id > Pager.total || id < 1)
|
||||
return 'javascript:;'
|
||||
return Pager.url.replace('{id}', id)
|
||||
};
|
||||
opts.onJump = function(event, id){
|
||||
event.preventDefault()
|
||||
id = id >> 0;
|
||||
jump(id, Pager);
|
||||
};
|
||||
opts.jumpPage = function(event){
|
||||
var pid = Pager.jumpTxt;
|
||||
if(pid > Pager.total)
|
||||
Pager.jumpTxt = Pager.total;
|
||||
|
||||
if(event.keyCode == 13)
|
||||
return jump(pid, Pager);
|
||||
}
|
||||
|
||||
var Pager = av.define(opts);
|
||||
|
||||
|
||||
Pager.$watch('total', function(v, old){
|
||||
Pager.total = v >> 0 || 1; //自动转换成数字类型,防止传入的值为字符串时报错,如 '3'
|
||||
old = old >> 0;
|
||||
(v !== old) && calPages(Pager);
|
||||
})
|
||||
|
||||
Pager.$watch('curr', function(v, old){
|
||||
v = v >> 0 || 1;//自动转换成数字类型
|
||||
old = old >> 0;
|
||||
Pager.curr = v;
|
||||
(v !== old) && calPages(Pager);
|
||||
})
|
||||
|
||||
return Pager;
|
||||
}
|
||||
|
||||
/**
|
||||
* [calPages 计算要显示的页码数组,并赋值给pages]
|
||||
* @param {[type]} Pager [分页vm对象]
|
||||
*/
|
||||
function calPages(Pager){
|
||||
if(Pager.total < 2){
|
||||
Pager.pages.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
var pageArr = [], len = (Pager.curr < Pager.max / 2) ? Pager.max : Math.floor(Pager.max / 2);
|
||||
|
||||
if(Pager.curr - len > 1)
|
||||
pageArr.push('...');
|
||||
|
||||
for(var i = Pager.curr - len; i < Pager.curr + len && i <= Pager.total; i++){
|
||||
if(i > 0)
|
||||
pageArr.push(i)
|
||||
}
|
||||
if(Pager.curr + len < Pager.total)
|
||||
pageArr.push('...');
|
||||
|
||||
Pager.pages = pageArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* [jump 内部跳转函数]
|
||||
* @param {[type]} id [要跳转去的页码]
|
||||
* @param {[type]} Pager [分页vm对象]
|
||||
*/
|
||||
function jump(id, Pager){
|
||||
if(id < 1)
|
||||
id = Pager.jumpTxt = 1;
|
||||
if(id > Pager.total)
|
||||
id = Pager.jumpTxt = Pager.total;
|
||||
if(Pager.curr === id)
|
||||
return;
|
||||
|
||||
Pager.curr = Pager.jumpTxt = id;
|
||||
Pager.callback && Pager.callback(id);
|
||||
|
||||
calPages(Pager);
|
||||
}
|
||||
|
||||
//默认参数
|
||||
widget.defaults = {
|
||||
curr: 1, //当前页
|
||||
total: 1, // 总页数默认为1,即页面上不会显示分页条
|
||||
max: 5, // 最多显示页码数
|
||||
url: 'javascript:;', //页码按钮上的url,如'#!/page-{id}.html',其中{id}会被替换成该页码
|
||||
pageJump: !1, //是否显示跳转表单
|
||||
simpleMode: !1, //简单模式,即只有上一页和下一页
|
||||
jumpTxt: 1, //跳转输入框显示的页码
|
||||
pages: [], //页码数组
|
||||
btns: { //除页码本身外的按钮上的字符
|
||||
prev: '<<',
|
||||
next: '>>',
|
||||
home: '首页',
|
||||
end: '末页'
|
||||
},
|
||||
callback: null //点击页码/上/下/首/末页的回调,页码无效或者为当前页的时候不会触发
|
||||
}
|
||||
|
||||
|
||||
return av;
|
||||
})
|
|
@ -0,0 +1 @@
|
|||
.widget-pages .do-ui-pages{width:100%;height:30px;text-align:center}.widget-pages.h20 .do-ui-pages{height:20px}.widget-pages .do-ui-pages a{display:inline-block;width:auto;min-width:20px;height:30px;padding:0 10px;margin:0 3px;line-height:28px}.widget-pages .do-ui-pages .curr,.widget-pages .do-ui-pages .more{line-height:30px;padding:0;border:none!important;background:none!important;color:#666!important;cursor:default}.widget-pages.h20 .do-ui-pages a{min-width:10px;height:20px;line-height:18px}.widget-pages.h20 .do-ui-pages .curr,.widget-pages.h20 .do-ui-pages .more{line-height:20px}.widget-pages .do-ui-pages .page-jump,.widget-pages .do-ui-pages .page-jump input,.widget-pages .do-ui-pages .page-jump span{display:inline-block}.widget-pages .do-ui-pages .page-jump input{width:25px;height:18px;padding:0 3px;background:0 0;border:1px solid #ddd}.widget-pages.skin-default .do-ui-pages a{border:1px solid #ddd;background:#f3f3f3;color:#666}.widget-pages.skin-default .do-ui-pages a:hover{border:1px solid #e3e3e3;background:#e3e3e3;color:#666}.widget-pages.skin-default .do-ui-pages a:active{border:1px solid #ccc;background:#ccc;color:#666}.widget-pages.skin-blue .do-ui-pages a{border:1px solid #1b9af7;background:#1b9af7;color:#fff}.widget-pages.skin-blue .do-ui-pages a:hover{border:1px solid #13b5ff;background:#13b5ff;color:#fff}.widget-pages.skin-blue .do-ui-pages a:active{border:1px solid #1682cf;background:#1682cf;color:#fff}.widget-pages.skin-red .do-ui-pages a{border:1px solid #ff4351;background:#ff4351;color:#fff}.widget-pages.skin-red .do-ui-pages a:hover{border:1px solid #ff7680;background:#ff7680;color:#fff}.widget-pages.skin-red .do-ui-pages a:active{border:1px solid #f64c59;background:#f64c59;color:#fff}.widget-pages.skin-yellow .do-ui-pages a{border:1px solid #feae1b;background:#feae1b;color:#fff}.widget-pages.skin-yellow .do-ui-pages a:hover{border:1px solid #fec04e;background:#fec04e;color:#fff}.widget-pages.skin-yellow .do-ui-pages a:active{border:1px solid #f3ab26;background:#f3ab26;color:#fff}.widget-pages.skin-green .do-ui-pages a{border:1px solid #a5de37;background:#a5de37;color:#fff}.widget-pages.skin-green .do-ui-pages a:hover{border:1px solid #b9e563;background:#b9e563;color:#fff}.widget-pages.skin-green .do-ui-pages a:active{border:1px solid #a1d243;background:#a1d243;color:#fff}.widget-pages.skin-purple .do-ui-pages a{border:1px solid #7b72e9;background:#7b72e9;color:#fff}.widget-pages.skin-purple .do-ui-pages a:hover{border:1px solid #a49ef0;background:#a49ef0;color:#fff}.widget-pages.skin-purple .do-ui-pages a:active{border:1px solid #827ae1;background:#827ae1;color:#fff}
|
|
@ -0,0 +1 @@
|
|||
define(["avalon","text!./pages.tpl","css!./pages.css"],function(t,a){function e(t){if(t.total<2)return void t.pages.clear();var a=[],e=t.curr<t.max/2?t.max:Math.floor(t.max/2);t.curr-e>1&&a.push("...");for(var r=t.curr-e;r<t.curr+e&&r<=t.total;r++)r>0&&a.push(r);t.curr+e<t.total&&a.push("..."),t.pages=a}function r(t,a){1>t&&(t=a.jumpTxt=1),t>a.total&&(t=a.jumpTxt=a.total),a.curr!==t&&(a.curr=a.jumpTxt=t,a.callback&&a.callback(t),e(a))}var n=t.ui.pages=function(n,u){var c=t.mix({},u.pagesOptions),l=c.height||"",i=c.skin||"default";delete c.skin,delete c.height,c.pages=[],c.$id=u.pagesId,c.$init=function(t){n.classList.add("widget-pages","skin-"+i,"do-fn-noselect"),l&&n.classList.add(l),n.innerHTML=a,e(o),t()},c.$remove=function(){n.innerHTML=""},c.setUrl=function(t){return!o.url||"..."===t||o.curr===t||t>o.total||1>t?"javascript:;":o.url.replace("{id}",t)},c.onJump=function(t,a){t.preventDefault(),a>>=0,r(a,o)},c.jumpPage=function(t){var a=o.jumpTxt;return a>o.total&&(o.jumpTxt=o.total),13==t.keyCode?r(a,o):void 0};var o=t.define(c);return o.$watch("total",function(t,a){o.total=t>>0||1,a>>=0,t!==a&&e(o)}),o.$watch("curr",function(t,a){t=t>>0||1,a>>=0,o.curr=t,t!==a&&e(o)}),o};return n.defaults={curr:1,total:1,max:5,url:"javascript:;",pageJump:!1,simpleMode:!1,jumpTxt:1,pages:[],btns:{prev:"<<",next:">>",home:"首页",end:"末页"},callback:null},t});
|
|
@ -0,0 +1,13 @@
|
|||
<div class="do-ui-pages">
|
||||
<a class="rd3" ms-if="curr > 1 && !simpleMode" ms-attr="{href: setUrl(1)}" ms-click="onJump($event, 1)">{{btns.home}}</a>
|
||||
<a class="rd3" ms-if="curr > 1" ms-attr="{href: setUrl(curr - 1)}" ms-click="onJump($event, curr - 1)">{{btns.prev}}</a>
|
||||
<a class="rd3" ms-if-loop="!simpleMode || curr === el" ms-repeat="pages" ms-attr="{href: setUrl(el)}" ms-class="curr: curr === el" ms-class-1="more: '...' === el" ms-click="onJump($event, el)">{{el}}</a>
|
||||
<a class="rd3" ms-if="curr < total" ms-attr="{href: setUrl(curr + 1)}" ms-click="onJump($event, curr + 1)">{{btns.next}}</a>
|
||||
<a class="rd3" ms-if="curr < total && !simpleMode" ms-attr="{href: setUrl(total)}" ms-click="onJump($event, total)">{{btns.end}}</a>
|
||||
<div class="page-jump" ms-if="pageJump && !simpleMode">
|
||||
<span>共{{total}}页,跳转到第</span>
|
||||
<input type="text" ms-duplex-number="jumpTxt" ms-keyup="jumpPage($event)">
|
||||
<span>页</span>
|
||||
<a class="rd3" ms-attr="{href: setUrl(jumpTxt)}" ms-click="onJump($event, jumpTxt)">确定</a>
|
||||
</div>
|
||||
</div>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
define(function(){"object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(t){return 10>t?"0"+t:t}function this_value(){return this.valueOf()}function quote(t){return rx_escapable.lastIndex=0,rx_escapable.test(t)?'"'+t.replace(rx_escapable,function(t){var e=meta[t];return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'}function str(t,e){var r,n,o,u,f,a=gap,i=e[t];switch(i&&"object"==typeof i&&"function"==typeof i.toJSON&&(i=i.toJSON(t)),"function"==typeof rep&&(i=rep.call(e,t,i)),typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";if(gap+=indent,f=[],"[object Array]"===Object.prototype.toString.apply(i)){for(u=i.length,r=0;u>r;r+=1)f[r]=str(r,i)||"null";return o=0===f.length?"[]":gap?"[\n"+gap+f.join(",\n"+gap)+"\n"+a+"]":"["+f.join(",")+"]",gap=a,o}if(rep&&"object"==typeof rep)for(u=rep.length,r=0;u>r;r+=1)"string"==typeof rep[r]&&(n=rep[r],o=str(n,i),o&&f.push(quote(n)+(gap?": ":":")+o));else for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(o=str(n,i),o&&f.push(quote(n)+(gap?": ":":")+o));return o=0===f.length?"{}":gap?"{\n"+gap+f.join(",\n"+gap)+"\n"+a+"}":"{"+f.join(",")+"}",gap=a,o}}var rx_one=/^[\],:{}\s]*$/,rx_two=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,rx_three=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,rx_four=/(?:^|:|,)(?:\s*\[)+/g,rx_escapable=/[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,rx_dangerous=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},Boolean.prototype.toJSON=this_value,Number.prototype.toJSON=this_value,String.prototype.toJSON=this_value);var gap,indent,meta,rep;"function"!=typeof JSON.stringify&&(meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},JSON.stringify=function(t,e,r){var n;if(gap="",indent="","number"==typeof r)for(n=0;r>n;n+=1)indent+=" ";else"string"==typeof r&&(indent=r);if(rep=e,e&&"function"!=typeof e&&("object"!=typeof e||"number"!=typeof e.length))throw new Error("JSON.stringify");return str("",{"":t})}),"function"!=typeof JSON.parse&&(JSON.parse=function(text,reviver){function walk(t,e){var r,n,o=t[e];if(o&&"object"==typeof o)for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(n=walk(o,r),void 0!==n?o[r]=n:delete o[r]);return reviver.call(t,e,o)}var j;if(text=String(text),rx_dangerous.lastIndex=0,rx_dangerous.test(text)&&(text=text.replace(rx_dangerous,function(t){return"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})),rx_one.test(text.replace(rx_two,"@").replace(rx_three,"]").replace(rx_four,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}();})
|
|
@ -0,0 +1,237 @@
|
|||
/**
|
||||
*
|
||||
* @authors yutent (yutent@doui.cc)
|
||||
* @date 2016-11-26 16:35:45
|
||||
*
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
define(function(){
|
||||
|
||||
var _Promise = function(callback){
|
||||
this.callback = []
|
||||
var _this = this
|
||||
|
||||
if(typeof this !== 'object')
|
||||
throw new TypeError('Promises must be constructed via new')
|
||||
|
||||
if(typeof callback !== 'function')
|
||||
throw new TypeError('Argument must be a function')
|
||||
|
||||
callback(function(val){
|
||||
_resolve(_this, val)
|
||||
}, function(val){
|
||||
_reject(_this, val)
|
||||
})
|
||||
}
|
||||
var self = {
|
||||
_state: 1,
|
||||
_fired: 1,
|
||||
_val: 1,
|
||||
callback: 1
|
||||
}
|
||||
|
||||
_Promise.prototype = {
|
||||
constructor: _Promise,
|
||||
_state: 'pending',
|
||||
_fired: false,
|
||||
_fire: function(yes, no){
|
||||
if(this._state === 'rejected'){
|
||||
if(typeof no === 'function')
|
||||
no(this._val)
|
||||
else
|
||||
throw this._val
|
||||
}else{
|
||||
if(typeof yes === 'function')
|
||||
yes(this._val)
|
||||
}
|
||||
},
|
||||
_then: function(yes, no){
|
||||
if(this._fired){
|
||||
var _this = this
|
||||
fireCallback(_this, function(){
|
||||
_this._fire(yes, no)
|
||||
})
|
||||
}else{
|
||||
this.callback.push({yes: yes, no: no})
|
||||
}
|
||||
},
|
||||
then: function(yes, no){
|
||||
yes = typeof yes === 'function' ? yes : _yes
|
||||
no = typeof no === 'function' ? no : _no
|
||||
var _this = this
|
||||
var next = new _Promise(function(resolve, reject){
|
||||
|
||||
_this._then(function(val){
|
||||
try{
|
||||
val = yes(val)
|
||||
}catch(err){
|
||||
return reject(err)
|
||||
}
|
||||
}, function(val){
|
||||
try{
|
||||
val = no(val)
|
||||
}catch(err){
|
||||
return reject(err)
|
||||
}
|
||||
resolve(val)
|
||||
})
|
||||
})
|
||||
for(var i in _this){
|
||||
if(!self[i])
|
||||
next[i] = _this[i]
|
||||
}
|
||||
return next
|
||||
},
|
||||
done: done,
|
||||
catch: fail,
|
||||
fail: fail
|
||||
}
|
||||
|
||||
_Promise.all = function(arr){
|
||||
return _some(false, arr)
|
||||
}
|
||||
|
||||
_Promise.race = function(arr){
|
||||
return _some(true, arr)
|
||||
}
|
||||
|
||||
_Promise.defer = defer
|
||||
|
||||
// -----------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
function _yes(val){
|
||||
return val
|
||||
}
|
||||
|
||||
function _no(err){
|
||||
throw err
|
||||
}
|
||||
|
||||
|
||||
function done(callback){
|
||||
return this.then(callback, _no)
|
||||
}
|
||||
|
||||
function fail(callback){
|
||||
return this.then(_yes, callback)
|
||||
}
|
||||
|
||||
function defer(){
|
||||
var obj = {}
|
||||
obj.promise = new this(function(yes, no){
|
||||
obj.resolve = yes
|
||||
obj.reject = no
|
||||
})
|
||||
return obj
|
||||
}
|
||||
|
||||
|
||||
//成功的回调
|
||||
function _resolve(obj, val){
|
||||
if(obj._state !== 'pending')
|
||||
return
|
||||
|
||||
if(val && typeof val.then === 'function'){
|
||||
var method = val instanceof _Promise ? '_then' : 'then'
|
||||
val[method](function(v){
|
||||
_transmit(obj, v, true)
|
||||
}, function(v){
|
||||
_transmit(obj, v, false)
|
||||
})
|
||||
}else{
|
||||
_transmit(obj, val, true)
|
||||
}
|
||||
}
|
||||
|
||||
//失败的回调
|
||||
function _reject(obj, val){
|
||||
if(obj._state !== 'pending')
|
||||
return
|
||||
|
||||
_transmit(obj, val, false)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 改变Promise的_fired值,并保持用户传参,触发所有回调
|
||||
function _transmit(obj, val, isResolved){
|
||||
obj._fired = true
|
||||
obj._val = val
|
||||
obj._state = isResolved ? 'fulfilled' : 'rejected'
|
||||
|
||||
fireCallback(obj, function(){
|
||||
for(var i in obj.callback){
|
||||
obj._fire(obj.callback[i].yes, obj.callback[i].no)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function fireCallback(obj, callback){
|
||||
var isAsync = false
|
||||
|
||||
if(typeof obj.async === 'boolean')
|
||||
isAsync = obj.async
|
||||
else
|
||||
isAsync = obj.async = true
|
||||
|
||||
if(isAsync)
|
||||
setTimeout(callback, 0)
|
||||
else
|
||||
callback()
|
||||
}
|
||||
|
||||
|
||||
function _some(bool, iterable){
|
||||
iterable = Array.isArray(iterable) ? iterable : []
|
||||
|
||||
var n = 0
|
||||
var res = []
|
||||
var end = false
|
||||
|
||||
return new _Promise(function(yes, no){
|
||||
if(!iterable.length)
|
||||
no(res)
|
||||
|
||||
function loop(obj, idx){
|
||||
obj.then(function(val){
|
||||
if(!end){
|
||||
res[idx] = val
|
||||
n++
|
||||
if(bool || n >= iterable.length){
|
||||
yes(bool ? val : res)
|
||||
end = true
|
||||
}
|
||||
}
|
||||
}, function(val){
|
||||
end = true
|
||||
no(val)
|
||||
})
|
||||
}
|
||||
|
||||
for(var i = 0, len = iterable.length; i < len; i++){
|
||||
loop(iterable[i], i)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
|
||||
var nativePromise = window.Promise
|
||||
if(/native code/.test(nativePromise)){
|
||||
nativePromise.prototype.done = done
|
||||
nativePromise.prototype.fail = fail
|
||||
if(!nativePromise.defer)
|
||||
nativePromise.defer = defer
|
||||
}
|
||||
|
||||
return window.Promise = nativePromise || _Promise
|
||||
|
||||
|
||||
})
|
|
@ -0,0 +1,739 @@
|
|||
/**
|
||||
* 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: '',
|
||||
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
|
||||
})
|
|
@ -0,0 +1,860 @@
|
|||
/**
|
||||
* Request组件, full版, 支持IE6+,chrome,FF
|
||||
* @authors yutent (yutent@doui.cc)
|
||||
* @date 2016-11-27 13:08:40
|
||||
*
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
var r = []
|
||||
if(!window.JSON)
|
||||
r = ['./json'];
|
||||
|
||||
define(r, function(){
|
||||
var _request = function(url, protocol){
|
||||
this.transport = true
|
||||
protocol = (protocol + '').trim().toUpperCase()
|
||||
this.xhr = Xhr()
|
||||
this.pool = {
|
||||
url: (url + '').trim(),
|
||||
type: protocol || 'GET',
|
||||
form: '',
|
||||
headers: {},
|
||||
uuid: Math.random().toString(16).substr(2)
|
||||
}
|
||||
}
|
||||
var _requestp = _request.prototype
|
||||
var toS = Object.prototype.toString
|
||||
var win = window
|
||||
var doc = win.document
|
||||
var encode = encodeURIComponent
|
||||
var decode = decodeURIComponent
|
||||
var 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
|
||||
|
||||
// ----------------- 一些兼容性预处理 --------------------
|
||||
|
||||
if(!win.FormData){
|
||||
|
||||
}
|
||||
|
||||
//IE8-
|
||||
if(String.prototype.trim){
|
||||
String.prototype.trim = function(){
|
||||
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')
|
||||
}
|
||||
}
|
||||
//IE8-
|
||||
if (!Array.prototype.forEach) {
|
||||
|
||||
Array.prototype.forEach = function(callback, thisArg) {
|
||||
|
||||
var T, k;
|
||||
|
||||
if (this === null)
|
||||
throw new TypeError('forEach is not a function of null');
|
||||
|
||||
var O = Object(this);
|
||||
var len = O.length >>> 0;
|
||||
|
||||
if (typeof callback !== "function")
|
||||
throw new TypeError('callback is not a function');
|
||||
|
||||
if (arguments.length > 1) {
|
||||
T = thisArg;
|
||||
}
|
||||
|
||||
|
||||
k = 0;
|
||||
while (k < len) {
|
||||
var kValue;
|
||||
if (k in O) {
|
||||
kValue = O[k];
|
||||
callback.call(T, kValue, k, O);
|
||||
}
|
||||
k++;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* if (!Array.prototype.filter) {
|
||||
Array.prototype.filter = function(fun) {
|
||||
'use strict';
|
||||
|
||||
if (this === void 0 || this === null) {
|
||||
throw new TypeError('filter is not a function of null');
|
||||
}
|
||||
|
||||
var t = Object(this);
|
||||
var len = t.length >>> 0;
|
||||
if (typeof fun !== 'function') {
|
||||
throw new TypeError('callback is not a function');
|
||||
}
|
||||
|
||||
var res = [];
|
||||
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (i in t) {
|
||||
var val = t[i];
|
||||
if (fun.call(thisArg, val, i, t)) {
|
||||
res.push(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
}*/
|
||||
// IE8-
|
||||
if(!Array.isArray){
|
||||
Array.isArray = function(arg) {
|
||||
return toS.call(arg) === '[object Array]';
|
||||
};
|
||||
}
|
||||
|
||||
var IE = (function(){
|
||||
if(window.VBArray){
|
||||
var mode = document.documentMode
|
||||
return mode ? mode : (window.XMLHttpRequest ? 7 : 6)
|
||||
}
|
||||
return 0
|
||||
})();
|
||||
|
||||
win.Xhr = (function(){
|
||||
var obj = [
|
||||
"XMLHttpRequest",
|
||||
"ActiveXObject('MSXML2.XMLHTTP.6.0')",
|
||||
"ActiveXObject('MSXML2.XMLHTTP.3.0')",
|
||||
"ActiveXObject('MSXML2.XMLHTTP')",
|
||||
"ActiveXObject('Microsoft.XMLHTTP')"
|
||||
]
|
||||
//IE7- 本地打开文件不能使用原生XMLHttpRequest
|
||||
obj[0] = (IE < 8 && IE !== 0 && isLocal) ? '!' : obj[0]
|
||||
|
||||
for(var i = 0,a; a = obj[i++];){
|
||||
try{
|
||||
if(eval('new ' + a)){
|
||||
return new Function('return new ' + a)
|
||||
}
|
||||
}catch(e){}
|
||||
}
|
||||
|
||||
})();
|
||||
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{
|
||||
var mode = doc.documentMode
|
||||
//标准浏览器
|
||||
if(win.DOMParser && (!mode || mode > 8)){
|
||||
tmp = new DOMParser()
|
||||
xml = tmp.parseFromString(data, 'text/xml')
|
||||
}else{// IE了
|
||||
xml = new ActiveXObject('Microsoft.XMLDOM')
|
||||
xml.async = 'false'
|
||||
xml.loadXML(data)
|
||||
}
|
||||
}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(){
|
||||
return window[this.jsonpCallback]
|
||||
}
|
||||
}
|
||||
var requestExtend = {
|
||||
formData: function(){
|
||||
|
||||
//现代浏览器直接切换为FormData方式
|
||||
if(win.FormData){
|
||||
if(this.pool.form){
|
||||
console.log(this.pool.form.elements)
|
||||
var data = F.parseForm(this.pool.form)
|
||||
console.log(data)
|
||||
F.merge(this.pool.data, data)
|
||||
}
|
||||
|
||||
var form = new FormData()
|
||||
for(var i in this.pool.data){
|
||||
var el = this.pool.data[i]
|
||||
if(Array.isArray(el)){
|
||||
el.forEach(function(it){
|
||||
form.append(i + '[]', it)
|
||||
})
|
||||
}else{
|
||||
form.append(i, this.pool.data[i])
|
||||
}
|
||||
}
|
||||
return form
|
||||
// IE8- 使用iframe
|
||||
}else{
|
||||
this.transport = this.mkIframe(this.pool.uuid)
|
||||
this.pool.form = this.mkForm(this.pool.form)
|
||||
this.pool.field = []
|
||||
for(var i in this.pool.data){
|
||||
|
||||
var val = this.pool.data[i]
|
||||
if(Array.isArray(val)){
|
||||
for(var j = 0,v; v = val[j++];){
|
||||
var el = doc.createElement('input')
|
||||
el.type = 'hidden'
|
||||
el.name = i + '[]'
|
||||
el.value = v
|
||||
this.pool.field.push(el)
|
||||
this.pool.form.appendChild(el)
|
||||
}
|
||||
}else{
|
||||
var el = doc.createElement('input')
|
||||
el.type = 'hidden'
|
||||
el.name = i
|
||||
el.value = val
|
||||
this.pool.field.push(el)
|
||||
this.pool.form.appendChild(el)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mkIframe: function(id){
|
||||
var iframe = F.parseHTML('<iframe id="' + id + '" name="' + id + '" style="position: ' + (IE === 6 ? 'absolute' : 'fixed') + ';top: -9999px;left: 0"></iframe>').firstChild
|
||||
return (doc.body || doc.documentElement).insertBefore(iframe, null)
|
||||
},
|
||||
mkForm: function(form){
|
||||
if(!form)
|
||||
form = doc.createElement('form')
|
||||
|
||||
form.target = this.pool.uuid
|
||||
form.action = this.pool.url
|
||||
form.method = 'POST'
|
||||
form.enctype = 'multipart/form-data'
|
||||
|
||||
return form
|
||||
},
|
||||
dispatch: function(self, status){
|
||||
var _this = this
|
||||
|
||||
if(!this.transport)
|
||||
return
|
||||
|
||||
//状态为4,既已成功, 则清除超时
|
||||
clearTimeout(_this.timeoutID)
|
||||
|
||||
if(status === 4)
|
||||
self.status = status
|
||||
|
||||
//成功的回调
|
||||
var isSucc = (self.status >= 200 && self.status < 300) || self.status === 304
|
||||
|
||||
var result = {
|
||||
response: {
|
||||
url: self.responseURL || self.URL,
|
||||
headers: {'content-type': ''}
|
||||
},
|
||||
request: {
|
||||
url: self.responseURL || self.URL,
|
||||
headers: _this.pool.headers
|
||||
},
|
||||
status: self.status,
|
||||
statusText: self.statusText || 'OK',
|
||||
text: '',
|
||||
body: '',
|
||||
error: null
|
||||
}
|
||||
if(typeof _this.transport !== 'object'){
|
||||
delete _this.transport
|
||||
delete _this.pool
|
||||
}
|
||||
// 非iframe方式
|
||||
if(!status){
|
||||
var headers = self.getAllResponseHeaders()
|
||||
headers = headers.split('\n')
|
||||
headers.forEach(function(it, i){
|
||||
it = it.trim()
|
||||
if(it){
|
||||
it = it.split(':')
|
||||
result.response.headers[it.shift().toLowerCase()] = it.join(':').trim()
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
if(isSucc){
|
||||
|
||||
if(status === 204){
|
||||
result.statusText = 'no content'
|
||||
}else if(status === 304){
|
||||
result.statusText = 'not modified'
|
||||
}else{
|
||||
//处理返回的数据
|
||||
|
||||
var dataType = result.response.headers['content-type'].match(/json|xml|script|html/i) || ['text']
|
||||
|
||||
dataType = dataType[0].toLowerCase()
|
||||
|
||||
var responseTXT = self.responseText || ''
|
||||
var responseXML = self.responseXML || ''
|
||||
try{
|
||||
result.text = responseTXT || responseXML
|
||||
result.body = requestConvert[dataType](responseTXT, responseXML)
|
||||
}catch(e){
|
||||
isSucc = false
|
||||
result.error = e
|
||||
result.statusText = 'parse error'
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(status){
|
||||
result.status = 200
|
||||
|
||||
if(self.body){
|
||||
result.text = self.body.innerHTML
|
||||
result.body = result.text
|
||||
var child = self.body.firstChild
|
||||
if(child && child.nodeName.toUpperCase() === 'PRE'){
|
||||
result.text = child.innerHTML
|
||||
result.body = requestConvert.json(result.text)
|
||||
}
|
||||
}else{
|
||||
result.text = result.body = self
|
||||
}
|
||||
|
||||
//删除iframe
|
||||
_this.transport.parentNode.removeChild(_this.transport)
|
||||
//还原表单, 避免参数重复提交
|
||||
if(_this.pool.field && _this.pool.field.length){
|
||||
_this.pool.form.target = ''
|
||||
_this.pool.form.action = ''
|
||||
for(var i = 0,el; el = _this.pool.field[i++];){
|
||||
_this.pool.form.removeChild(el)
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
result.status = result.status || 504
|
||||
result.statusText = result.statusText || 'Connected timeout'
|
||||
result.error = F.merge(new Error(result.statusText), {status: result.status})
|
||||
}
|
||||
}
|
||||
|
||||
_this.callback(result.error, result)
|
||||
delete _this.transport
|
||||
delete _this.pool
|
||||
delete _this.xhr
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 设置表单类型, 支持2种, form/json
|
||||
_requestp.type = function(t){
|
||||
if(this.pool.formType === 'form-data')
|
||||
return this
|
||||
|
||||
this.pool.formType = t || 'form'
|
||||
if(t === 'form' || this.pool.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.pool.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.pool.headers[k]
|
||||
else
|
||||
this.pool.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.pool.data && (typeof this.pool.data === 'string'))
|
||||
throw new Error('param can not be string and object at the same time')
|
||||
if(!this.pool.data)
|
||||
this.pool.data = {}
|
||||
|
||||
F.merge(this.pool.data, k)
|
||||
}else{
|
||||
if(typeof k === 'string'){
|
||||
if(arguments.length === 1){
|
||||
if(this.pool.data)
|
||||
throw new Error('invalid param in function send')
|
||||
|
||||
this.pool.data = k
|
||||
}else{
|
||||
if(this.pool.data && (typeof this.pool.data === 'string'))
|
||||
throw new Error('param can not be string and object at the same time')
|
||||
|
||||
if(!this.pool.data)
|
||||
this.pool.data = {}
|
||||
|
||||
this.pool.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.pool.formType = 'form-data'
|
||||
if(!this.pool.data || (this.pool.data && typeof this.pool.data !== 'object'))
|
||||
this.pool.data = {}
|
||||
|
||||
if(arguments.length === 1 && typeof k === 'object'){
|
||||
F.merge(this.pool.data, k)
|
||||
}else if(arguments.length === 2){
|
||||
this.pool.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.pool.type === 'GET')
|
||||
this.pool.cache = !!t
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
//取消网络请求
|
||||
_requestp.abort = function(){
|
||||
delete this.transport
|
||||
if(!this.pool.form)
|
||||
this.xhr.abort()
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
//超时设置, 单位毫秒
|
||||
_requestp.timeout = function(time){
|
||||
if(typeof time !== 'number' || time < 1)
|
||||
return this
|
||||
|
||||
this.pool.timeout = time
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
_requestp.form = function(form){
|
||||
if(typeof form === 'object' && form.nodeName === 'FORM'){
|
||||
this.pool.type = 'POST'
|
||||
this.pool.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.pool.url)
|
||||
throw new Error('Invalid request url')
|
||||
|
||||
F.merge(this, requestExtend)
|
||||
|
||||
this.callback = callback || noop
|
||||
|
||||
// 1. url规范化
|
||||
this.pool.url = this.pool.url.replace(/#.*$/, '').replace(/^\/\//, location.protocol + '//')
|
||||
|
||||
// 2. data转字符串
|
||||
this.pool.param = F.param(this.pool.data)
|
||||
|
||||
// 3. 处理跨域
|
||||
if(typeof this.pool.crossDomain !== 'boolean'){
|
||||
var anchor = doc.createElement('a')
|
||||
try{
|
||||
anchor.href = this.pool.url
|
||||
// IE7及以下浏览器 '1'[0]的结果是 undefined
|
||||
// IE7下需要获取绝对路径
|
||||
var absUrl = !'1'[0] ? anchor.getAttribute('href', 4) : anchor.href
|
||||
anchor.href = absUrl
|
||||
this.pool.crossDomain = (originAnchor.protocol !== anchor.protocol) || (originAnchor.host !== anchor.host)
|
||||
}catch(e){
|
||||
this.pool.crossDomain = true
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 设置Content-Type类型, 默认x-www-form-urlencoded
|
||||
if(!this.pool.formType)
|
||||
this.type('form')
|
||||
|
||||
// 5.处理GET请求
|
||||
this.pool.hasContent = this.pool.type !== 'GET' //是否为post请求
|
||||
if(!this.pool.hasContent){
|
||||
|
||||
//GET请求直接把参数拼接到url上
|
||||
if(this.pool.param){
|
||||
this.pool.url += (/\?/.test(this.pool.url) ? '&' : '?') + this.pool.param
|
||||
}
|
||||
//加随机值,避免缓存
|
||||
if(this.pool.cache === false)
|
||||
this.pool.url += (/\?/.test(this.pool.url) ? '&' : '?') + '_=' + Math.random()
|
||||
}else{
|
||||
if(this.pool.formType === 'form-data'){
|
||||
delete this.pool.headers['content-type']
|
||||
this.pool.param = this.formData()
|
||||
|
||||
}else if(this.pool.formType !== 'form'){
|
||||
this.pool.param = JSON.stringify(this.pool.data)
|
||||
}
|
||||
}
|
||||
|
||||
// transport不恒为 true, 则说明是走iframe路线的
|
||||
if(this.transport !== true){
|
||||
this.transport.onload = function(ev){
|
||||
_this.dispatch(this.contentWindow.document, 4)
|
||||
}
|
||||
this.pool.form.submit()
|
||||
}else{
|
||||
this.xhr.onreadystatechange = function(statusTxt){
|
||||
|
||||
if(this.readyState !== 4)
|
||||
return
|
||||
|
||||
_this.dispatch(this)
|
||||
}
|
||||
|
||||
|
||||
// 6. 初始化xhr提交
|
||||
this.xhr.open(this.pool.type, this.pool.url, true)
|
||||
|
||||
// 7. 设置头信息
|
||||
for(var i in this.pool.headers){
|
||||
if(this.pool.headers[i])
|
||||
this.xhr.setRequestHeader(i, this.pool.headers[i])
|
||||
}
|
||||
|
||||
// 8. 发起网络请求
|
||||
this.xhr.send(this.pool.param)
|
||||
|
||||
|
||||
}
|
||||
|
||||
//超时处理
|
||||
//IE8- 不支持timeout属性的设置,
|
||||
if(this.pool.timeout && this.pool.timeout > 0){
|
||||
this.timeoutID = setTimeout(function(){
|
||||
_this.abort()
|
||||
}, this.pool.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')
|
||||
},
|
||||
version: '1.0.0',
|
||||
release: 'request full version/1.0.0'
|
||||
}
|
||||
}
|
||||
|
||||
return request
|
||||
})
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,163 @@
|
|||
define(['yua'], function(){
|
||||
|
||||
function Router(){
|
||||
this.table = {get: []};
|
||||
this.errorFn = null;
|
||||
this.history = null;
|
||||
this.hash = '';
|
||||
this.started = false;
|
||||
this.init = {};
|
||||
}
|
||||
|
||||
var defaultOptions = {
|
||||
prefix: /^(#!|#)[\/]?/, //hash前缀正则
|
||||
historyOpen: true, //是否开启hash历史
|
||||
allowReload: true //连续点击同一个链接是否重新加载
|
||||
};
|
||||
var isMouseUp = true;
|
||||
|
||||
var ruleRegExp = /(:id)|(\{id\})|(\{id:([A-z\d\,\[\]\{\}\-\+\*\?\!:\^\$]*)\})/g;
|
||||
|
||||
Router.prototype = {
|
||||
error: function(callback){
|
||||
this.errorFn = callback;
|
||||
},
|
||||
config: function(opts){
|
||||
if(this.started)
|
||||
return console.error('Router config has been set');
|
||||
|
||||
this.started = true;
|
||||
if(!opts.allowReload)
|
||||
opts.historyOpen = true;
|
||||
this.init = yua.mix({}, defaultOptions, opts);
|
||||
},
|
||||
_getRegExp: function(rule, opts){
|
||||
var re = rule.replace(ruleRegExp, function(m, p1, p2, p3, p4){
|
||||
var w = '([\\w.-]';
|
||||
if(p1 || p2){
|
||||
return w + '+)';
|
||||
}else{
|
||||
if(!/^\{[\d\,]+\}$/.test(p4)){
|
||||
w = '(';
|
||||
}
|
||||
return w + p4 + ')';
|
||||
}
|
||||
})
|
||||
re = re.replace(/(([^\\])([\/]+))/g, '$2\\/').replace(/(([^\\])([\.]+))/g, '$2\\.').replace(/(([^\\])([\-]+))/g, '$2\\-').replace(/(\(.*)(\\[\-]+)(.*\))/g, '$1-$3');
|
||||
re = '^' + re + '$';
|
||||
opts.regexp = new RegExp(re)
|
||||
return opts;
|
||||
},
|
||||
_add: function(method, rule, callback){
|
||||
if(!this.started)
|
||||
this.config({});
|
||||
|
||||
var table = this.table[method.toLowerCase()];
|
||||
if (rule.charAt(0) !== "/") {
|
||||
console.error('char "/" must be in front of router rule');
|
||||
return;
|
||||
}
|
||||
rule = rule.replace(/^[\/]+|[\/]+$|\s+/g, '');
|
||||
var opts = {};
|
||||
opts.rule = rule;
|
||||
opts.callback = callback;
|
||||
yua.Array.ensure(table, this._getRegExp(rule, opts));
|
||||
},
|
||||
_route: function(method, hash){
|
||||
var hash = hash.trim();
|
||||
var table = this.table[method];
|
||||
var init = this.init;
|
||||
|
||||
if(!init.allowReload && hash === this.history)
|
||||
return;
|
||||
|
||||
if(init.historyOpen){
|
||||
this.history = hash;
|
||||
if(yua.ls)
|
||||
yua.ls('lastHash', hash);
|
||||
}
|
||||
|
||||
for(var i = 0, obj; obj = table[i++];){
|
||||
var args = hash.match(obj.regexp);
|
||||
if(args){
|
||||
args.shift();
|
||||
return obj.callback.apply(obj, args)
|
||||
}
|
||||
}
|
||||
this.errorFn && this.errorFn(hash);
|
||||
},
|
||||
on: function(rule, callback){
|
||||
this._add('get', rule, callback);
|
||||
}
|
||||
}
|
||||
|
||||
yua.bind(window, 'load', function(){
|
||||
if(!yua.router.started)
|
||||
return;
|
||||
var prefix = yua.router.init.prefix;
|
||||
var hash = location.hash;
|
||||
hash = hash.replace(prefix, "").trim();
|
||||
yua.router._route('get', hash);
|
||||
});
|
||||
|
||||
|
||||
if('onhashchange' in window){
|
||||
window.addEventListener('hashchange', function(event){
|
||||
if(!isMouseUp)
|
||||
return;
|
||||
var prefix = yua.router.init.prefix;
|
||||
var hash = location.hash.replace(prefix, "").trim();
|
||||
yua.router._route('get', hash)
|
||||
})
|
||||
}
|
||||
|
||||
//劫持页面上所有点击事件,如果事件源来自链接或其内部,
|
||||
//并且它不会跳出本页,并且以"#/"或"#!/"开头,那么触发updateLocation方法
|
||||
yua.bind(document, "mousedown", function(event){
|
||||
var defaultPrevented = "defaultPrevented" in event ? event['defaultPrevented'] : event.returnValue === false
|
||||
if (defaultPrevented || event.ctrlKey || event.metaKey || event.which === 2)
|
||||
return
|
||||
var target = event.target
|
||||
while (target.nodeName !== "A") {
|
||||
target = target.parentNode
|
||||
if (!target || target.tagName === "BODY") {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (targetIsThisWindow(target.target)){
|
||||
if(!yua.router.started)
|
||||
return;
|
||||
var href = target.getAttribute("href") || target.getAttribute("xlink:href"),
|
||||
prefix = yua.router.init.prefix;
|
||||
|
||||
if (href === null || !prefix.test(href))
|
||||
return
|
||||
|
||||
yua.router.hash = href.replace(prefix, "").trim();
|
||||
event.preventDefault();
|
||||
location.hash = href;
|
||||
isMouseUp = false;
|
||||
}
|
||||
})
|
||||
|
||||
yua.bind(document, "mouseup", function(){
|
||||
if(!isMouseUp){
|
||||
yua.router._route('get', yua.router.hash);
|
||||
isMouseUp = true;
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
//判定A标签的target属性是否指向自身
|
||||
//thanks https://github.com/quirkey/sammy/blob/master/lib/sammy.js#L219
|
||||
function targetIsThisWindow(targetWindow) {
|
||||
if (!targetWindow || targetWindow === window.name || targetWindow === '_self' || (targetWindow === 'top' && window == window.top)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return yua.router = new Router;
|
||||
})
|
|
@ -0,0 +1 @@
|
|||
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});
|
|
@ -0,0 +1,62 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<title>Examples</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<link href="../css/base.min.css" rel="stylesheet">
|
||||
<style type="text/css">
|
||||
.preview {width:500px;height:300px;margin:auto;border:1px solid #ddd;}
|
||||
</style>
|
||||
</head>
|
||||
<body ms-controller="test">
|
||||
|
||||
<div class="preview">
|
||||
<img ms-attr-src="preview">
|
||||
</div>
|
||||
|
||||
<input type="file" ms-duplex="file" id="file">
|
||||
|
||||
<a href="javascript:;" class="submit">提交</a>
|
||||
|
||||
|
||||
<script src="../avalon.modern.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
|
||||
require(['uploader/uploader', 'ajax/ajax.min'], function(Up){
|
||||
|
||||
var uploader = new Up()
|
||||
|
||||
uploader.setUrl('http://up.qbox.me')
|
||||
.onProgress(function(obj){
|
||||
console.log(obj.speed, obj.progress, obj.loaded, obj.time)
|
||||
})
|
||||
.onEnd(function(res){
|
||||
console.info(res)
|
||||
})
|
||||
|
||||
var submit = document.querySelector('.submit')
|
||||
var file = document.querySelector('#file')
|
||||
|
||||
submit.onclick = function(){
|
||||
// console.log(file.files[0])
|
||||
avalon.get('/upload.php?image=' + file.files[0].name, '', function(txt){
|
||||
uploader.init()
|
||||
.setField('file', file.files[0])
|
||||
.setField('token', txt)
|
||||
.setField('key', 'avatar/dsfghj')
|
||||
.start()
|
||||
}, 'text')
|
||||
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* Uploader 无刷新上传文件(next版)
|
||||
* 只支持chrome/firefox/IE10+/opera12+
|
||||
* @authors yutent (yutent@doui.cc)
|
||||
* @date 2016-09-05 19:33:23
|
||||
*
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
define(function(){
|
||||
|
||||
/* var isIE = !!window.VBArray
|
||||
|
||||
function IEVersion(){
|
||||
if(document.documentMode)
|
||||
return document.documentMode
|
||||
|
||||
return window.XMLHttpRequest ? 7 : 6
|
||||
}*/
|
||||
|
||||
var Uploader = function(){
|
||||
this.init()
|
||||
}
|
||||
|
||||
Uploader.prototype = {
|
||||
init: function(){
|
||||
this.xhr = new XMLHttpRequest()
|
||||
this.form = new FormData()
|
||||
this.field = {}
|
||||
this.header = {}
|
||||
return this
|
||||
},
|
||||
setUrl: function(url){
|
||||
if(!url || typeof url !== 'string')
|
||||
return console.error('url不能为空且必须是字符串')
|
||||
|
||||
this.url = url
|
||||
return this
|
||||
},
|
||||
setField: function(key, val){
|
||||
if(typeof key === 'object'){
|
||||
for(var i in key){
|
||||
this.field[i] = key[i]
|
||||
}
|
||||
}else{
|
||||
this.field[key] = val
|
||||
}
|
||||
return this
|
||||
},
|
||||
setHeader: function(key, val){
|
||||
if(typeof key === 'object'){
|
||||
for(var i in key){
|
||||
this.header[i] = key[i]
|
||||
}
|
||||
}else{
|
||||
this.header[key] = val
|
||||
}
|
||||
return this
|
||||
},
|
||||
start: function(){
|
||||
var _this = this
|
||||
if(!this.url)
|
||||
return console.error('请先设置url')
|
||||
|
||||
this.xhr.open('POST', this.url, true)
|
||||
|
||||
for(var i in this.field){
|
||||
this.form.append(i, this.field[i])
|
||||
}
|
||||
|
||||
var startTime = Date.now()
|
||||
|
||||
this.xhr.upload.addEventListener('progress', function(evt){
|
||||
|
||||
if(evt.lengthComputable && _this.progress){
|
||||
var now = Date.now()
|
||||
var upSize = (evt.loaded * 1000) / 1024
|
||||
var res = {loaded: evt.loaded, time: now - startTime}
|
||||
res.speed = upSize / res.time
|
||||
|
||||
if(res.speed < 10){
|
||||
res.speed = Math.floor(res.speed * 1024) + ' B/s'
|
||||
}else{
|
||||
res.speed = res.speed.toFixed(2) + ' KB/s'
|
||||
}
|
||||
|
||||
res.progress = Math.round(evt.loaded * 100 / evt.total)
|
||||
_this.progress(res)
|
||||
}
|
||||
|
||||
}, false)
|
||||
|
||||
this.xhr.onreadystatechange = function(){
|
||||
if(_this.xhr.readyState === 4 &&
|
||||
_this.xhr.status === 200 &&
|
||||
_this.xhr.responseText !== ''){
|
||||
var res = _this.xhr.responseText
|
||||
try{
|
||||
res = JSON.parse(res)
|
||||
}catch(err){}
|
||||
_this.end && _this.end(res)
|
||||
}else{
|
||||
if(_this.xhr.status !== 200 && _this.xhr.responseText)
|
||||
_this.error && _this.error(_this.xhr.responseText)
|
||||
}
|
||||
}
|
||||
|
||||
this.xhr.send(this.form)
|
||||
|
||||
},
|
||||
onProgress: function(fn){
|
||||
this.progress = fn
|
||||
return this
|
||||
},
|
||||
onEnd: function(fn){
|
||||
this.end = fn
|
||||
return this
|
||||
},
|
||||
onError: function(fn){
|
||||
this.error = fn
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if(!window.Uploader)
|
||||
window.Uploader = Uploader
|
||||
|
||||
|
||||
return Uploader
|
||||
|
||||
})
|
|
@ -0,0 +1,544 @@
|
|||
var ua = navigator.userAgent.toLowerCase()
|
||||
//http://stackoverflow.com/questions/9038625/detect-if-device-is-ios
|
||||
function iOSversion() {
|
||||
//https://developer.apple.com/library/prerelease/mac/releasenotes/General/WhatsNewInSafari/Articles/Safari_9.html
|
||||
//http://mp.weixin.qq.com/s?__biz=MzA3MDQ4MzQzMg==&mid=256900619&idx=1&sn=b29f84cff0b8d7b9742e5d8b3cd8f218&scene=1&srcid=1009F9l4gh9nZ7rcQJEhmf7Q#rd
|
||||
if (/iPad|iPhone|iPod/i.test(ua) && !window.MSStream) {
|
||||
if ("backdropFilter" in document.documentElement.style) {
|
||||
return 9
|
||||
}
|
||||
if (!!window.indexedDB) {
|
||||
return 8
|
||||
}
|
||||
if (!!window.SpeechSynthesisUtterance) {
|
||||
return 7
|
||||
}
|
||||
if (!!window.webkitAudioContext) {
|
||||
return 6
|
||||
}
|
||||
if (!!window.matchMedia) {
|
||||
return 5
|
||||
}
|
||||
if (!!window.history && 'pushState' in window.history) {
|
||||
return 4
|
||||
}
|
||||
return 3
|
||||
}
|
||||
return NaN
|
||||
}
|
||||
|
||||
var deviceIsAndroid = ua.indexOf('android') > 0
|
||||
var deviceIsIOS = iOSversion()
|
||||
|
||||
var Recognizer = yua.gestureHooks = {
|
||||
pointers: {},
|
||||
//以AOP切入touchstart, touchmove, touchend, touchcancel回调
|
||||
start: function (event, callback) {
|
||||
|
||||
//touches是当前屏幕上所有触摸点的列表;
|
||||
//targetTouches是当前对象上所有触摸点的列表;
|
||||
//changedTouches是涉及当前事件的触摸点的列表。
|
||||
for (var i = 0; i < event.changedTouches.length; i++) {
|
||||
var touch = event.changedTouches[i],
|
||||
id = touch.identifier,
|
||||
pointer = {
|
||||
startTouch: mixLocations({}, touch),
|
||||
startTime: Date.now(),
|
||||
status: 'tapping',
|
||||
element: event.target,
|
||||
pressingHandler: Recognizer.pointers[id] && Recognizer.pointers[id].pressingHandler
|
||||
}
|
||||
Recognizer.pointers[id] = pointer;
|
||||
callback(pointer, touch)
|
||||
|
||||
}
|
||||
},
|
||||
move: function (event, callback) {
|
||||
for (var i = 0; i < event.changedTouches.length; i++) {
|
||||
var touch = event.changedTouches[i]
|
||||
var pointer = Recognizer.pointers[touch.identifier]
|
||||
if (!pointer) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!("lastTouch" in pointer)) {
|
||||
pointer.lastTouch = pointer.startTouch
|
||||
pointer.lastTime = pointer.startTime
|
||||
pointer.deltaX = pointer.deltaY = pointer.duration = pointer.distance = 0
|
||||
}
|
||||
|
||||
var time = Date.now() - pointer.lastTime
|
||||
|
||||
if (time > 0) {
|
||||
|
||||
var RECORD_DURATION = 70
|
||||
if (time > RECORD_DURATION) {
|
||||
time = RECORD_DURATION
|
||||
}
|
||||
if (pointer.duration + time > RECORD_DURATION) {
|
||||
pointer.duration = RECORD_DURATION - time
|
||||
}
|
||||
|
||||
pointer.duration += time;
|
||||
pointer.lastTouch = mixLocations({}, touch)
|
||||
|
||||
pointer.lastTime = Date.now()
|
||||
|
||||
pointer.deltaX = touch.clientX - pointer.startTouch.clientX
|
||||
pointer.deltaY = touch.clientY - pointer.startTouch.clientY
|
||||
var x = pointer.deltaX * pointer.deltaX
|
||||
var y = pointer.deltaY * pointer.deltaY
|
||||
pointer.distance = Math.sqrt(x + y)
|
||||
pointer.isVertical = x < y
|
||||
|
||||
callback(pointer, touch)
|
||||
}
|
||||
}
|
||||
},
|
||||
end: function (event, callback) {
|
||||
for (var i = 0; i < event.changedTouches.length; i++) {
|
||||
var touch = event.changedTouches[i],
|
||||
id = touch.identifier,
|
||||
pointer = Recognizer.pointers[id]
|
||||
|
||||
if (!pointer)
|
||||
continue
|
||||
|
||||
callback(pointer, touch)
|
||||
|
||||
delete Recognizer.pointers[id]
|
||||
}
|
||||
},
|
||||
//人工触发合成事件
|
||||
fire: function (elem, type, props) {
|
||||
if (elem) {
|
||||
var event = document.createEvent('Events')
|
||||
event.initEvent(type, true, true)
|
||||
yua.mix(event, props)
|
||||
elem.dispatchEvent(event)
|
||||
}
|
||||
},
|
||||
//添加各种识别器
|
||||
add: function (name, recognizer) {
|
||||
function move(event) {
|
||||
recognizer.touchmove(event)
|
||||
}
|
||||
|
||||
function end(event) {
|
||||
recognizer.touchend(event)
|
||||
|
||||
document.removeEventListener('touchmove', move)
|
||||
|
||||
document.removeEventListener('touchend', end)
|
||||
|
||||
document.removeEventListener('touchcancel', cancel)
|
||||
|
||||
}
|
||||
|
||||
function cancel(event) {
|
||||
recognizer.touchcancel(event)
|
||||
|
||||
document.removeEventListener('touchmove', move)
|
||||
|
||||
document.removeEventListener('touchend', end)
|
||||
|
||||
document.removeEventListener('touchcancel', cancel)
|
||||
|
||||
}
|
||||
|
||||
recognizer.events.forEach(function (eventName) {
|
||||
yua.eventHooks[eventName] = {
|
||||
fix: function (el, fn) {
|
||||
if (!el['touch-' + name]) {
|
||||
el['touch-' + name] = '1'
|
||||
el.addEventListener('touchstart', function (event) {
|
||||
recognizer.touchstart(event)
|
||||
|
||||
document.addEventListener('touchmove', move)
|
||||
|
||||
document.addEventListener('touchend', end)
|
||||
|
||||
document.addEventListener('touchcancel', cancel)
|
||||
|
||||
})
|
||||
}
|
||||
return fn
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var locations = ['screenX', 'screenY', 'clientX', 'clientY', 'pageX', 'pageY']
|
||||
|
||||
// 复制 touch 对象上的有用属性到固定对象上
|
||||
function mixLocations(target, source) {
|
||||
if (source) {
|
||||
locations.forEach(function (key) {
|
||||
target[key] = source[key]
|
||||
})
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
var supportPointer = !!navigator.pointerEnabled || !!navigator.msPointerEnabled
|
||||
|
||||
if (supportPointer) { // 支持pointer的设备可用样式来取消click事件的300毫秒延迟
|
||||
root.style.msTouchAction = root.style.touchAction = 'none'
|
||||
}
|
||||
var tapRecognizer = {
|
||||
events: ['tap'],
|
||||
touchBoundary: 10,
|
||||
tapDelay: 200,
|
||||
needClick: function(target) {
|
||||
//判定是否使用原生的点击事件, 否则使用sendClick方法手动触发一个人工的点击事件
|
||||
switch (target.nodeName.toLowerCase()) {
|
||||
case 'button':
|
||||
case 'select':
|
||||
case 'textarea':
|
||||
if (target.disabled) {
|
||||
return true
|
||||
}
|
||||
|
||||
break;
|
||||
case 'input':
|
||||
// IOS6 pad 上选择文件,如果不是原生的click,弹出的选择界面尺寸错误
|
||||
if ((deviceIsIOS && target.type === 'file') || target.disabled) {
|
||||
return true
|
||||
}
|
||||
|
||||
break;
|
||||
case 'label':
|
||||
case 'iframe':
|
||||
case 'video':
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
needFocus: function(target) {
|
||||
switch (target.nodeName.toLowerCase()) {
|
||||
case 'textarea':
|
||||
case 'select': //实测android下select也需要
|
||||
return true;
|
||||
case 'input':
|
||||
switch (target.type) {
|
||||
case 'button':
|
||||
case 'checkbox':
|
||||
case 'file':
|
||||
case 'image':
|
||||
case 'radio':
|
||||
case 'submit':
|
||||
return false
|
||||
}
|
||||
//如果是只读或disabled状态,就无须获得焦点了
|
||||
return !target.disabled && !target.readOnly
|
||||
default:
|
||||
return false
|
||||
}
|
||||
},
|
||||
focus: function(targetElement) {
|
||||
var length;
|
||||
//在iOS7下, 对一些新表单元素(如date, datetime, time, month)调用focus方法会抛错,
|
||||
//幸好的是,我们可以改用setSelectionRange获取焦点, 将光标挪到文字的最后
|
||||
var type = targetElement.type
|
||||
if (deviceIsIOS && targetElement.setSelectionRange &&
|
||||
type.indexOf('date') !== 0 && type !== 'time' && type !== 'month') {
|
||||
length = targetElement.value.length
|
||||
targetElement.setSelectionRange(length, length)
|
||||
} else {
|
||||
targetElement.focus()
|
||||
}
|
||||
},
|
||||
findControl: function(labelElement) {
|
||||
// 获取label元素所对应的表单元素
|
||||
// 可以能过control属性, getElementById, 或用querySelector直接找其内部第一表单元素实现
|
||||
if (labelElement.control !== undefined) {
|
||||
return labelElement.control
|
||||
}
|
||||
|
||||
if (labelElement.htmlFor) {
|
||||
return document.getElementById(labelElement.htmlFor)
|
||||
}
|
||||
|
||||
return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea')
|
||||
},
|
||||
fixTarget: function(target) {
|
||||
if (target.nodeType === 3) {
|
||||
return target.parentNode
|
||||
}
|
||||
if (window.SVGElementInstance && (target instanceof SVGElementInstance)) {
|
||||
return target.correspondingUseElement;
|
||||
}
|
||||
|
||||
return target
|
||||
},
|
||||
updateScrollParent: function(targetElement) {
|
||||
//如果事件源元素位于某一个有滚动条的祖父元素中,那么保持其scrollParent与scrollTop值
|
||||
var scrollParent = targetElement.tapScrollParent
|
||||
|
||||
if (!scrollParent || !scrollParent.contains(targetElement)) {
|
||||
var parentElement = targetElement
|
||||
do {
|
||||
if (parentElement.scrollHeight > parentElement.offsetHeight) {
|
||||
scrollParent = parentElement
|
||||
targetElement.tapScrollParent = parentElement
|
||||
break
|
||||
}
|
||||
|
||||
parentElement = parentElement.parentElement
|
||||
} while (parentElement)
|
||||
}
|
||||
|
||||
if (scrollParent) {
|
||||
scrollParent.lastScrollTop = scrollParent.scrollTop
|
||||
}
|
||||
},
|
||||
touchHasMoved: function(event) {
|
||||
//判定是否发生移动,其阀值是10px
|
||||
var touch = event.changedTouches[0],
|
||||
boundary = tapRecognizer.touchBoundary
|
||||
return Math.abs(touch.pageX - tapRecognizer.pageX) > boundary ||
|
||||
Math.abs(touch.pageY - tapRecognizer.pageY) > boundary
|
||||
|
||||
},
|
||||
|
||||
findType: function(targetElement) {
|
||||
// 安卓chrome浏览器上,模拟的 click 事件不能让 select 打开,故使用 mousedown 事件
|
||||
return deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select' ?
|
||||
'mousedown' : 'click'
|
||||
},
|
||||
sendClick: function(targetElement, event) {
|
||||
// 在click之前触发tap事件
|
||||
Recognizer.fire(targetElement, 'tap', {
|
||||
touchEvent: event
|
||||
})
|
||||
var clickEvent, touch
|
||||
//某些安卓设备必须先移除焦点,之后模拟的click事件才能让新元素获取焦点
|
||||
if (document.activeElement && document.activeElement !== targetElement) {
|
||||
document.activeElement.blur()
|
||||
}
|
||||
|
||||
touch = event.changedTouches[0]
|
||||
// 手动触发点击事件,此时必须使用document.createEvent('MouseEvents')来创建事件
|
||||
// 及使用initMouseEvent来初始化它
|
||||
clickEvent = document.createEvent('MouseEvents')
|
||||
clickEvent.initMouseEvent(tapRecognizer.findType(targetElement), true, true, window, 1, touch.screenX,
|
||||
touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null)
|
||||
clickEvent.touchEvent = event
|
||||
targetElement.dispatchEvent(clickEvent)
|
||||
},
|
||||
touchstart: function(event) {
|
||||
//忽略多点触摸
|
||||
if (event.targetTouches.length !== 1) {
|
||||
return true
|
||||
}
|
||||
//修正事件源对象
|
||||
var targetElement = tapRecognizer.fixTarget(event.target)
|
||||
var touch = event.targetTouches[0]
|
||||
if (deviceIsIOS) {
|
||||
// 判断是否是点击文字,进行选择等操作,如果是,不需要模拟click
|
||||
var selection = window.getSelection();
|
||||
if (selection.rangeCount && !selection.isCollapsed) {
|
||||
return true
|
||||
}
|
||||
var id = touch.identifier
|
||||
//当 alert 或 confirm 时,点击其他地方,会触发touch事件,identifier相同,此事件应该被忽略
|
||||
if (id && isFinite(tapRecognizer.lastTouchIdentifier) && tapRecognizer.lastTouchIdentifier === id) {
|
||||
event.preventDefault()
|
||||
return false
|
||||
}
|
||||
|
||||
tapRecognizer.lastTouchIdentifier = id
|
||||
|
||||
tapRecognizer.updateScrollParent(targetElement)
|
||||
}
|
||||
//收集触摸点的信息
|
||||
tapRecognizer.status = "tapping"
|
||||
tapRecognizer.startTime = Date.now()
|
||||
tapRecognizer.element = targetElement
|
||||
tapRecognizer.pageX = touch.pageX
|
||||
tapRecognizer.pageY = touch.pageY
|
||||
// 如果点击太快,阻止双击带来的放大收缩行为
|
||||
if ((tapRecognizer.startTime - tapRecognizer.lastTime) < tapRecognizer.tapDelay) {
|
||||
event.preventDefault()
|
||||
}
|
||||
},
|
||||
touchmove: function(event) {
|
||||
if (tapRecognizer.status !== "tapping") {
|
||||
return true
|
||||
}
|
||||
// 如果事件源元素发生改变,或者发生了移动,那么就取消触发点击事件
|
||||
if (tapRecognizer.element !== tapRecognizer.fixTarget(event.target) ||
|
||||
tapRecognizer.touchHasMoved(event)) {
|
||||
tapRecognizer.status = tapRecognizer.element = 0
|
||||
}
|
||||
|
||||
},
|
||||
touchend: function(event) {
|
||||
var targetElement = tapRecognizer.element
|
||||
var now = Date.now()
|
||||
//如果是touchstart与touchend相隔太久,可以认为是长按,那么就直接返回
|
||||
//或者是在touchstart, touchmove阶段,判定其不该触发点击事件,也直接返回
|
||||
if (!targetElement || now - tapRecognizer.startTime > tapRecognizer.tapDelay) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
tapRecognizer.lastTime = now
|
||||
|
||||
var startTime = tapRecognizer.startTime
|
||||
tapRecognizer.status = tapRecognizer.startTime = 0
|
||||
|
||||
targetTagName = targetElement.tagName.toLowerCase()
|
||||
if (targetTagName === 'label') {
|
||||
//尝试触发label上可能绑定的tap事件
|
||||
Recognizer.fire(targetElement, 'tap', {
|
||||
touchEvent: event
|
||||
})
|
||||
var forElement = tapRecognizer.findControl(targetElement)
|
||||
if (forElement) {
|
||||
tapRecognizer.focus(targetElement)
|
||||
targetElement = forElement
|
||||
}
|
||||
} else if (tapRecognizer.needFocus(targetElement)) {
|
||||
// 如果元素从touchstart到touchend经历时间过长,那么不应该触发点击事
|
||||
// 或者此元素是iframe中的input元素,那么它也无法获点焦点
|
||||
if ((now - startTime) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) {
|
||||
tapRecognizer.element = 0
|
||||
return false
|
||||
}
|
||||
|
||||
tapRecognizer.focus(targetElement)
|
||||
deviceIsAndroid && tapRecognizer.sendClick(targetElement, event)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
if (deviceIsIOS) {
|
||||
//如果它的父容器的滚动条发生改变,那么应该识别为划动或拖动事件,不应该触发点击事件
|
||||
var scrollParent = targetElement.tapScrollParent;
|
||||
if (scrollParent && scrollParent.lastScrollTop !== scrollParent.scrollTop) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
//如果这不是一个需要使用原生click的元素,则屏蔽原生事件,避免触发两次click
|
||||
if (!tapRecognizer.needClick(targetElement)) {
|
||||
event.preventDefault()
|
||||
// 触发一次模拟的click
|
||||
tapRecognizer.sendClick(targetElement, event)
|
||||
}
|
||||
},
|
||||
touchcancel: function() {
|
||||
tapRecognizer.startTime = tapRecognizer.element = 0
|
||||
}
|
||||
}
|
||||
|
||||
Recognizer.add("tap", tapRecognizer)
|
||||
|
||||
var pressRecognizer = {
|
||||
events: ['longtap', 'doubletap'],
|
||||
cancelPress: function (pointer) {
|
||||
clearTimeout(pointer.pressingHandler)
|
||||
pointer.pressingHandler = null
|
||||
},
|
||||
touchstart: function (event) {
|
||||
Recognizer.start(event, function (pointer, touch) {
|
||||
pointer.pressingHandler = setTimeout(function () {
|
||||
if (pointer.status === 'tapping') {
|
||||
Recognizer.fire(event.target, 'longtap', {
|
||||
touch: touch,
|
||||
touchEvent: event
|
||||
})
|
||||
}
|
||||
pressRecognizer.cancelPress(pointer)
|
||||
}, 800)
|
||||
if (event.changedTouches.length !== 1) {
|
||||
pointer.status = 0
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
touchmove: function (event) {
|
||||
Recognizer.move(event, function (pointer) {
|
||||
if (pointer.distance > 10 && pointer.pressingHandler) {
|
||||
pressRecognizer.cancelPress(pointer)
|
||||
if (pointer.status === 'tapping') {
|
||||
pointer.status = 'panning'
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
touchend: function (event) {
|
||||
Recognizer.end(event, function (pointer, touch) {
|
||||
pressRecognizer.cancelPress(pointer)
|
||||
if (pointer.status === 'tapping') {
|
||||
pointer.lastTime = Date.now()
|
||||
if (pressRecognizer.lastTap && pointer.lastTime - pressRecognizer.lastTap.lastTime < 300) {
|
||||
Recognizer.fire(pointer.element, 'doubletap', {
|
||||
touch: touch,
|
||||
touchEvent: event
|
||||
})
|
||||
}
|
||||
|
||||
pressRecognizer.lastTap = pointer
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
touchcancel: function (event) {
|
||||
Recognizer.end(event, function (pointer) {
|
||||
pressRecognizer.cancelPress(pointer)
|
||||
})
|
||||
}
|
||||
}
|
||||
Recognizer.add('press', pressRecognizer)
|
||||
|
||||
var swipeRecognizer = {
|
||||
events: ['swipe', 'swipeleft', 'swiperight', 'swipeup', 'swipedown'],
|
||||
getAngle: function (x, y ) {
|
||||
return Math.atan2(y, x) * 180 / Math.PI
|
||||
},
|
||||
getDirection: function (x, y) {
|
||||
var angle = swipeRecognizer.getAngle(x, y)
|
||||
if ((angle < -45) && (angle > -135)) {
|
||||
return "up"
|
||||
} else if ((angle >= 45) && (angle < 315)) {
|
||||
return "down"
|
||||
} else if ((angle > -45) && (angle <= 45)) {
|
||||
return "right"
|
||||
} else{
|
||||
return "left"
|
||||
}
|
||||
},
|
||||
touchstart: function (event) {
|
||||
Recognizer.start(event, noop)
|
||||
},
|
||||
touchmove: function (event) {
|
||||
Recognizer.move(event, noop)
|
||||
},
|
||||
touchend: function (event) {
|
||||
if(event.changedTouches.length !== 1){
|
||||
return
|
||||
}
|
||||
Recognizer.end(event, function (pointer, touch) {
|
||||
var isflick = (pointer.distance > 30 && pointer.distance / pointer.duration > 0.65)
|
||||
if (isflick) {
|
||||
var extra = {
|
||||
deltaX : pointer.deltaX,
|
||||
deltaY: pointer.deltaY,
|
||||
touch: touch,
|
||||
touchEvent: event,
|
||||
direction: swipeRecognizer.getDirection(pointer.deltaX, pointer.deltaY),
|
||||
isVertical: pointer.isVertical
|
||||
}
|
||||
var target = pointer.element
|
||||
Recognizer.fire(target, 'swipe', extra)
|
||||
Recognizer.fire(target, 'swipe' + extra.direction, extra)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
swipeRecognizer.touchcancel = swipeRecognizer.touchend
|
||||
Recognizer.add('swipe', swipeRecognizer)
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue