|
|
/*!
|
|
|
* =====================================================
|
|
|
* Mui v3.7.2 (http://dev.dcloud.net.cn/mui)
|
|
|
* =====================================================
|
|
|
*/
|
|
|
/**
|
|
|
* MUI核心JS
|
|
|
* @type _L4.$|Function
|
|
|
*/
|
|
|
var mui = (function(document, undefined) {
|
|
|
var readyRE = /complete|loaded|interactive/;
|
|
|
var idSelectorRE = /^#([\w-]+)$/;
|
|
|
var classSelectorRE = /^\.([\w-]+)$/;
|
|
|
var tagSelectorRE = /^[\w-]+$/;
|
|
|
var translateRE = /translate(?:3d)?\((.+?)\)/;
|
|
|
var translateMatrixRE = /matrix(3d)?\((.+?)\)/;
|
|
|
|
|
|
var $ = function(selector, context) {
|
|
|
context = context || document;
|
|
|
if (!selector)
|
|
|
return wrap();
|
|
|
if (typeof selector === 'object')
|
|
|
if ($.isArrayLike(selector)) {
|
|
|
return wrap($.slice.call(selector), null);
|
|
|
} else {
|
|
|
return wrap([selector], null);
|
|
|
}
|
|
|
if (typeof selector === 'function')
|
|
|
return $.ready(selector);
|
|
|
if (typeof selector === 'string') {
|
|
|
try {
|
|
|
selector = selector.trim();
|
|
|
if (idSelectorRE.test(selector)) {
|
|
|
var found = document.getElementById(RegExp.$1);
|
|
|
return wrap(found ? [found] : []);
|
|
|
}
|
|
|
return wrap($.qsa(selector, context), selector);
|
|
|
} catch (e) {}
|
|
|
}
|
|
|
return wrap();
|
|
|
};
|
|
|
|
|
|
var wrap = function(dom, selector) {
|
|
|
dom = dom || [];
|
|
|
Object.setPrototypeOf(dom, $.fn);
|
|
|
dom.selector = selector || '';
|
|
|
return dom;
|
|
|
};
|
|
|
|
|
|
$.uuid = 0;
|
|
|
|
|
|
$.data = {};
|
|
|
/**
|
|
|
* extend(simple)
|
|
|
* @param {type} target
|
|
|
* @param {type} source
|
|
|
* @param {type} deep
|
|
|
* @returns {unresolved}
|
|
|
*/
|
|
|
$.extend = function() { //from jquery2
|
|
|
var options, name, src, copy, copyIsArray, clone,
|
|
|
target = arguments[0] || {},
|
|
|
i = 1,
|
|
|
length = arguments.length,
|
|
|
deep = false;
|
|
|
|
|
|
if (typeof target === "boolean") {
|
|
|
deep = target;
|
|
|
|
|
|
target = arguments[i] || {};
|
|
|
i++;
|
|
|
}
|
|
|
|
|
|
if (typeof target !== "object" && !$.isFunction(target)) {
|
|
|
target = {};
|
|
|
}
|
|
|
|
|
|
if (i === length) {
|
|
|
target = this;
|
|
|
i--;
|
|
|
}
|
|
|
|
|
|
for (; i < length; i++) {
|
|
|
if ((options = arguments[i]) != null) {
|
|
|
for (name in options) {
|
|
|
src = target[name];
|
|
|
copy = options[name];
|
|
|
|
|
|
if (target === copy) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
if (deep && copy && ($.isPlainObject(copy) || (copyIsArray = $.isArray(copy)))) {
|
|
|
if (copyIsArray) {
|
|
|
copyIsArray = false;
|
|
|
clone = src && $.isArray(src) ? src : [];
|
|
|
|
|
|
} else {
|
|
|
clone = src && $.isPlainObject(src) ? src : {};
|
|
|
}
|
|
|
|
|
|
target[name] = $.extend(deep, clone, copy);
|
|
|
|
|
|
} else if (copy !== undefined) {
|
|
|
target[name] = copy;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return target;
|
|
|
};
|
|
|
/**
|
|
|
* mui noop(function)
|
|
|
*/
|
|
|
$.noop = function() {};
|
|
|
/**
|
|
|
* mui slice(array)
|
|
|
*/
|
|
|
$.slice = [].slice;
|
|
|
/**
|
|
|
* mui filter(array)
|
|
|
*/
|
|
|
$.filter = [].filter;
|
|
|
|
|
|
$.type = function(obj) {
|
|
|
return obj == null ? String(obj) : class2type[{}.toString.call(obj)] || "object";
|
|
|
};
|
|
|
/**
|
|
|
* mui isArray
|
|
|
*/
|
|
|
$.isArray = Array.isArray ||
|
|
|
function(object) {
|
|
|
return object instanceof Array;
|
|
|
};
|
|
|
/**
|
|
|
* mui isArrayLike
|
|
|
* @param {Object} obj
|
|
|
*/
|
|
|
$.isArrayLike = function(obj) {
|
|
|
var length = !!obj && "length" in obj && obj.length;
|
|
|
var type = $.type(obj);
|
|
|
if (type === "function" || $.isWindow(obj)) {
|
|
|
return false;
|
|
|
}
|
|
|
return type === "array" || length === 0 ||
|
|
|
typeof length === "number" && length > 0 && (length - 1) in obj;
|
|
|
};
|
|
|
/**
|
|
|
* mui isWindow(需考虑obj为undefined的情况)
|
|
|
*/
|
|
|
$.isWindow = function(obj) {
|
|
|
return obj != null && obj === obj.window;
|
|
|
};
|
|
|
/**
|
|
|
* mui isObject
|
|
|
*/
|
|
|
$.isObject = function(obj) {
|
|
|
return $.type(obj) === "object";
|
|
|
};
|
|
|
/**
|
|
|
* mui isPlainObject
|
|
|
*/
|
|
|
$.isPlainObject = function(obj) {
|
|
|
return $.isObject(obj) && !$.isWindow(obj) && Object.getPrototypeOf(obj) === Object.prototype;
|
|
|
};
|
|
|
/**
|
|
|
* mui isEmptyObject
|
|
|
* @param {Object} o
|
|
|
*/
|
|
|
$.isEmptyObject = function(o) {
|
|
|
for (var p in o) {
|
|
|
if (p !== undefined) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
};
|
|
|
/**
|
|
|
* mui isFunction
|
|
|
*/
|
|
|
$.isFunction = function(value) {
|
|
|
return $.type(value) === "function";
|
|
|
};
|
|
|
/**
|
|
|
* mui querySelectorAll
|
|
|
* @param {type} selector
|
|
|
* @param {type} context
|
|
|
* @returns {Array}
|
|
|
*/
|
|
|
$.qsa = function(selector, context) {
|
|
|
context = context || document;
|
|
|
return $.slice.call(classSelectorRE.test(selector) ? context.getElementsByClassName(RegExp.$1) : tagSelectorRE.test(selector) ? context.getElementsByTagName(selector) : context.querySelectorAll(selector));
|
|
|
};
|
|
|
/**
|
|
|
* ready(DOMContentLoaded)
|
|
|
* @param {type} callback
|
|
|
* @returns {_L6.$}
|
|
|
*/
|
|
|
$.ready = function(callback) {
|
|
|
if (readyRE.test(document.readyState)) {
|
|
|
callback($);
|
|
|
} else {
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
callback($);
|
|
|
}, false);
|
|
|
}
|
|
|
return this;
|
|
|
};
|
|
|
/**
|
|
|
* 将 fn 缓存一段时间后, 再被调用执行
|
|
|
* 此方法为了避免在 ms 段时间内, 执行 fn 多次. 常用于 resize , scroll , mousemove 等连续性事件中;
|
|
|
* 当 ms 设置为 -1, 表示立即执行 fn, 即和直接调用 fn 一样;
|
|
|
* 调用返回函数的 stop 停止最后一次的 buffer 效果
|
|
|
* @param {Object} fn
|
|
|
* @param {Object} ms
|
|
|
* @param {Object} context
|
|
|
*/
|
|
|
$.buffer = function(fn, ms, context) {
|
|
|
var timer;
|
|
|
var lastStart = 0;
|
|
|
var lastEnd = 0;
|
|
|
var ms = ms || 150;
|
|
|
|
|
|
function run() {
|
|
|
if (timer) {
|
|
|
timer.cancel();
|
|
|
timer = 0;
|
|
|
}
|
|
|
lastStart = $.now();
|
|
|
fn.apply(context || this, arguments);
|
|
|
lastEnd = $.now();
|
|
|
}
|
|
|
|
|
|
return $.extend(function() {
|
|
|
if (
|
|
|
(!lastStart) || // 从未运行过
|
|
|
(lastEnd >= lastStart && $.now() - lastEnd > ms) || // 上次运行成功后已经超过ms毫秒
|
|
|
(lastEnd < lastStart && $.now() - lastStart > ms * 8) // 上次运行或未完成,后8*ms毫秒
|
|
|
) {
|
|
|
run.apply(this, arguments);
|
|
|
} else {
|
|
|
if (timer) {
|
|
|
timer.cancel();
|
|
|
}
|
|
|
timer = $.later(run, ms, null, $.slice.call(arguments));
|
|
|
}
|
|
|
}, {
|
|
|
stop: function() {
|
|
|
if (timer) {
|
|
|
timer.cancel();
|
|
|
timer = 0;
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
/**
|
|
|
* each
|
|
|
* @param {type} elements
|
|
|
* @param {type} callback
|
|
|
* @returns {_L8.$}
|
|
|
*/
|
|
|
$.each = function(elements, callback, hasOwnProperty) {
|
|
|
if (!elements) {
|
|
|
return this;
|
|
|
}
|
|
|
if (typeof elements.length === 'number') {
|
|
|
[].every.call(elements, function(el, idx) {
|
|
|
return callback.call(el, idx, el) !== false;
|
|
|
});
|
|
|
} else {
|
|
|
for (var key in elements) {
|
|
|
if (hasOwnProperty) {
|
|
|
if (elements.hasOwnProperty(key)) {
|
|
|
if (callback.call(elements[key], key, elements[key]) === false) return elements;
|
|
|
}
|
|
|
} else {
|
|
|
if (callback.call(elements[key], key, elements[key]) === false) return elements;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return this;
|
|
|
};
|
|
|
$.focus = function(element) {
|
|
|
if ($.os.ios) {
|
|
|
setTimeout(function() {
|
|
|
element.focus();
|
|
|
}, 10);
|
|
|
} else {
|
|
|
element.focus();
|
|
|
}
|
|
|
};
|
|
|
/**
|
|
|
* trigger event
|
|
|
* @param {type} element
|
|
|
* @param {type} eventType
|
|
|
* @param {type} eventData
|
|
|
* @returns {_L8.$}
|
|
|
*/
|
|
|
$.trigger = function(element, eventType, eventData) {
|
|
|
element.dispatchEvent(new CustomEvent(eventType, {
|
|
|
detail: eventData,
|
|
|
bubbles: true,
|
|
|
cancelable: true
|
|
|
}));
|
|
|
return this;
|
|
|
};
|
|
|
/**
|
|
|
* getStyles
|
|
|
* @param {type} element
|
|
|
* @param {type} property
|
|
|
* @returns {styles}
|
|
|
*/
|
|
|
$.getStyles = function(element, property) {
|
|
|
var styles = element.ownerDocument.defaultView.getComputedStyle(element, null);
|
|
|
if (property) {
|
|
|
return styles.getPropertyValue(property) || styles[property];
|
|
|
}
|
|
|
return styles;
|
|
|
};
|
|
|
/**
|
|
|
* parseTranslate
|
|
|
* @param {type} translateString
|
|
|
* @param {type} position
|
|
|
* @returns {Object}
|
|
|
*/
|
|
|
$.parseTranslate = function(translateString, position) {
|
|
|
var result = translateString.match(translateRE || '');
|
|
|
if (!result || !result[1]) {
|
|
|
result = ['', '0,0,0'];
|
|
|
}
|
|
|
result = result[1].split(",");
|
|
|
result = {
|
|
|
x: parseFloat(result[0]),
|
|
|
y: parseFloat(result[1]),
|
|
|
z: parseFloat(result[2])
|
|
|
};
|
|
|
if (position && result.hasOwnProperty(position)) {
|
|
|
return result[position];
|
|
|
}
|
|
|
return result;
|
|
|
};
|
|
|
/**
|
|
|
* parseTranslateMatrix
|
|
|
* @param {type} translateString
|
|
|
* @param {type} position
|
|
|
* @returns {Object}
|
|
|
*/
|
|
|
$.parseTranslateMatrix = function(translateString, position) {
|
|
|
var matrix = translateString.match(translateMatrixRE);
|
|
|
var is3D = matrix && matrix[1];
|
|
|
if (matrix) {
|
|
|
matrix = matrix[2].split(",");
|
|
|
if (is3D === "3d")
|
|
|
matrix = matrix.slice(12, 15);
|
|
|
else {
|
|
|
matrix.push(0);
|
|
|
matrix = matrix.slice(4, 7);
|
|
|
}
|
|
|
} else {
|
|
|
matrix = [0, 0, 0];
|
|
|
}
|
|
|
var result = {
|
|
|
x: parseFloat(matrix[0]),
|
|
|
y: parseFloat(matrix[1]),
|
|
|
z: parseFloat(matrix[2])
|
|
|
};
|
|
|
if (position && result.hasOwnProperty(position)) {
|
|
|
return result[position];
|
|
|
}
|
|
|
return result;
|
|
|
};
|
|
|
$.hooks = {};
|
|
|
$.addAction = function(type, hook) {
|
|
|
var hooks = $.hooks[type];
|
|
|
if (!hooks) {
|
|
|
hooks = [];
|
|
|
}
|
|
|
hook.index = hook.index || 1000;
|
|
|
hooks.push(hook);
|
|
|
hooks.sort(function(a, b) {
|
|
|
return a.index - b.index;
|
|
|
});
|
|
|
$.hooks[type] = hooks;
|
|
|
return $.hooks[type];
|
|
|
};
|
|
|
$.doAction = function(type, callback) {
|
|
|
if ($.isFunction(callback)) { //指定了callback
|
|
|
$.each($.hooks[type], callback);
|
|
|
} else { //未指定callback,直接执行
|
|
|
$.each($.hooks[type], function(index, hook) {
|
|
|
return !hook.handle();
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
/**
|
|
|
* setTimeout封装
|
|
|
* @param {Object} fn
|
|
|
* @param {Object} when
|
|
|
* @param {Object} context
|
|
|
* @param {Object} data
|
|
|
*/
|
|
|
$.later = function(fn, when, context, data) {
|
|
|
when = when || 0;
|
|
|
var m = fn;
|
|
|
var d = data;
|
|
|
var f;
|
|
|
var r;
|
|
|
|
|
|
if (typeof fn === 'string') {
|
|
|
m = context[fn];
|
|
|
}
|
|
|
|
|
|
f = function() {
|
|
|
m.apply(context, $.isArray(d) ? d : [d]);
|
|
|
};
|
|
|
|
|
|
r = setTimeout(f, when);
|
|
|
|
|
|
return {
|
|
|
id: r,
|
|
|
cancel: function() {
|
|
|
clearTimeout(r);
|
|
|
}
|
|
|
};
|
|
|
};
|
|
|
$.now = Date.now || function() {
|
|
|
return +new Date();
|
|
|
};
|
|
|
var class2type = {};
|
|
|
$.each(['Boolean', 'Number', 'String', 'Function', 'Array', 'Date', 'RegExp', 'Object', 'Error'], function(i, name) {
|
|
|
class2type["[object " + name + "]"] = name.toLowerCase();
|
|
|
});
|
|
|
if (window.JSON) {
|
|
|
$.parseJSON = JSON.parse;
|
|
|
}
|
|
|
/**
|
|
|
* $.fn
|
|
|
*/
|
|
|
$.fn = {
|
|
|
each: function(callback) {
|
|
|
[].every.call(this, function(el, idx) {
|
|
|
return callback.call(el, idx, el) !== false;
|
|
|
});
|
|
|
return this;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 兼容 AMD 模块
|
|
|
**/
|
|
|
if (typeof define === 'function' && define.amd) {
|
|
|
define('mui', [], function() {
|
|
|
return $;
|
|
|
});
|
|
|
}
|
|
|
|
|
|
return $;
|
|
|
})(document);
|
|
|
//window.mui = mui;
|
|
|
//'$' in window || (window.$ = mui);
|
|
|
/**
|
|
|
* $.os
|
|
|
* @param {type} $
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window) {
|
|
|
function detect(ua) {
|
|
|
this.os = {};
|
|
|
var funcs = [
|
|
|
|
|
|
function() { //wechat
|
|
|
var wechat = ua.match(/(MicroMessenger)\/([\d\.]+)/i);
|
|
|
if (wechat) { //wechat
|
|
|
this.os.wechat = {
|
|
|
version: wechat[2].replace(/_/g, '.')
|
|
|
};
|
|
|
}
|
|
|
return false;
|
|
|
},
|
|
|
function() { //android
|
|
|
var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/);
|
|
|
if (android) {
|
|
|
this.os.android = true;
|
|
|
this.os.version = android[2];
|
|
|
|
|
|
this.os.isBadAndroid = !(/Chrome\/\d/.test(window.navigator.appVersion));
|
|
|
}
|
|
|
return this.os.android === true;
|
|
|
},
|
|
|
function() { //ios
|
|
|
var iphone = ua.match(/(iPhone\sOS)\s([\d_]+)/);
|
|
|
if (iphone) { //iphone
|
|
|
this.os.ios = this.os.iphone = true;
|
|
|
this.os.version = iphone[2].replace(/_/g, '.');
|
|
|
} else {
|
|
|
var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
|
|
|
if (ipad) { //ipad
|
|
|
this.os.ios = this.os.ipad = true;
|
|
|
this.os.version = ipad[2].replace(/_/g, '.');
|
|
|
}
|
|
|
}
|
|
|
return this.os.ios === true;
|
|
|
}
|
|
|
];
|
|
|
[].every.call(funcs, function(func) {
|
|
|
return !func.call($);
|
|
|
});
|
|
|
}
|
|
|
detect.call($, navigator.userAgent);
|
|
|
})(mui, window);
|
|
|
/**
|
|
|
* $.os.plus
|
|
|
* @param {type} $
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, document) {
|
|
|
function detect(ua) {
|
|
|
this.os = this.os || {};
|
|
|
var plus = ua.match(/Html5Plus/i); //TODO 5\+Browser?
|
|
|
if (plus) {
|
|
|
this.os.plus = true;
|
|
|
$(function() {
|
|
|
document.body.classList.add('mui-plus');
|
|
|
});
|
|
|
if (ua.match(/StreamApp/i)) { //TODO 最好有流应用自己的标识
|
|
|
this.os.stream = true;
|
|
|
$(function() {
|
|
|
document.body.classList.add('mui-plus-stream');
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
detect.call($, navigator.userAgent);
|
|
|
})(mui, document);
|
|
|
/**
|
|
|
* 仅提供简单的on,off(仅支持事件委托,不支持当前元素绑定,当前元素绑定请直接使用addEventListener,removeEventListener)
|
|
|
* @param {Object} $
|
|
|
*/
|
|
|
(function($) {
|
|
|
if ('ontouchstart' in window) {
|
|
|
$.isTouchable = true;
|
|
|
$.EVENT_START = 'touchstart';
|
|
|
$.EVENT_MOVE = 'touchmove';
|
|
|
$.EVENT_END = 'touchend';
|
|
|
} else {
|
|
|
$.isTouchable = false;
|
|
|
$.EVENT_START = 'mousedown';
|
|
|
$.EVENT_MOVE = 'mousemove';
|
|
|
$.EVENT_END = 'mouseup';
|
|
|
}
|
|
|
$.EVENT_CANCEL = 'touchcancel';
|
|
|
$.EVENT_CLICK = 'click';
|
|
|
|
|
|
var _mid = 1;
|
|
|
var delegates = {};
|
|
|
//需要wrap的函数
|
|
|
var eventMethods = {
|
|
|
preventDefault: 'isDefaultPrevented',
|
|
|
stopImmediatePropagation: 'isImmediatePropagationStopped',
|
|
|
stopPropagation: 'isPropagationStopped'
|
|
|
};
|
|
|
//默认true返回函数
|
|
|
var returnTrue = function() {
|
|
|
return true
|
|
|
};
|
|
|
//默认false返回函数
|
|
|
var returnFalse = function() {
|
|
|
return false
|
|
|
};
|
|
|
//wrap浏览器事件
|
|
|
var compatible = function(event, target) {
|
|
|
if (!event.detail) {
|
|
|
event.detail = {
|
|
|
currentTarget: target
|
|
|
};
|
|
|
} else {
|
|
|
event.detail.currentTarget = target;
|
|
|
}
|
|
|
$.each(eventMethods, function(name, predicate) {
|
|
|
var sourceMethod = event[name];
|
|
|
event[name] = function() {
|
|
|
this[predicate] = returnTrue;
|
|
|
return sourceMethod && sourceMethod.apply(event, arguments)
|
|
|
}
|
|
|
event[predicate] = returnFalse;
|
|
|
}, true);
|
|
|
return event;
|
|
|
};
|
|
|
//简单的wrap对象_mid
|
|
|
var mid = function(obj) {
|
|
|
return obj && (obj._mid || (obj._mid = _mid++));
|
|
|
};
|
|
|
//事件委托对象绑定的事件回调列表
|
|
|
var delegateFns = {};
|
|
|
//返回事件委托的wrap事件回调
|
|
|
var delegateFn = function(element, event, selector, callback) {
|
|
|
return function(e) {
|
|
|
//same event
|
|
|
var callbackObjs = delegates[element._mid][event];
|
|
|
var handlerQueue = [];
|
|
|
var target = e.target;
|
|
|
var selectorAlls = {};
|
|
|
for (; target && target !== document; target = target.parentNode) {
|
|
|
if (target === element) {
|
|
|
break;
|
|
|
}
|
|
|
if (~['click', 'tap', 'doubletap', 'longtap', 'hold'].indexOf(event) && (target.disabled || target.classList.contains('mui-disabled'))) {
|
|
|
break;
|
|
|
}
|
|
|
var matches = {};
|
|
|
$.each(callbackObjs, function(selector, callbacks) { //same selector
|
|
|
selectorAlls[selector] || (selectorAlls[selector] = $.qsa(selector, element));
|
|
|
if (selectorAlls[selector] && ~(selectorAlls[selector]).indexOf(target)) {
|
|
|
if (!matches[selector]) {
|
|
|
matches[selector] = callbacks;
|
|
|
}
|
|
|
}
|
|
|
}, true);
|
|
|
if (!$.isEmptyObject(matches)) {
|
|
|
handlerQueue.push({
|
|
|
element: target,
|
|
|
handlers: matches
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
selectorAlls = null;
|
|
|
e = compatible(e); //compatible event
|
|
|
$.each(handlerQueue, function(index, handler) {
|
|
|
target = handler.element;
|
|
|
var tagName = target.tagName;
|
|
|
if (event === 'tap' && (tagName !== 'INPUT' && tagName !== 'TEXTAREA' && tagName !== 'SELECT')) {
|
|
|
e.preventDefault();
|
|
|
e.detail && e.detail.gesture && e.detail.gesture.preventDefault();
|
|
|
}
|
|
|
$.each(handler.handlers, function(index, handler) {
|
|
|
$.each(handler, function(index, callback) {
|
|
|
if (callback.call(target, e) === false) {
|
|
|
e.preventDefault();
|
|
|
e.stopPropagation();
|
|
|
}
|
|
|
}, true);
|
|
|
}, true)
|
|
|
if (e.isPropagationStopped()) {
|
|
|
return false;
|
|
|
}
|
|
|
}, true);
|
|
|
};
|
|
|
};
|
|
|
var findDelegateFn = function(element, event) {
|
|
|
var delegateCallbacks = delegateFns[mid(element)];
|
|
|
var result = [];
|
|
|
if (delegateCallbacks) {
|
|
|
result = [];
|
|
|
if (event) {
|
|
|
var filterFn = function(fn) {
|
|
|
return fn.type === event;
|
|
|
}
|
|
|
return delegateCallbacks.filter(filterFn);
|
|
|
} else {
|
|
|
result = delegateCallbacks;
|
|
|
}
|
|
|
}
|
|
|
return result;
|
|
|
};
|
|
|
var preventDefaultException = /^(INPUT|TEXTAREA|BUTTON|SELECT)$/;
|
|
|
/**
|
|
|
* mui delegate events
|
|
|
* @param {type} event
|
|
|
* @param {type} selector
|
|
|
* @param {type} callback
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
$.fn.on = function(event, selector, callback) { //仅支持简单的事件委托,主要是tap事件使用,类似mouse,focus之类暂不封装支持
|
|
|
return this.each(function() {
|
|
|
var element = this;
|
|
|
mid(element);
|
|
|
mid(callback);
|
|
|
var isAddEventListener = false;
|
|
|
var delegateEvents = delegates[element._mid] || (delegates[element._mid] = {});
|
|
|
var delegateCallbackObjs = delegateEvents[event] || ((delegateEvents[event] = {}));
|
|
|
if ($.isEmptyObject(delegateCallbackObjs)) {
|
|
|
isAddEventListener = true;
|
|
|
}
|
|
|
var delegateCallbacks = delegateCallbackObjs[selector] || (delegateCallbackObjs[selector] = []);
|
|
|
delegateCallbacks.push(callback);
|
|
|
if (isAddEventListener) {
|
|
|
var delegateFnArray = delegateFns[mid(element)];
|
|
|
if (!delegateFnArray) {
|
|
|
delegateFnArray = [];
|
|
|
}
|
|
|
var delegateCallback = delegateFn(element, event, selector, callback);
|
|
|
delegateFnArray.push(delegateCallback);
|
|
|
delegateCallback.i = delegateFnArray.length - 1;
|
|
|
delegateCallback.type = event;
|
|
|
delegateFns[mid(element)] = delegateFnArray;
|
|
|
element.addEventListener(event, delegateCallback);
|
|
|
if (event === 'tap') { //TODO 需要找个更好的解决方案
|
|
|
element.addEventListener('click', function(e) {
|
|
|
if (e.target) {
|
|
|
var tagName = e.target.tagName;
|
|
|
if (!preventDefaultException.test(tagName)) {
|
|
|
if (tagName === 'A') {
|
|
|
var href = e.target.href;
|
|
|
if (!(href && ~href.indexOf('tel:'))) {
|
|
|
e.preventDefault();
|
|
|
}
|
|
|
} else {
|
|
|
e.preventDefault();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
$.fn.off = function(event, selector, callback) {
|
|
|
return this.each(function() {
|
|
|
var _mid = mid(this);
|
|
|
if (!event) { //mui(selector).off();
|
|
|
delegates[_mid] && delete delegates[_mid];
|
|
|
} else if (!selector) { //mui(selector).off(event);
|
|
|
delegates[_mid] && delete delegates[_mid][event];
|
|
|
} else if (!callback) { //mui(selector).off(event,selector);
|
|
|
delegates[_mid] && delegates[_mid][event] && delete delegates[_mid][event][selector];
|
|
|
} else { //mui(selector).off(event,selector,callback);
|
|
|
var delegateCallbacks = delegates[_mid] && delegates[_mid][event] && delegates[_mid][event][selector];
|
|
|
$.each(delegateCallbacks, function(index, delegateCallback) {
|
|
|
if (mid(delegateCallback) === mid(callback)) {
|
|
|
delegateCallbacks.splice(index, 1);
|
|
|
return false;
|
|
|
}
|
|
|
}, true);
|
|
|
}
|
|
|
if (delegates[_mid]) {
|
|
|
//如果off掉了所有当前element的指定的event事件,则remove掉当前element的delegate回调
|
|
|
if ((!delegates[_mid][event] || $.isEmptyObject(delegates[_mid][event]))) {
|
|
|
findDelegateFn(this, event).forEach(function(fn) {
|
|
|
this.removeEventListener(fn.type, fn);
|
|
|
delete delegateFns[_mid][fn.i];
|
|
|
}.bind(this));
|
|
|
}
|
|
|
} else {
|
|
|
//如果delegates[_mid]已不存在,删除所有
|
|
|
findDelegateFn(this).forEach(function(fn) {
|
|
|
this.removeEventListener(fn.type, fn);
|
|
|
delete delegateFns[_mid][fn.i];
|
|
|
}.bind(this));
|
|
|
}
|
|
|
});
|
|
|
|
|
|
};
|
|
|
})(mui);
|
|
|
/**
|
|
|
* mui target(action>popover>modal>tab>toggle)
|
|
|
*/
|
|
|
(function($, window, document) {
|
|
|
/**
|
|
|
* targets
|
|
|
*/
|
|
|
$.targets = {};
|
|
|
/**
|
|
|
* target handles
|
|
|
*/
|
|
|
$.targetHandles = [];
|
|
|
/**
|
|
|
* register target
|
|
|
* @param {type} target
|
|
|
* @returns {$.targets}
|
|
|
*/
|
|
|
$.registerTarget = function(target) {
|
|
|
|
|
|
target.index = target.index || 1000;
|
|
|
|
|
|
$.targetHandles.push(target);
|
|
|
|
|
|
$.targetHandles.sort(function(a, b) {
|
|
|
return a.index - b.index;
|
|
|
});
|
|
|
|
|
|
return $.targetHandles;
|
|
|
};
|
|
|
window.addEventListener($.EVENT_START, function(event) {
|
|
|
var target = event.target;
|
|
|
var founds = {};
|
|
|
for (; target && target !== document; target = target.parentNode) {
|
|
|
var isFound = false;
|
|
|
$.each($.targetHandles, function(index, targetHandle) {
|
|
|
var name = targetHandle.name;
|
|
|
if (!isFound && !founds[name] && targetHandle.hasOwnProperty('handle')) {
|
|
|
$.targets[name] = targetHandle.handle(event, target);
|
|
|
if ($.targets[name]) {
|
|
|
founds[name] = true;
|
|
|
if (targetHandle.isContinue !== true) {
|
|
|
isFound = true;
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
if (!founds[name]) {
|
|
|
if (targetHandle.isReset !== false)
|
|
|
$.targets[name] = false;
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
if (isFound) {
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
window.addEventListener('click', function(event) { //解决touch与click的target不一致的问题(比如链接边缘点击时,touch的target为html,而click的target为A)
|
|
|
var target = event.target;
|
|
|
var isFound = false;
|
|
|
for (; target && target !== document; target = target.parentNode) {
|
|
|
if (target.tagName === 'A') {
|
|
|
$.each($.targetHandles, function(index, targetHandle) {
|
|
|
var name = targetHandle.name;
|
|
|
if (targetHandle.hasOwnProperty('handle')) {
|
|
|
if (targetHandle.handle(event, target)) {
|
|
|
isFound = true;
|
|
|
event.preventDefault();
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
if (isFound) {
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
})(mui, window, document);
|
|
|
/**
|
|
|
* fixed trim
|
|
|
* @param {type} undefined
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function(undefined) {
|
|
|
if (String.prototype.trim === undefined) { // fix for iOS 3.2
|
|
|
String.prototype.trim = function() {
|
|
|
return this.replace(/^\s+|\s+$/g, '');
|
|
|
};
|
|
|
}
|
|
|
Object.setPrototypeOf = Object.setPrototypeOf || function(obj, proto) {
|
|
|
obj['__proto__'] = proto;
|
|
|
return obj;
|
|
|
};
|
|
|
|
|
|
})();
|
|
|
/**
|
|
|
* fixed CustomEvent
|
|
|
*/
|
|
|
(function() {
|
|
|
if (typeof window.CustomEvent === 'undefined') {
|
|
|
function CustomEvent(event, params) {
|
|
|
params = params || {
|
|
|
bubbles: false,
|
|
|
cancelable: false,
|
|
|
detail: undefined
|
|
|
};
|
|
|
var evt = document.createEvent('Events');
|
|
|
var bubbles = true;
|
|
|
for (var name in params) {
|
|
|
(name === 'bubbles') ? (bubbles = !!params[name]) : (evt[name] = params[name]);
|
|
|
}
|
|
|
evt.initEvent(event, bubbles, true);
|
|
|
return evt;
|
|
|
};
|
|
|
CustomEvent.prototype = window.Event.prototype;
|
|
|
window.CustomEvent = CustomEvent;
|
|
|
}
|
|
|
})();
|
|
|
/*
|
|
|
A shim for non ES5 supporting browsers.
|
|
|
Adds function bind to Function prototype, so that you can do partial application.
|
|
|
Works even with the nasty thing, where the first word is the opposite of extranet, the second one is the profession of Columbus, and the version number is 9, flipped 180 degrees.
|
|
|
*/
|
|
|
|
|
|
Function.prototype.bind = Function.prototype.bind || function(to) {
|
|
|
// Make an array of our arguments, starting from second argument
|
|
|
var partial = Array.prototype.splice.call(arguments, 1),
|
|
|
// We'll need the original function.
|
|
|
fn = this;
|
|
|
var bound = function() {
|
|
|
// Join the already applied arguments to the now called ones (after converting to an array again).
|
|
|
var args = partial.concat(Array.prototype.splice.call(arguments, 0));
|
|
|
// If not being called as a constructor
|
|
|
if (!(this instanceof bound)) {
|
|
|
// return the result of the function called bound to target and partially applied.
|
|
|
return fn.apply(to, args);
|
|
|
}
|
|
|
// If being called as a constructor, apply the function bound to self.
|
|
|
fn.apply(this, args);
|
|
|
}
|
|
|
// Attach the prototype of the function to our newly created function.
|
|
|
bound.prototype = fn.prototype;
|
|
|
return bound;
|
|
|
};
|
|
|
/**
|
|
|
* mui fixed classList
|
|
|
* @param {type} document
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function(document) {
|
|
|
if (!("classList" in document.documentElement) && Object.defineProperty && typeof HTMLElement !== 'undefined') {
|
|
|
|
|
|
Object.defineProperty(HTMLElement.prototype, 'classList', {
|
|
|
get: function() {
|
|
|
var self = this;
|
|
|
function update(fn) {
|
|
|
return function(value) {
|
|
|
var classes = self.className.split(/\s+/),
|
|
|
index = classes.indexOf(value);
|
|
|
|
|
|
fn(classes, index, value);
|
|
|
self.className = classes.join(" ");
|
|
|
};
|
|
|
}
|
|
|
|
|
|
var ret = {
|
|
|
add: update(function(classes, index, value) {
|
|
|
~index || classes.push(value);
|
|
|
}),
|
|
|
remove: update(function(classes, index) {
|
|
|
~index && classes.splice(index, 1);
|
|
|
}),
|
|
|
toggle: update(function(classes, index, value) {
|
|
|
~index ? classes.splice(index, 1) : classes.push(value);
|
|
|
}),
|
|
|
contains: function(value) {
|
|
|
return !!~self.className.split(/\s+/).indexOf(value);
|
|
|
},
|
|
|
item: function(i) {
|
|
|
return self.className.split(/\s+/)[i] || null;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Object.defineProperty(ret, 'length', {
|
|
|
get: function() {
|
|
|
return self.className.split(/\s+/).length;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
})(document);
|
|
|
|
|
|
/**
|
|
|
* mui fixed requestAnimationFrame
|
|
|
* @param {type} window
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function(window) {
|
|
|
if (!window.requestAnimationFrame) {
|
|
|
var lastTime = 0;
|
|
|
window.requestAnimationFrame = window.webkitRequestAnimationFrame || function(callback, element) {
|
|
|
var currTime = new Date().getTime();
|
|
|
var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
|
|
|
var id = window.setTimeout(function() {
|
|
|
callback(currTime + timeToCall);
|
|
|
}, timeToCall);
|
|
|
lastTime = currTime + timeToCall;
|
|
|
return id;
|
|
|
};
|
|
|
window.cancelAnimationFrame = window.webkitCancelAnimationFrame || window.webkitCancelRequestAnimationFrame || function(id) {
|
|
|
clearTimeout(id);
|
|
|
};
|
|
|
};
|
|
|
}(window));
|
|
|
/**
|
|
|
* fastclick(only for radio,checkbox)
|
|
|
*/
|
|
|
(function($, window, name) {
|
|
|
if (!$.os.android && !$.os.ios) { //目前仅识别android和ios
|
|
|
return;
|
|
|
}
|
|
|
if (window.FastClick) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
var handle = function(event, target) {
|
|
|
if (target.tagName === 'LABEL') {
|
|
|
if (target.parentNode) {
|
|
|
target = target.parentNode.querySelector('input');
|
|
|
}
|
|
|
}
|
|
|
if (target && (target.type === 'radio' || target.type === 'checkbox')) {
|
|
|
if (!target.disabled) { //disabled
|
|
|
return target;
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
$.registerTarget({
|
|
|
name: name,
|
|
|
index: 40,
|
|
|
handle: handle,
|
|
|
target: false
|
|
|
});
|
|
|
var dispatchEvent = function(event) {
|
|
|
var targetElement = $.targets.click;
|
|
|
if (targetElement) {
|
|
|
var clickEvent, touch;
|
|
|
// On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect
|
|
|
if (document.activeElement && document.activeElement !== targetElement) {
|
|
|
document.activeElement.blur();
|
|
|
}
|
|
|
touch = event.detail.gesture.changedTouches[0];
|
|
|
// Synthesise a click event, with an extra attribute so it can be tracked
|
|
|
clickEvent = document.createEvent('MouseEvents');
|
|
|
clickEvent.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
|
|
|
clickEvent.forwardedTouchEvent = true;
|
|
|
targetElement.dispatchEvent(clickEvent);
|
|
|
event.detail && event.detail.gesture.preventDefault();
|
|
|
}
|
|
|
};
|
|
|
window.addEventListener('tap', dispatchEvent);
|
|
|
window.addEventListener('doubletap', dispatchEvent);
|
|
|
//捕获
|
|
|
window.addEventListener('click', function(event) {
|
|
|
if ($.targets.click) {
|
|
|
if (!event.forwardedTouchEvent) { //stop click
|
|
|
if (event.stopImmediatePropagation) {
|
|
|
event.stopImmediatePropagation();
|
|
|
} else {
|
|
|
// Part of the hack for browsers that don't support Event#stopImmediatePropagation
|
|
|
event.propagationStopped = true;
|
|
|
}
|
|
|
event.stopPropagation();
|
|
|
event.preventDefault();
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
}, true);
|
|
|
|
|
|
})(mui, window, 'click');
|
|
|
(function($, document) {
|
|
|
$(function() {
|
|
|
if (!$.os.ios) {
|
|
|
return;
|
|
|
}
|
|
|
var CLASS_FOCUSIN = 'mui-focusin';
|
|
|
var CLASS_BAR_TAB = 'mui-bar-tab';
|
|
|
var CLASS_BAR_FOOTER = 'mui-bar-footer';
|
|
|
var CLASS_BAR_FOOTER_SECONDARY = 'mui-bar-footer-secondary';
|
|
|
var CLASS_BAR_FOOTER_SECONDARY_TAB = 'mui-bar-footer-secondary-tab';
|
|
|
// var content = document.querySelector('.' + CLASS_CONTENT);
|
|
|
// if (content) {
|
|
|
// document.body.insertBefore(content, document.body.firstElementChild);
|
|
|
// }
|
|
|
document.addEventListener('focusin', function(e) {
|
|
|
if ($.os.plus) { //在父webview里边不fix
|
|
|
if (window.plus) {
|
|
|
if (plus.webview.currentWebview().children().length > 0) {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
var target = e.target;
|
|
|
//TODO 需考虑所有键盘弹起的情况
|
|
|
if (target.tagName && (target.tagName === 'TEXTAREA' || (target.tagName === 'INPUT' && (target.type === 'text' || target.type === 'search' || target.type === 'number')))) {
|
|
|
if (target.disabled || target.readOnly) {
|
|
|
return;
|
|
|
}
|
|
|
document.body.classList.add(CLASS_FOCUSIN);
|
|
|
var isFooter = false;
|
|
|
for (; target && target !== document; target = target.parentNode) {
|
|
|
var classList = target.classList;
|
|
|
if (classList && classList.contains(CLASS_BAR_TAB) || classList.contains(CLASS_BAR_FOOTER) || classList.contains(CLASS_BAR_FOOTER_SECONDARY) || classList.contains(CLASS_BAR_FOOTER_SECONDARY_TAB)) {
|
|
|
isFooter = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if (isFooter) {
|
|
|
var scrollTop = document.body.scrollHeight;
|
|
|
var scrollLeft = document.body.scrollLeft;
|
|
|
setTimeout(function() {
|
|
|
window.scrollTo(scrollLeft, scrollTop);
|
|
|
}, 20);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
document.addEventListener('focusout', function(e) {
|
|
|
var classList = document.body.classList;
|
|
|
if (classList.contains(CLASS_FOCUSIN)) {
|
|
|
classList.remove(CLASS_FOCUSIN);
|
|
|
setTimeout(function() {
|
|
|
window.scrollTo(document.body.scrollLeft, document.body.scrollTop);
|
|
|
}, 20);
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
})(mui, document);
|
|
|
/**
|
|
|
* mui namespace(optimization)
|
|
|
* @param {type} $
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($) {
|
|
|
$.namespace = 'mui';
|
|
|
$.classNamePrefix = $.namespace + '-';
|
|
|
$.classSelectorPrefix = '.' + $.classNamePrefix;
|
|
|
/**
|
|
|
* 返回正确的className
|
|
|
* @param {type} className
|
|
|
* @returns {String}
|
|
|
*/
|
|
|
$.className = function(className) {
|
|
|
return $.classNamePrefix + className;
|
|
|
};
|
|
|
/**
|
|
|
* 返回正确的classSelector
|
|
|
* @param {type} classSelector
|
|
|
* @returns {String}
|
|
|
*/
|
|
|
$.classSelector = function(classSelector) {
|
|
|
return classSelector.replace(/\./g, $.classSelectorPrefix);
|
|
|
};
|
|
|
/**
|
|
|
* 返回正确的eventName
|
|
|
* @param {type} event
|
|
|
* @param {type} module
|
|
|
* @returns {String}
|
|
|
*/
|
|
|
$.eventName = function(event, module) {
|
|
|
return event + ($.namespace ? ('.' + $.namespace) : '') + ( module ? ('.' + module) : '');
|
|
|
};
|
|
|
})(mui);
|
|
|
|
|
|
/**
|
|
|
* mui gestures
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window) {
|
|
|
$.gestures = {
|
|
|
session: {}
|
|
|
};
|
|
|
/**
|
|
|
* Gesture preventDefault
|
|
|
* @param {type} e
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
$.preventDefault = function(e) {
|
|
|
e.preventDefault();
|
|
|
};
|
|
|
/**
|
|
|
* Gesture stopPropagation
|
|
|
* @param {type} e
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
$.stopPropagation = function(e) {
|
|
|
e.stopPropagation();
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* register gesture
|
|
|
* @param {type} gesture
|
|
|
* @returns {$.gestures}
|
|
|
*/
|
|
|
$.addGesture = function(gesture) {
|
|
|
return $.addAction('gestures', gesture);
|
|
|
|
|
|
};
|
|
|
|
|
|
var round = Math.round;
|
|
|
var abs = Math.abs;
|
|
|
var sqrt = Math.sqrt;
|
|
|
var atan = Math.atan;
|
|
|
var atan2 = Math.atan2;
|
|
|
/**
|
|
|
* distance
|
|
|
* @param {type} p1
|
|
|
* @param {type} p2
|
|
|
* @returns {Number}
|
|
|
*/
|
|
|
var getDistance = function(p1, p2, props) {
|
|
|
if(!props) {
|
|
|
props = ['x', 'y'];
|
|
|
}
|
|
|
var x = p2[props[0]] - p1[props[0]];
|
|
|
var y = p2[props[1]] - p1[props[1]];
|
|
|
return sqrt((x * x) + (y * y));
|
|
|
};
|
|
|
/**
|
|
|
* scale
|
|
|
* @param {Object} starts
|
|
|
* @param {Object} moves
|
|
|
*/
|
|
|
var getScale = function(starts, moves) {
|
|
|
if(starts.length >= 2 && moves.length >= 2) {
|
|
|
var props = ['pageX', 'pageY'];
|
|
|
return getDistance(moves[1], moves[0], props) / getDistance(starts[1], starts[0], props);
|
|
|
}
|
|
|
return 1;
|
|
|
};
|
|
|
/**
|
|
|
* angle
|
|
|
* @param {type} p1
|
|
|
* @param {type} p2
|
|
|
* @returns {Number}
|
|
|
*/
|
|
|
var getAngle = function(p1, p2, props) {
|
|
|
if(!props) {
|
|
|
props = ['x', 'y'];
|
|
|
}
|
|
|
var x = p2[props[0]] - p1[props[0]];
|
|
|
var y = p2[props[1]] - p1[props[1]];
|
|
|
return atan2(y, x) * 180 / Math.PI;
|
|
|
};
|
|
|
/**
|
|
|
* direction
|
|
|
* @param {Object} x
|
|
|
* @param {Object} y
|
|
|
*/
|
|
|
var getDirection = function(x, y) {
|
|
|
if(x === y) {
|
|
|
return '';
|
|
|
}
|
|
|
if(abs(x) >= abs(y)) {
|
|
|
return x > 0 ? 'left' : 'right';
|
|
|
}
|
|
|
return y > 0 ? 'up' : 'down';
|
|
|
};
|
|
|
/**
|
|
|
* rotation
|
|
|
* @param {Object} start
|
|
|
* @param {Object} end
|
|
|
*/
|
|
|
var getRotation = function(start, end) {
|
|
|
var props = ['pageX', 'pageY'];
|
|
|
return getAngle(end[1], end[0], props) - getAngle(start[1], start[0], props);
|
|
|
};
|
|
|
/**
|
|
|
* px per ms
|
|
|
* @param {Object} deltaTime
|
|
|
* @param {Object} x
|
|
|
* @param {Object} y
|
|
|
*/
|
|
|
var getVelocity = function(deltaTime, x, y) {
|
|
|
return {
|
|
|
x: x / deltaTime || 0,
|
|
|
y: y / deltaTime || 0
|
|
|
};
|
|
|
};
|
|
|
/**
|
|
|
* detect gestures
|
|
|
* @param {type} event
|
|
|
* @param {type} touch
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
var detect = function(event, touch) {
|
|
|
if($.gestures.stoped) {
|
|
|
return;
|
|
|
}
|
|
|
$.doAction('gestures', function(index, gesture) {
|
|
|
if(!$.gestures.stoped) {
|
|
|
if($.options.gestureConfig[gesture.name] !== false) {
|
|
|
gesture.handle(event, touch);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
/**
|
|
|
* 暂时无用
|
|
|
* @param {Object} node
|
|
|
* @param {Object} parent
|
|
|
*/
|
|
|
var hasParent = function(node, parent) {
|
|
|
while(node) {
|
|
|
if(node == parent) {
|
|
|
return true;
|
|
|
}
|
|
|
node = node.parentNode;
|
|
|
}
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
var uniqueArray = function(src, key, sort) {
|
|
|
var results = [];
|
|
|
var values = [];
|
|
|
var i = 0;
|
|
|
|
|
|
while(i < src.length) {
|
|
|
var val = key ? src[i][key] : src[i];
|
|
|
if(values.indexOf(val) < 0) {
|
|
|
results.push(src[i]);
|
|
|
}
|
|
|
values[i] = val;
|
|
|
i++;
|
|
|
}
|
|
|
|
|
|
if(sort) {
|
|
|
if(!key) {
|
|
|
results = results.sort();
|
|
|
} else {
|
|
|
results = results.sort(function sortUniqueArray(a, b) {
|
|
|
return a[key] > b[key];
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return results;
|
|
|
};
|
|
|
var getMultiCenter = function(touches) {
|
|
|
var touchesLength = touches.length;
|
|
|
if(touchesLength === 1) {
|
|
|
return {
|
|
|
x: round(touches[0].pageX),
|
|
|
y: round(touches[0].pageY)
|
|
|
};
|
|
|
}
|
|
|
|
|
|
var x = 0;
|
|
|
var y = 0;
|
|
|
var i = 0;
|
|
|
while(i < touchesLength) {
|
|
|
x += touches[i].pageX;
|
|
|
y += touches[i].pageY;
|
|
|
i++;
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
x: round(x / touchesLength),
|
|
|
y: round(y / touchesLength)
|
|
|
};
|
|
|
};
|
|
|
var multiTouch = function() {
|
|
|
return $.options.gestureConfig.pinch;
|
|
|
};
|
|
|
var copySimpleTouchData = function(touch) {
|
|
|
var touches = [];
|
|
|
var i = 0;
|
|
|
while(i < touch.touches.length) {
|
|
|
touches[i] = {
|
|
|
pageX: round(touch.touches[i].pageX),
|
|
|
pageY: round(touch.touches[i].pageY)
|
|
|
};
|
|
|
i++;
|
|
|
}
|
|
|
return {
|
|
|
timestamp: $.now(),
|
|
|
gesture: touch.gesture,
|
|
|
touches: touches,
|
|
|
center: getMultiCenter(touch.touches),
|
|
|
deltaX: touch.deltaX,
|
|
|
deltaY: touch.deltaY
|
|
|
};
|
|
|
};
|
|
|
|
|
|
var calDelta = function(touch) {
|
|
|
var session = $.gestures.session;
|
|
|
var center = touch.center;
|
|
|
var offset = session.offsetDelta || {};
|
|
|
var prevDelta = session.prevDelta || {};
|
|
|
var prevTouch = session.prevTouch || {};
|
|
|
|
|
|
if(touch.gesture.type === $.EVENT_START || touch.gesture.type === $.EVENT_END) {
|
|
|
prevDelta = session.prevDelta = {
|
|
|
x: prevTouch.deltaX || 0,
|
|
|
y: prevTouch.deltaY || 0
|
|
|
};
|
|
|
|
|
|
offset = session.offsetDelta = {
|
|
|
x: center.x,
|
|
|
y: center.y
|
|
|
};
|
|
|
}
|
|
|
touch.deltaX = prevDelta.x + (center.x - offset.x);
|
|
|
touch.deltaY = prevDelta.y + (center.y - offset.y);
|
|
|
};
|
|
|
var calTouchData = function(touch) {
|
|
|
var session = $.gestures.session;
|
|
|
var touches = touch.touches;
|
|
|
var touchesLength = touches.length;
|
|
|
|
|
|
if(!session.firstTouch) {
|
|
|
session.firstTouch = copySimpleTouchData(touch);
|
|
|
}
|
|
|
|
|
|
if(multiTouch() && touchesLength > 1 && !session.firstMultiTouch) {
|
|
|
session.firstMultiTouch = copySimpleTouchData(touch);
|
|
|
} else if(touchesLength === 1) {
|
|
|
session.firstMultiTouch = false;
|
|
|
}
|
|
|
|
|
|
var firstTouch = session.firstTouch;
|
|
|
var firstMultiTouch = session.firstMultiTouch;
|
|
|
var offsetCenter = firstMultiTouch ? firstMultiTouch.center : firstTouch.center;
|
|
|
|
|
|
var center = touch.center = getMultiCenter(touches);
|
|
|
touch.timestamp = $.now();
|
|
|
touch.deltaTime = touch.timestamp - firstTouch.timestamp;
|
|
|
|
|
|
touch.angle = getAngle(offsetCenter, center);
|
|
|
touch.distance = getDistance(offsetCenter, center);
|
|
|
|
|
|
calDelta(touch);
|
|
|
|
|
|
touch.offsetDirection = getDirection(touch.deltaX, touch.deltaY);
|
|
|
|
|
|
touch.scale = firstMultiTouch ? getScale(firstMultiTouch.touches, touches) : 1;
|
|
|
touch.rotation = firstMultiTouch ? getRotation(firstMultiTouch.touches, touches) : 0;
|
|
|
|
|
|
calIntervalTouchData(touch);
|
|
|
|
|
|
};
|
|
|
var CAL_INTERVAL = 25;
|
|
|
var calIntervalTouchData = function(touch) {
|
|
|
var session = $.gestures.session;
|
|
|
var last = session.lastInterval || touch;
|
|
|
var deltaTime = touch.timestamp - last.timestamp;
|
|
|
var velocity;
|
|
|
var velocityX;
|
|
|
var velocityY;
|
|
|
var direction;
|
|
|
|
|
|
if(touch.gesture.type != $.EVENT_CANCEL && (deltaTime > CAL_INTERVAL || last.velocity === undefined)) {
|
|
|
var deltaX = last.deltaX - touch.deltaX;
|
|
|
var deltaY = last.deltaY - touch.deltaY;
|
|
|
|
|
|
var v = getVelocity(deltaTime, deltaX, deltaY);
|
|
|
velocityX = v.x;
|
|
|
velocityY = v.y;
|
|
|
velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
|
|
|
direction = getDirection(deltaX, deltaY) || last.direction;
|
|
|
|
|
|
session.lastInterval = touch;
|
|
|
} else {
|
|
|
velocity = last.velocity;
|
|
|
velocityX = last.velocityX;
|
|
|
velocityY = last.velocityY;
|
|
|
direction = last.direction;
|
|
|
}
|
|
|
|
|
|
touch.velocity = velocity;
|
|
|
touch.velocityX = velocityX;
|
|
|
touch.velocityY = velocityY;
|
|
|
touch.direction = direction;
|
|
|
};
|
|
|
var targetIds = {};
|
|
|
var convertTouches = function(touches) {
|
|
|
for(var i = 0; i < touches.length; i++) {
|
|
|
!touches['identifier'] && (touches['identifier'] = 0);
|
|
|
}
|
|
|
return touches;
|
|
|
};
|
|
|
var getTouches = function(event, touch) {
|
|
|
var allTouches = convertTouches($.slice.call(event.touches || [event]));
|
|
|
|
|
|
var type = event.type;
|
|
|
|
|
|
var targetTouches = [];
|
|
|
var changedTargetTouches = [];
|
|
|
|
|
|
//当touchstart或touchmove且touches长度为1,直接获得all和changed
|
|
|
if((type === $.EVENT_START || type === $.EVENT_MOVE) && allTouches.length === 1) {
|
|
|
targetIds[allTouches[0].identifier] = true;
|
|
|
targetTouches = allTouches;
|
|
|
changedTargetTouches = allTouches;
|
|
|
touch.target = event.target;
|
|
|
} else {
|
|
|
var i = 0;
|
|
|
var targetTouches = [];
|
|
|
var changedTargetTouches = [];
|
|
|
var changedTouches = convertTouches($.slice.call(event.changedTouches || [event]));
|
|
|
|
|
|
touch.target = event.target;
|
|
|
var sessionTarget = $.gestures.session.target || event.target;
|
|
|
targetTouches = allTouches.filter(function(touch) {
|
|
|
return hasParent(touch.target, sessionTarget);
|
|
|
});
|
|
|
|
|
|
if(type === $.EVENT_START) {
|
|
|
i = 0;
|
|
|
while(i < targetTouches.length) {
|
|
|
targetIds[targetTouches[i].identifier] = true;
|
|
|
i++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
i = 0;
|
|
|
while(i < changedTouches.length) {
|
|
|
if(targetIds[changedTouches[i].identifier]) {
|
|
|
changedTargetTouches.push(changedTouches[i]);
|
|
|
}
|
|
|
if(type === $.EVENT_END || type === $.EVENT_CANCEL) {
|
|
|
delete targetIds[changedTouches[i].identifier];
|
|
|
}
|
|
|
i++;
|
|
|
}
|
|
|
|
|
|
if(!changedTargetTouches.length) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
targetTouches = uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true);
|
|
|
var touchesLength = targetTouches.length;
|
|
|
var changedTouchesLength = changedTargetTouches.length;
|
|
|
if(type === $.EVENT_START && touchesLength - changedTouchesLength === 0) { //first
|
|
|
touch.isFirst = true;
|
|
|
$.gestures.touch = $.gestures.session = {
|
|
|
target: event.target
|
|
|
};
|
|
|
}
|
|
|
touch.isFinal = ((type === $.EVENT_END || type === $.EVENT_CANCEL) && (touchesLength - changedTouchesLength === 0));
|
|
|
|
|
|
touch.touches = targetTouches;
|
|
|
touch.changedTouches = changedTargetTouches;
|
|
|
return true;
|
|
|
|
|
|
};
|
|
|
var handleTouchEvent = function(event) {
|
|
|
var touch = {
|
|
|
gesture: event
|
|
|
};
|
|
|
var touches = getTouches(event, touch);
|
|
|
if(!touches) {
|
|
|
return;
|
|
|
}
|
|
|
calTouchData(touch);
|
|
|
detect(event, touch);
|
|
|
$.gestures.session.prevTouch = touch;
|
|
|
if(event.type === $.EVENT_END && !$.isTouchable) {
|
|
|
$.gestures.touch = $.gestures.session = {};
|
|
|
}
|
|
|
};
|
|
|
var supportsPassive = (function checkPassiveListener() {
|
|
|
var supportsPassive = false;
|
|
|
try {
|
|
|
var opts = Object.defineProperty({}, 'passive', {
|
|
|
get: function get() {
|
|
|
supportsPassive = true;
|
|
|
},
|
|
|
});
|
|
|
window.addEventListener('testPassiveListener', null, opts);
|
|
|
} catch(e) {
|
|
|
// No support
|
|
|
}
|
|
|
return supportsPassive;
|
|
|
}())
|
|
|
window.addEventListener($.EVENT_START, handleTouchEvent);
|
|
|
window.addEventListener($.EVENT_MOVE, handleTouchEvent, supportsPassive ? {
|
|
|
passive: false,
|
|
|
capture: false
|
|
|
} : false);
|
|
|
window.addEventListener($.EVENT_END, handleTouchEvent);
|
|
|
window.addEventListener($.EVENT_CANCEL, handleTouchEvent);
|
|
|
//fixed hashchange(android)
|
|
|
window.addEventListener($.EVENT_CLICK, function(e) {
|
|
|
//TODO 应该判断当前target是不是在targets.popover内部,而不是非要相等
|
|
|
if(($.os.android || $.os.ios) && (($.targets.popover && e.target === $.targets.popover) || ($.targets.tab) || $.targets.offcanvas || $.targets.modal)) {
|
|
|
e.preventDefault();
|
|
|
}
|
|
|
}, true);
|
|
|
|
|
|
//增加原生滚动识别
|
|
|
$.isScrolling = false;
|
|
|
var scrollingTimeout = null;
|
|
|
window.addEventListener('scroll', function() {
|
|
|
$.isScrolling = true;
|
|
|
scrollingTimeout && clearTimeout(scrollingTimeout);
|
|
|
scrollingTimeout = setTimeout(function() {
|
|
|
$.isScrolling = false;
|
|
|
}, 250);
|
|
|
});
|
|
|
})(mui, window);
|
|
|
/**
|
|
|
* mui gesture flick[left|right|up|down]
|
|
|
* @param {type} $
|
|
|
* @param {type} name
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, name) {
|
|
|
var flickStartTime = 0;
|
|
|
var handle = function(event, touch) {
|
|
|
var session = $.gestures.session;
|
|
|
var options = this.options;
|
|
|
var now = $.now();
|
|
|
switch (event.type) {
|
|
|
case $.EVENT_MOVE:
|
|
|
if (now - flickStartTime > 300) {
|
|
|
flickStartTime = now;
|
|
|
session.flickStart = touch.center;
|
|
|
}
|
|
|
break;
|
|
|
case $.EVENT_END:
|
|
|
case $.EVENT_CANCEL:
|
|
|
touch.flick = false;
|
|
|
if (session.flickStart && options.flickMaxTime > (now - flickStartTime) && touch.distance > options.flickMinDistince) {
|
|
|
touch.flick = true;
|
|
|
touch.flickTime = now - flickStartTime;
|
|
|
touch.flickDistanceX = touch.center.x - session.flickStart.x;
|
|
|
touch.flickDistanceY = touch.center.y - session.flickStart.y;
|
|
|
$.trigger(session.target, name, touch);
|
|
|
$.trigger(session.target, name + touch.direction, touch);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
};
|
|
|
/**
|
|
|
* mui gesture flick
|
|
|
*/
|
|
|
$.addGesture({
|
|
|
name: name,
|
|
|
index: 5,
|
|
|
handle: handle,
|
|
|
options: {
|
|
|
flickMaxTime: 200,
|
|
|
flickMinDistince: 10
|
|
|
}
|
|
|
});
|
|
|
})(mui, 'flick');
|
|
|
/**
|
|
|
* mui gesture swipe[left|right|up|down]
|
|
|
* @param {type} $
|
|
|
* @param {type} name
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, name) {
|
|
|
var handle = function(event, touch) {
|
|
|
var session = $.gestures.session;
|
|
|
if (event.type === $.EVENT_END || event.type === $.EVENT_CANCEL) {
|
|
|
var options = this.options;
|
|
|
touch.swipe = false;
|
|
|
//TODO 后续根据velocity计算
|
|
|
if (touch.direction && options.swipeMaxTime > touch.deltaTime && touch.distance > options.swipeMinDistince) {
|
|
|
touch.swipe = true;
|
|
|
$.trigger(session.target, name, touch);
|
|
|
$.trigger(session.target, name + touch.direction, touch);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
/**
|
|
|
* mui gesture swipe
|
|
|
*/
|
|
|
$.addGesture({
|
|
|
name: name,
|
|
|
index: 10,
|
|
|
handle: handle,
|
|
|
options: {
|
|
|
swipeMaxTime: 300,
|
|
|
swipeMinDistince: 18
|
|
|
}
|
|
|
});
|
|
|
})(mui, 'swipe');
|
|
|
/**
|
|
|
* mui gesture drag[start|left|right|up|down|end]
|
|
|
* @param {type} $
|
|
|
* @param {type} name
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, name) {
|
|
|
var handle = function(event, touch) {
|
|
|
var session = $.gestures.session;
|
|
|
switch (event.type) {
|
|
|
case $.EVENT_START:
|
|
|
break;
|
|
|
case $.EVENT_MOVE:
|
|
|
if (!touch.direction || !session.target) {
|
|
|
return;
|
|
|
}
|
|
|
//修正direction,可在session期间自行锁定拖拽方向,方便开发scroll类不同方向拖拽插件嵌套
|
|
|
if (session.lockDirection && session.startDirection) {
|
|
|
if (session.startDirection && session.startDirection !== touch.direction) {
|
|
|
if (session.startDirection === 'up' || session.startDirection === 'down') {
|
|
|
touch.direction = touch.deltaY < 0 ? 'up' : 'down';
|
|
|
} else {
|
|
|
touch.direction = touch.deltaX < 0 ? 'left' : 'right';
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (!session.drag) {
|
|
|
session.drag = true;
|
|
|
$.trigger(session.target, name + 'start', touch);
|
|
|
}
|
|
|
$.trigger(session.target, name, touch);
|
|
|
$.trigger(session.target, name + touch.direction, touch);
|
|
|
break;
|
|
|
case $.EVENT_END:
|
|
|
case $.EVENT_CANCEL:
|
|
|
if (session.drag && touch.isFinal) {
|
|
|
$.trigger(session.target, name + 'end', touch);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
};
|
|
|
/**
|
|
|
* mui gesture drag
|
|
|
*/
|
|
|
$.addGesture({
|
|
|
name: name,
|
|
|
index: 20,
|
|
|
handle: handle,
|
|
|
options: {
|
|
|
fingers: 1
|
|
|
}
|
|
|
});
|
|
|
})(mui, 'drag');
|
|
|
/**
|
|
|
* mui gesture tap and doubleTap
|
|
|
* @param {type} $
|
|
|
* @param {type} name
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, name) {
|
|
|
var lastTarget;
|
|
|
var lastTapTime;
|
|
|
var handle = function(event, touch) {
|
|
|
var session = $.gestures.session;
|
|
|
var options = this.options;
|
|
|
switch (event.type) {
|
|
|
case $.EVENT_END:
|
|
|
if (!touch.isFinal) {
|
|
|
return;
|
|
|
}
|
|
|
var target = session.target;
|
|
|
if (!target || (target.disabled || (target.classList && target.classList.contains('mui-disabled')))) {
|
|
|
return;
|
|
|
}
|
|
|
if (touch.distance < options.tapMaxDistance && touch.deltaTime < options.tapMaxTime) {
|
|
|
if ($.options.gestureConfig.doubletap && lastTarget && (lastTarget === target)) { //same target
|
|
|
if (lastTapTime && (touch.timestamp - lastTapTime) < options.tapMaxInterval) {
|
|
|
$.trigger(target, 'doubletap', touch);
|
|
|
lastTapTime = $.now();
|
|
|
lastTarget = target;
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
$.trigger(target, name, touch);
|
|
|
lastTapTime = $.now();
|
|
|
lastTarget = target;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
};
|
|
|
/**
|
|
|
* mui gesture tap
|
|
|
*/
|
|
|
$.addGesture({
|
|
|
name: name,
|
|
|
index: 30,
|
|
|
handle: handle,
|
|
|
options: {
|
|
|
fingers: 1,
|
|
|
tapMaxInterval: 300,
|
|
|
tapMaxDistance: 5,
|
|
|
tapMaxTime: 250
|
|
|
}
|
|
|
});
|
|
|
})(mui, 'tap');
|
|
|
/**
|
|
|
* mui gesture longtap
|
|
|
* @param {type} $
|
|
|
* @param {type} name
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, name) {
|
|
|
var timer;
|
|
|
var handle = function(event, touch) {
|
|
|
var session = $.gestures.session;
|
|
|
var options = this.options;
|
|
|
switch (event.type) {
|
|
|
case $.EVENT_START:
|
|
|
clearTimeout(timer);
|
|
|
timer = setTimeout(function() {
|
|
|
$.trigger(session.target, name, touch);
|
|
|
}, options.holdTimeout);
|
|
|
break;
|
|
|
case $.EVENT_MOVE:
|
|
|
if (touch.distance > options.holdThreshold) {
|
|
|
clearTimeout(timer);
|
|
|
}
|
|
|
break;
|
|
|
case $.EVENT_END:
|
|
|
case $.EVENT_CANCEL:
|
|
|
clearTimeout(timer);
|
|
|
break;
|
|
|
}
|
|
|
};
|
|
|
/**
|
|
|
* mui gesture longtap
|
|
|
*/
|
|
|
$.addGesture({
|
|
|
name: name,
|
|
|
index: 10,
|
|
|
handle: handle,
|
|
|
options: {
|
|
|
fingers: 1,
|
|
|
holdTimeout: 500,
|
|
|
holdThreshold: 2
|
|
|
}
|
|
|
});
|
|
|
})(mui, 'longtap');
|
|
|
/**
|
|
|
* mui gesture hold
|
|
|
* @param {type} $
|
|
|
* @param {type} name
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, name) {
|
|
|
var timer;
|
|
|
var handle = function(event, touch) {
|
|
|
var session = $.gestures.session;
|
|
|
var options = this.options;
|
|
|
switch (event.type) {
|
|
|
case $.EVENT_START:
|
|
|
if ($.options.gestureConfig.hold) {
|
|
|
timer && clearTimeout(timer);
|
|
|
timer = setTimeout(function() {
|
|
|
touch.hold = true;
|
|
|
$.trigger(session.target, name, touch);
|
|
|
}, options.holdTimeout);
|
|
|
}
|
|
|
break;
|
|
|
case $.EVENT_MOVE:
|
|
|
break;
|
|
|
case $.EVENT_END:
|
|
|
case $.EVENT_CANCEL:
|
|
|
if (timer) {
|
|
|
clearTimeout(timer) && (timer = null);
|
|
|
$.trigger(session.target, 'release', touch);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
};
|
|
|
/**
|
|
|
* mui gesture hold
|
|
|
*/
|
|
|
$.addGesture({
|
|
|
name: name,
|
|
|
index: 10,
|
|
|
handle: handle,
|
|
|
options: {
|
|
|
fingers: 1,
|
|
|
holdTimeout: 0
|
|
|
}
|
|
|
});
|
|
|
})(mui, 'hold');
|
|
|
/**
|
|
|
* mui gesture pinch
|
|
|
* @param {type} $
|
|
|
* @param {type} name
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, name) {
|
|
|
var handle = function(event, touch) {
|
|
|
var options = this.options;
|
|
|
var session = $.gestures.session;
|
|
|
switch (event.type) {
|
|
|
case $.EVENT_START:
|
|
|
break;
|
|
|
case $.EVENT_MOVE:
|
|
|
if ($.options.gestureConfig.pinch) {
|
|
|
if (touch.touches.length < 2) {
|
|
|
return;
|
|
|
}
|
|
|
if (!session.pinch) { //start
|
|
|
session.pinch = true;
|
|
|
$.trigger(session.target, name + 'start', touch);
|
|
|
}
|
|
|
$.trigger(session.target, name, touch);
|
|
|
var scale = touch.scale;
|
|
|
var rotation = touch.rotation;
|
|
|
var lastScale = typeof touch.lastScale === 'undefined' ? 1 : touch.lastScale;
|
|
|
var scaleDiff = 0.000000000001; //防止scale与lastScale相等,不触发事件的情况。
|
|
|
if (scale > lastScale) { //out
|
|
|
lastScale = scale - scaleDiff;
|
|
|
$.trigger(session.target, name + 'out', touch);
|
|
|
} //in
|
|
|
else if (scale < lastScale) {
|
|
|
lastScale = scale + scaleDiff;
|
|
|
$.trigger(session.target, name + 'in', touch);
|
|
|
}
|
|
|
if (Math.abs(rotation) > options.minRotationAngle) {
|
|
|
$.trigger(session.target, 'rotate', touch);
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
case $.EVENT_END:
|
|
|
case $.EVENT_CANCEL:
|
|
|
if ($.options.gestureConfig.pinch && session.pinch && touch.touches.length === 2) {
|
|
|
session.pinch = false;
|
|
|
$.trigger(session.target, name + 'end', touch);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
};
|
|
|
/**
|
|
|
* mui gesture pinch
|
|
|
*/
|
|
|
$.addGesture({
|
|
|
name: name,
|
|
|
index: 10,
|
|
|
handle: handle,
|
|
|
options: {
|
|
|
minRotationAngle: 0
|
|
|
}
|
|
|
});
|
|
|
})(mui, 'pinch');
|
|
|
/**
|
|
|
* mui.init
|
|
|
* @param {type} $
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($) {
|
|
|
$.global = $.options = {
|
|
|
gestureConfig: {
|
|
|
tap: true,
|
|
|
doubletap: false,
|
|
|
longtap: false,
|
|
|
hold: false,
|
|
|
flick: true,
|
|
|
swipe: true,
|
|
|
drag: true,
|
|
|
pinch: false
|
|
|
}
|
|
|
};
|
|
|
/**
|
|
|
*
|
|
|
* @param {type} options
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
$.initGlobal = function(options) {
|
|
|
$.options = $.extend(true, $.global, options);
|
|
|
return this;
|
|
|
};
|
|
|
var inits = {};
|
|
|
|
|
|
/**
|
|
|
* 单页配置 初始化
|
|
|
* @param {object} options
|
|
|
*/
|
|
|
$.init = function(options) {
|
|
|
$.options = $.extend(true, $.global, options || {});
|
|
|
$.ready(function() {
|
|
|
$.doAction('inits', function(index, init) {
|
|
|
var isInit = !!(!inits[init.name] || init.repeat);
|
|
|
if (isInit) {
|
|
|
init.handle.call($);
|
|
|
inits[init.name] = true;
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
return this;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 增加初始化执行流程
|
|
|
* @param {function} init
|
|
|
*/
|
|
|
$.addInit = function(init) {
|
|
|
return $.addAction('inits', init);
|
|
|
};
|
|
|
/**
|
|
|
* 处理html5版本subpages
|
|
|
*/
|
|
|
$.addInit({
|
|
|
name: 'iframe',
|
|
|
index: 100,
|
|
|
handle: function() {
|
|
|
var options = $.options;
|
|
|
var subpages = options.subpages || [];
|
|
|
if (!$.os.plus && subpages.length) {
|
|
|
//暂时只处理单个subpage。后续可以考虑支持多个subpage
|
|
|
createIframe(subpages[0]);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
var createIframe = function(options) {
|
|
|
var wrapper = document.createElement('div');
|
|
|
wrapper.className = 'mui-iframe-wrapper';
|
|
|
var styles = options.styles || {};
|
|
|
if (typeof styles.top !== 'string') {
|
|
|
styles.top = '0px';
|
|
|
}
|
|
|
if (typeof styles.bottom !== 'string') {
|
|
|
styles.bottom = '0px';
|
|
|
}
|
|
|
wrapper.style.top = styles.top;
|
|
|
wrapper.style.bottom = styles.bottom;
|
|
|
var iframe = document.createElement('iframe');
|
|
|
iframe.src = options.url;
|
|
|
iframe.id = options.id || options.url;
|
|
|
iframe.name = iframe.id;
|
|
|
wrapper.appendChild(iframe);
|
|
|
document.body.appendChild(wrapper);
|
|
|
//目前仅处理微信
|
|
|
$.os.wechat && handleScroll(wrapper, iframe);
|
|
|
};
|
|
|
|
|
|
function handleScroll(wrapper, iframe) {
|
|
|
var key = 'MUI_SCROLL_POSITION_' + document.location.href + '_' + iframe.src;
|
|
|
var scrollTop = (parseFloat(localStorage.getItem(key)) || 0);
|
|
|
if (scrollTop) {
|
|
|
(function(y) {
|
|
|
iframe.onload = function() {
|
|
|
window.scrollTo(0, y);
|
|
|
};
|
|
|
})(scrollTop);
|
|
|
}
|
|
|
setInterval(function() {
|
|
|
var _scrollTop = window.scrollY;
|
|
|
if (scrollTop !== _scrollTop) {
|
|
|
localStorage.setItem(key, _scrollTop + '');
|
|
|
scrollTop = _scrollTop;
|
|
|
}
|
|
|
}, 100);
|
|
|
};
|
|
|
$(function() {
|
|
|
var classList = document.body.classList;
|
|
|
var os = [];
|
|
|
if ($.os.ios) {
|
|
|
os.push({
|
|
|
os: 'ios',
|
|
|
version: $.os.version
|
|
|
});
|
|
|
classList.add('mui-ios');
|
|
|
} else if ($.os.android) {
|
|
|
os.push({
|
|
|
os: 'android',
|
|
|
version: $.os.version
|
|
|
});
|
|
|
classList.add('mui-android');
|
|
|
}
|
|
|
if ($.os.wechat) {
|
|
|
os.push({
|
|
|
os: 'wechat',
|
|
|
version: $.os.wechat.version
|
|
|
});
|
|
|
classList.add('mui-wechat');
|
|
|
}
|
|
|
if (os.length) {
|
|
|
$.each(os, function(index, osObj) {
|
|
|
var version = '';
|
|
|
var classArray = [];
|
|
|
if (osObj.version) {
|
|
|
$.each(osObj.version.split('.'), function(i, v) {
|
|
|
version = version + (version ? '-' : '') + v;
|
|
|
classList.add($.className(osObj.os + '-' + version));
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
})(mui);
|
|
|
/**
|
|
|
* mui.init 5+
|
|
|
* @param {type} $
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($) {
|
|
|
var defaultOptions = {
|
|
|
swipeBack: false,
|
|
|
preloadPages: [], //5+ lazyLoad webview
|
|
|
preloadLimit: 10, //预加载窗口的数量限制(一旦超出,先进先出)
|
|
|
keyEventBind: {
|
|
|
backbutton: true,
|
|
|
menubutton: true
|
|
|
},
|
|
|
titleConfig: {
|
|
|
height: "44px",
|
|
|
backgroundColor: "#f7f7f7", //导航栏背景色
|
|
|
bottomBorderColor: "#cccccc", //底部边线颜色
|
|
|
title: { //标题配置
|
|
|
text: "", //标题文字
|
|
|
position: {
|
|
|
top: 0,
|
|
|
left: 0,
|
|
|
width: "100%",
|
|
|
height: "100%"
|
|
|
},
|
|
|
styles: {
|
|
|
color: "#000000",
|
|
|
align: "center",
|
|
|
family: "'Helvetica Neue',Helvetica,sans-serif",
|
|
|
size: "17px",
|
|
|
style: "normal",
|
|
|
weight: "normal",
|
|
|
fontSrc: ""
|
|
|
}
|
|
|
},
|
|
|
back: {
|
|
|
image: {
|
|
|
base64Data: '',
|
|
|
imgSrc: '',
|
|
|
sprite: {
|
|
|
top: '0px',
|
|
|
left: '0px',
|
|
|
width: '100%',
|
|
|
height: '100%'
|
|
|
},
|
|
|
position: {
|
|
|
top: "10px",
|
|
|
left: "10px",
|
|
|
width: "24px",
|
|
|
height: "24px"
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
//默认页面动画
|
|
|
var defaultShow = {
|
|
|
event:"titleUpdate",
|
|
|
autoShow: true,
|
|
|
duration: 300,
|
|
|
aniShow: 'slide-in-right',
|
|
|
extras:{}
|
|
|
};
|
|
|
//若执行了显示动画初始化操作,则要覆盖默认配置
|
|
|
if($.options.show) {
|
|
|
defaultShow = $.extend(true, defaultShow, $.options.show);
|
|
|
}
|
|
|
|
|
|
$.currentWebview = null;
|
|
|
|
|
|
$.extend(true, $.global, defaultOptions);
|
|
|
$.extend(true, $.options, defaultOptions);
|
|
|
/**
|
|
|
* 等待动画配置
|
|
|
* @param {type} options
|
|
|
* @returns {Object}
|
|
|
*/
|
|
|
$.waitingOptions = function(options) {
|
|
|
return $.extend(true, {}, {
|
|
|
autoShow: true,
|
|
|
title: '',
|
|
|
modal: false
|
|
|
}, options);
|
|
|
};
|
|
|
/**
|
|
|
* 窗口显示配置
|
|
|
* @param {type} options
|
|
|
* @returns {Object}
|
|
|
*/
|
|
|
$.showOptions = function(options) {
|
|
|
return $.extend(true, {}, defaultShow, options);
|
|
|
};
|
|
|
/**
|
|
|
* 窗口默认配置
|
|
|
* @param {type} options
|
|
|
* @returns {Object}
|
|
|
*/
|
|
|
$.windowOptions = function(options) {
|
|
|
return $.extend({
|
|
|
scalable: false,
|
|
|
bounce: "" //vertical
|
|
|
}, options);
|
|
|
};
|
|
|
/**
|
|
|
* plusReady
|
|
|
* @param {type} callback
|
|
|
* @returns {_L6.$}
|
|
|
*/
|
|
|
$.plusReady = function(callback) {
|
|
|
if(window.plus) {
|
|
|
setTimeout(function() { //解决callback与plusready事件的执行时机问题(典型案例:showWaiting,closeWaiting)
|
|
|
callback();
|
|
|
}, 0);
|
|
|
} else {
|
|
|
document.addEventListener("plusready", function() {
|
|
|
callback();
|
|
|
}, false);
|
|
|
}
|
|
|
return this;
|
|
|
};
|
|
|
/**
|
|
|
* 5+ event(5+没提供之前我自己实现)
|
|
|
* @param {type} webview
|
|
|
* @param {type} eventType
|
|
|
* @param {type} data
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
$.fire = function(webview, eventType, data) {
|
|
|
if(webview) {
|
|
|
if(typeof data === 'undefined') {
|
|
|
data = '';
|
|
|
} else if(typeof data === 'boolean' || typeof data === 'number') {
|
|
|
webview.evalJS("typeof mui!=='undefined'&&mui.receive('" + eventType + "'," + data + ")");
|
|
|
return;
|
|
|
} else if($.isPlainObject(data) || $.isArray(data)) {
|
|
|
data = JSON.stringify(data || {}).replace(/\'/g, "\\u0027").replace(/\\/g, "\\u005c");
|
|
|
}
|
|
|
webview.evalJS("typeof mui!=='undefined'&&mui.receive('" + eventType + "','" + data + "')");
|
|
|
}
|
|
|
};
|
|
|
/**
|
|
|
* 5+ event(5+没提供之前我自己实现)
|
|
|
* @param {type} eventType
|
|
|
* @param {type} data
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
$.receive = function(eventType, data) {
|
|
|
if(eventType) {
|
|
|
try {
|
|
|
if(data && typeof data === 'string') {
|
|
|
data = JSON.parse(data);
|
|
|
}
|
|
|
} catch(e) {}
|
|
|
$.trigger(document, eventType, data);
|
|
|
}
|
|
|
};
|
|
|
var triggerPreload = function(webview) {
|
|
|
if(!webview.preloaded) { //保证仅触发一次
|
|
|
$.fire(webview, 'preload');
|
|
|
var list = webview.children();
|
|
|
for(var i = 0; i < list.length; i++) {
|
|
|
$.fire(list[i], 'preload');
|
|
|
}
|
|
|
webview.preloaded = true;
|
|
|
}
|
|
|
};
|
|
|
var trigger = function(webview, eventType, timeChecked) {
|
|
|
if(timeChecked) {
|
|
|
if(!webview[eventType + 'ed']) {
|
|
|
$.fire(webview, eventType);
|
|
|
var list = webview.children();
|
|
|
for(var i = 0; i < list.length; i++) {
|
|
|
$.fire(list[i], eventType);
|
|
|
}
|
|
|
webview[eventType + 'ed'] = true;
|
|
|
}
|
|
|
} else {
|
|
|
$.fire(webview, eventType);
|
|
|
var list = webview.children();
|
|
|
for(var i = 0; i < list.length; i++) {
|
|
|
$.fire(list[i], eventType);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
};
|
|
|
/**
|
|
|
* 打开新窗口
|
|
|
* @param {string} url 要打开的页面地址
|
|
|
* @param {string} id 指定页面ID
|
|
|
* @param {object} options 可选:参数,等待,窗口,显示配置{params:{},waiting:{},styles:{},show:{}}
|
|
|
*/
|
|
|
$.openWindow = function(url, id, options) {
|
|
|
if(typeof url === 'object') {
|
|
|
options = url;
|
|
|
url = options.url;
|
|
|
id = options.id || url;
|
|
|
} else {
|
|
|
if(typeof id === 'object') {
|
|
|
options = id;
|
|
|
id = options.id || url;
|
|
|
} else {
|
|
|
id = id || url;
|
|
|
}
|
|
|
}
|
|
|
if(!$.os.plus) {
|
|
|
//TODO 先临时这么处理:手机上顶层跳,PC上parent跳
|
|
|
if($.os.ios || $.os.android) {
|
|
|
window.top.location.href = url;
|
|
|
} else {
|
|
|
window.parent.location.href = url;
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
if(!window.plus) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
options = options || {};
|
|
|
var params = options.params || {};
|
|
|
var webview = null,
|
|
|
webviewCache = null,
|
|
|
nShow, nWaiting;
|
|
|
|
|
|
if($.webviews[id]) {
|
|
|
webviewCache = $.webviews[id];
|
|
|
//webview真实存在,才能获取
|
|
|
if(plus.webview.getWebviewById(id)) {
|
|
|
webview = webviewCache.webview;
|
|
|
}
|
|
|
} else if(options.createNew !== true) {
|
|
|
webview = plus.webview.getWebviewById(id);
|
|
|
}
|
|
|
|
|
|
if(webview) { //已缓存
|
|
|
//每次show都需要传递动画参数;
|
|
|
//预加载的动画参数优先级:openWindow配置>preloadPages配置>mui默认配置;
|
|
|
nShow = webviewCache ? webviewCache.show : defaultShow;
|
|
|
nShow = options.show ? $.extend(nShow, options.show) : nShow;
|
|
|
nShow.autoShow && webview.show(nShow.aniShow, nShow.duration, function() {
|
|
|
triggerPreload(webview);
|
|
|
trigger(webview, 'pagebeforeshow', false);
|
|
|
});
|
|
|
if(webviewCache) {
|
|
|
webviewCache.afterShowMethodName && webview.evalJS(webviewCache.afterShowMethodName + '(\'' + JSON.stringify(params) + '\')');
|
|
|
}
|
|
|
return webview;
|
|
|
} else { //新窗口
|
|
|
if(!url) {
|
|
|
throw new Error('webview[' + id + '] does not exist');
|
|
|
}
|
|
|
|
|
|
//显示waiting
|
|
|
var waitingConfig = $.waitingOptions(options.waiting);
|
|
|
if(waitingConfig.autoShow) {
|
|
|
nWaiting = plus.nativeUI.showWaiting(waitingConfig.title, waitingConfig.options);
|
|
|
}
|
|
|
|
|
|
//创建页面
|
|
|
options = $.extend(options, {
|
|
|
id: id,
|
|
|
url: url
|
|
|
});
|
|
|
|
|
|
webview = $.createWindow(options);
|
|
|
|
|
|
//显示
|
|
|
nShow = $.showOptions(options.show);
|
|
|
if(nShow.autoShow) {
|
|
|
var showWebview = function() {
|
|
|
//关闭等待框
|
|
|
if(nWaiting) {
|
|
|
nWaiting.close();
|
|
|
}
|
|
|
//显示页面
|
|
|
webview.show(nShow.aniShow, nShow.duration, function() {},nShow.extras);
|
|
|
options.afterShowMethodName && webview.evalJS(options.afterShowMethodName + '(\'' + JSON.stringify(params) + '\')');
|
|
|
};
|
|
|
//titleUpdate触发时机早于loaded,更换为titleUpdate后,可以更早的显示webview
|
|
|
webview.addEventListener(nShow.event, showWebview, false);
|
|
|
//loaded事件发生后,触发预加载和pagebeforeshow事件
|
|
|
webview.addEventListener("loaded", function() {
|
|
|
triggerPreload(webview);
|
|
|
trigger(webview, 'pagebeforeshow', false);
|
|
|
}, false);
|
|
|
}
|
|
|
}
|
|
|
return webview;
|
|
|
};
|
|
|
|
|
|
$.openWindowWithTitle = function(options, titleConfig) {
|
|
|
options = options || {};
|
|
|
var url = options.url;
|
|
|
var id = options.id || url;
|
|
|
|
|
|
if(!$.os.plus) {
|
|
|
//TODO 先临时这么处理:手机上顶层跳,PC上parent跳
|
|
|
if($.os.ios || $.os.android) {
|
|
|
window.top.location.href = url;
|
|
|
} else {
|
|
|
window.parent.location.href = url;
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
if(!window.plus) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
var params = options.params || {};
|
|
|
var webview = null,
|
|
|
webviewCache = null,
|
|
|
nShow, nWaiting;
|
|
|
|
|
|
if($.webviews[id]) {
|
|
|
webviewCache = $.webviews[id];
|
|
|
//webview真实存在,才能获取
|
|
|
if(plus.webview.getWebviewById(id)) {
|
|
|
webview = webviewCache.webview;
|
|
|
}
|
|
|
} else if(options.createNew !== true) {
|
|
|
webview = plus.webview.getWebviewById(id);
|
|
|
}
|
|
|
|
|
|
if(webview) { //已缓存
|
|
|
//每次show都需要传递动画参数;
|
|
|
//预加载的动画参数优先级:openWindow配置>preloadPages配置>mui默认配置;
|
|
|
nShow = webviewCache ? webviewCache.show : defaultShow;
|
|
|
nShow = options.show ? $.extend(nShow, options.show) : nShow;
|
|
|
nShow.autoShow && webview.show(nShow.aniShow, nShow.duration, function() {
|
|
|
triggerPreload(webview);
|
|
|
trigger(webview, 'pagebeforeshow', false);
|
|
|
});
|
|
|
if(webviewCache) {
|
|
|
webviewCache.afterShowMethodName && webview.evalJS(webviewCache.afterShowMethodName + '(\'' + JSON.stringify(params) + '\')');
|
|
|
}
|
|
|
return webview;
|
|
|
} else { //新窗口
|
|
|
if(!url) {
|
|
|
throw new Error('webview[' + id + '] does not exist');
|
|
|
}
|
|
|
|
|
|
//显示waiting
|
|
|
var waitingConfig = $.waitingOptions(options.waiting);
|
|
|
if(waitingConfig.autoShow) {
|
|
|
nWaiting = plus.nativeUI.showWaiting(waitingConfig.title, waitingConfig.options);
|
|
|
}
|
|
|
|
|
|
//创建页面
|
|
|
options = $.extend(options, {
|
|
|
id: id,
|
|
|
url: url
|
|
|
});
|
|
|
|
|
|
webview = $.createWindow(options);
|
|
|
|
|
|
if(titleConfig) { //处理原生头
|
|
|
$.extend(true, $.options.titleConfig, titleConfig);
|
|
|
var tid = $.options.titleConfig.id ? $.options.titleConfig.id : id + "_title";
|
|
|
var view = new plus.nativeObj.View(tid, {
|
|
|
top: 0,
|
|
|
height: $.options.titleConfig.height,
|
|
|
width: "100%",
|
|
|
dock: "top",
|
|
|
position: "dock"
|
|
|
});
|
|
|
view.drawRect($.options.titleConfig.backgroundColor); //绘制背景色
|
|
|
var _b = parseInt($.options.titleConfig.height) - 1;
|
|
|
view.drawRect($.options.titleConfig.bottomBorderColor, {
|
|
|
top: _b + "px",
|
|
|
left: "0px"
|
|
|
}); //绘制底部边线
|
|
|
|
|
|
//绘制文字
|
|
|
if($.options.titleConfig.title.text){
|
|
|
var _title = $.options.titleConfig.title;
|
|
|
view.drawText(_title.text,_title.position , _title.styles);
|
|
|
}
|
|
|
|
|
|
//返回图标绘制
|
|
|
var _back = $.options.titleConfig.back;
|
|
|
var backClick = null;
|
|
|
//优先字体
|
|
|
|
|
|
//其次是图片
|
|
|
var _backImage = _back.image;
|
|
|
if(_backImage.base64Data || _backImage.imgSrc) {
|
|
|
//TODO 此处需要处理百分比的情况
|
|
|
backClick = {
|
|
|
left:parseInt(_backImage.position.left),
|
|
|
right:parseInt(_backImage.position.left) + parseInt(_backImage.position.width)
|
|
|
};
|
|
|
var bitmap = new plus.nativeObj.Bitmap(id + "_back");
|
|
|
if(_backImage.base64Data) { //优先base64编码字符串
|
|
|
bitmap.loadBase64Data(_backImage.base64Data);
|
|
|
} else { //其次加载图片文件
|
|
|
bitmap.load(_backImage.imgSrc);
|
|
|
}
|
|
|
view.drawBitmap(bitmap,_backImage.sprite , _backImage.position);
|
|
|
}
|
|
|
|
|
|
//处理点击事件
|
|
|
view.setTouchEventRect({
|
|
|
top: "0px",
|
|
|
left: "0px",
|
|
|
width: "100%",
|
|
|
height: "100%"
|
|
|
});
|
|
|
view.interceptTouchEvent(true);
|
|
|
view.addEventListener("click", function(e) {
|
|
|
var x = e.clientX;
|
|
|
|
|
|
//返回按钮点击
|
|
|
if(backClick&& x > backClick.left && x < backClick.right){
|
|
|
if( _back.click && $.isFunction(_back.click)){
|
|
|
_back.click();
|
|
|
}else{
|
|
|
webview.evalJS("window.mui&&mui.back();");
|
|
|
}
|
|
|
}
|
|
|
}, false);
|
|
|
webview.append(view);
|
|
|
|
|
|
}
|
|
|
|
|
|
//显示
|
|
|
nShow = $.showOptions(options.show);
|
|
|
if(nShow.autoShow) {
|
|
|
//titleUpdate触发时机早于loaded,更换为titleUpdate后,可以更早的显示webview
|
|
|
webview.addEventListener(nShow.event, function () {
|
|
|
//关闭等待框
|
|
|
if(nWaiting) {
|
|
|
nWaiting.close();
|
|
|
}
|
|
|
//显示页面
|
|
|
webview.show(nShow.aniShow, nShow.duration, function() {},nShow.extras);
|
|
|
}, false);
|
|
|
}
|
|
|
}
|
|
|
return webview;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 根据配置信息创建一个webview
|
|
|
* @param {type} options
|
|
|
* @param {type} isCreate
|
|
|
* @returns {webview}
|
|
|
*/
|
|
|
$.createWindow = function(options, isCreate) {
|
|
|
if(!window.plus) {
|
|
|
return;
|
|
|
}
|
|
|
var id = options.id || options.url;
|
|
|
var webview;
|
|
|
if(options.preload) {
|
|
|
if($.webviews[id] && $.webviews[id].webview.getURL()) { //已经cache
|
|
|
webview = $.webviews[id].webview;
|
|
|
} else { //新增预加载窗口
|
|
|
//判断是否携带createNew参数,默认为false
|
|
|
if(options.createNew !== true) {
|
|
|
webview = plus.webview.getWebviewById(id);
|
|
|
}
|
|
|
|
|
|
//之前没有,那就新创建
|
|
|
if(!webview) {
|
|
|
webview = plus.webview.create(options.url, id, $.windowOptions(options.styles), $.extend({
|
|
|
preload: true
|
|
|
}, options.extras));
|
|
|
if(options.subpages) {
|
|
|
$.each(options.subpages, function(index, subpage) {
|
|
|
var subpageId = subpage.id || subpage.url;
|
|
|
if(subpageId) { //过滤空对象
|
|
|
var subWebview = plus.webview.getWebviewById(subpageId);
|
|
|
if(!subWebview) { //如果该webview不存在,则创建
|
|
|
subWebview = plus.webview.create(subpage.url, subpageId, $.windowOptions(subpage.styles), $.extend({
|
|
|
preload: true
|
|
|
}, subpage.extras));
|
|
|
}
|
|
|
webview.append(subWebview);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//TODO 理论上,子webview也应该计算到预加载队列中,但这样就麻烦了,要退必须退整体,否则可能出现问题;
|
|
|
$.webviews[id] = {
|
|
|
webview: webview, //目前仅preload的缓存webview
|
|
|
preload: true,
|
|
|
show: $.showOptions(options.show),
|
|
|
afterShowMethodName: options.afterShowMethodName //就不应该用evalJS。应该是通过事件消息通讯
|
|
|
};
|
|
|
//索引该预加载窗口
|
|
|
var preloads = $.data.preloads;
|
|
|
var index = preloads.indexOf(id);
|
|
|
if(~index) { //删除已存在的(变相调整插入位置)
|
|
|
preloads.splice(index, 1);
|
|
|
}
|
|
|
preloads.push(id);
|
|
|
if(preloads.length > $.options.preloadLimit) {
|
|
|
//先进先出
|
|
|
var first = $.data.preloads.shift();
|
|
|
var webviewCache = $.webviews[first];
|
|
|
if(webviewCache && webviewCache.webview) {
|
|
|
//需要将自己打开的所有页面,全部close;
|
|
|
//关闭该预加载webview
|
|
|
$.closeAll(webviewCache.webview);
|
|
|
}
|
|
|
//删除缓存
|
|
|
delete $.webviews[first];
|
|
|
}
|
|
|
} else {
|
|
|
if(isCreate !== false) { //直接创建非预加载窗口
|
|
|
webview = plus.webview.create(options.url, id, $.windowOptions(options.styles), options.extras);
|
|
|
if(options.subpages) {
|
|
|
$.each(options.subpages, function(index, subpage) {
|
|
|
var subpageId = subpage.id || subpage.url;
|
|
|
var subWebview = plus.webview.getWebviewById(subpageId);
|
|
|
if(!subWebview) {
|
|
|
subWebview = plus.webview.create(subpage.url, subpageId, $.windowOptions(subpage.styles), subpage.extras);
|
|
|
}
|
|
|
webview.append(subWebview);
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return webview;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 预加载
|
|
|
*/
|
|
|
$.preload = function(options) {
|
|
|
//调用预加载函数,不管是否传递preload参数,强制变为true
|
|
|
if(!options.preload) {
|
|
|
options.preload = true;
|
|
|
}
|
|
|
return $.createWindow(options);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
*关闭当前webview打开的所有webview;
|
|
|
*/
|
|
|
$.closeOpened = function(webview) {
|
|
|
var opened = webview.opened();
|
|
|
if(opened) {
|
|
|
for(var i = 0, len = opened.length; i < len; i++) {
|
|
|
var openedWebview = opened[i];
|
|
|
var open_open = openedWebview.opened();
|
|
|
if(open_open && open_open.length > 0) {
|
|
|
//关闭打开的webview
|
|
|
$.closeOpened(openedWebview);
|
|
|
//关闭自己
|
|
|
openedWebview.close("none");
|
|
|
} else {
|
|
|
//如果直接孩子节点,就不用关闭了,因为父关闭的时候,会自动关闭子;
|
|
|
if(openedWebview.parent() !== webview) {
|
|
|
openedWebview.close('none');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
$.closeAll = function(webview, aniShow) {
|
|
|
$.closeOpened(webview);
|
|
|
if(aniShow) {
|
|
|
webview.close(aniShow);
|
|
|
} else {
|
|
|
webview.close();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 批量创建webview
|
|
|
* @param {type} options
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
$.createWindows = function(options) {
|
|
|
$.each(options, function(index, option) {
|
|
|
//初始化预加载窗口(创建)和非预加载窗口(仅配置,不创建)
|
|
|
$.createWindow(option, false);
|
|
|
});
|
|
|
};
|
|
|
/**
|
|
|
* 创建当前页面的子webview
|
|
|
* @param {type} options
|
|
|
* @returns {webview}
|
|
|
*/
|
|
|
$.appendWebview = function(options) {
|
|
|
if(!window.plus) {
|
|
|
return;
|
|
|
}
|
|
|
var id = options.id || options.url;
|
|
|
var webview;
|
|
|
if(!$.webviews[id]) { //保证执行一遍
|
|
|
//TODO 这里也有隐患,比如某个webview不是作为subpage创建的,而是作为target webview的话;
|
|
|
if(!plus.webview.getWebviewById(id)) {
|
|
|
webview = plus.webview.create(options.url, id, options.styles, options.extras);
|
|
|
}
|
|
|
//之前的实现方案:子窗口loaded之后再append到父窗口中;
|
|
|
//问题:部分子窗口loaded事件发生较晚,此时执行父窗口的children方法会返回空,导致父子通讯失败;
|
|
|
// 比如父页面执行完preload事件后,需触发子页面的preload事件,此时未append的话,就无法触发;
|
|
|
//修改方式:不再监控loaded事件,直接append
|
|
|
//by chb@20150521
|
|
|
// webview.addEventListener('loaded', function() {
|
|
|
plus.webview.currentWebview().append(webview);
|
|
|
// });
|
|
|
$.webviews[id] = options;
|
|
|
|
|
|
}
|
|
|
return webview;
|
|
|
};
|
|
|
|
|
|
//全局webviews
|
|
|
$.webviews = {};
|
|
|
//预加载窗口索引
|
|
|
$.data.preloads = [];
|
|
|
//$.currentWebview
|
|
|
$.plusReady(function() {
|
|
|
$.currentWebview = plus.webview.currentWebview();
|
|
|
});
|
|
|
$.addInit({
|
|
|
name: '5+',
|
|
|
index: 100,
|
|
|
handle: function() {
|
|
|
var options = $.options;
|
|
|
var subpages = options.subpages || [];
|
|
|
if($.os.plus) {
|
|
|
$.plusReady(function() {
|
|
|
//TODO 这里需要判断一下,最好等子窗口加载完毕后,再调用主窗口的show方法;
|
|
|
//或者:在openwindow方法中,监听实现;
|
|
|
$.each(subpages, function(index, subpage) {
|
|
|
$.appendWebview(subpage);
|
|
|
});
|
|
|
//判断是否首页
|
|
|
if(plus.webview.currentWebview() === plus.webview.getWebviewById(plus.runtime.appid)) {
|
|
|
//首页需要自己激活预加载;
|
|
|
//timeout因为子页面loaded之后才append的,防止子页面尚未append、从而导致其preload未触发的问题;
|
|
|
setTimeout(function() {
|
|
|
triggerPreload(plus.webview.currentWebview());
|
|
|
}, 300);
|
|
|
}
|
|
|
//设置ios顶部状态栏颜色;
|
|
|
if($.os.ios && $.options.statusBarBackground) {
|
|
|
plus.navigator.setStatusBarBackground($.options.statusBarBackground);
|
|
|
}
|
|
|
if($.os.android && parseFloat($.os.version) < 4.4) {
|
|
|
//解决Android平台4.4版本以下,resume后,父窗体标题延迟渲染的问题;
|
|
|
if(plus.webview.currentWebview().parent() == null) {
|
|
|
document.addEventListener("resume", function() {
|
|
|
var body = document.body;
|
|
|
body.style.display = 'none';
|
|
|
setTimeout(function() {
|
|
|
body.style.display = '';
|
|
|
}, 10);
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
} else {
|
|
|
//已支持iframe嵌入
|
|
|
// if (subpages.length > 0) {
|
|
|
// var err = document.createElement('div');
|
|
|
// err.className = 'mui-error';
|
|
|
// //文字描述
|
|
|
// var span = document.createElement('span');
|
|
|
// span.innerHTML = '在该浏览器下,不支持创建子页面,具体参考';
|
|
|
// err.appendChild(span);
|
|
|
// var a = document.createElement('a');
|
|
|
// a.innerHTML = '"mui框架适用场景"';
|
|
|
// a.href = 'http://ask.dcloud.net.cn/article/113';
|
|
|
// err.appendChild(a);
|
|
|
// document.body.appendChild(err);
|
|
|
// console.log('在该浏览器下,不支持创建子页面');
|
|
|
// }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
});
|
|
|
window.addEventListener('preload', function() {
|
|
|
//处理预加载部分
|
|
|
var webviews = $.options.preloadPages || [];
|
|
|
$.plusReady(function() {
|
|
|
$.each(webviews, function(index, webview) {
|
|
|
$.createWindow($.extend(webview, {
|
|
|
preload: true
|
|
|
}));
|
|
|
});
|
|
|
|
|
|
});
|
|
|
});
|
|
|
$.supportStatusbarOffset = function() {
|
|
|
return $.os.plus && $.os.ios && parseFloat($.os.version) >= 7;
|
|
|
};
|
|
|
$.ready(function() {
|
|
|
//标识当前环境支持statusbar
|
|
|
if($.supportStatusbarOffset()) {
|
|
|
document.body.classList.add('mui-statusbar');
|
|
|
}
|
|
|
});
|
|
|
})(mui);
|
|
|
|
|
|
/**
|
|
|
* mui back
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window) {
|
|
|
/**
|
|
|
* register back
|
|
|
* @param {type} back
|
|
|
* @returns {$.gestures}
|
|
|
*/
|
|
|
$.addBack = function(back) {
|
|
|
return $.addAction('backs', back);
|
|
|
};
|
|
|
/**
|
|
|
* default
|
|
|
*/
|
|
|
$.addBack({
|
|
|
name: 'browser',
|
|
|
index: 100,
|
|
|
handle: function() {
|
|
|
if (window.history.length > 1) {
|
|
|
window.history.back();
|
|
|
return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
});
|
|
|
/**
|
|
|
* 后退
|
|
|
*/
|
|
|
$.back = function() {
|
|
|
if (typeof $.options.beforeback === 'function') {
|
|
|
if ($.options.beforeback() === false) {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
$.doAction('backs');
|
|
|
};
|
|
|
window.addEventListener('tap', function(e) {
|
|
|
var action = $.targets.action;
|
|
|
if (action && action.classList.contains('mui-action-back')) {
|
|
|
$.back();
|
|
|
$.targets.action = false;
|
|
|
}
|
|
|
});
|
|
|
window.addEventListener('swiperight', function(e) {
|
|
|
var detail = e.detail;
|
|
|
if ($.options.swipeBack === true && Math.abs(detail.angle) < 3) {
|
|
|
$.back();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
})(mui, window);
|
|
|
/**
|
|
|
* mui back 5+
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window) {
|
|
|
if ($.os.plus && $.os.android) {
|
|
|
$.addBack({
|
|
|
name: 'mui',
|
|
|
index: 5,
|
|
|
handle: function() {
|
|
|
//后续重新设计此处,将back放到各个空间内部实现
|
|
|
//popover
|
|
|
if ($.targets._popover && $.targets._popover.classList.contains('mui-active')) {
|
|
|
$($.targets._popover).popover('hide');
|
|
|
return true;
|
|
|
}
|
|
|
//offcanvas
|
|
|
var offCanvas = document.querySelector('.mui-off-canvas-wrap.mui-active');
|
|
|
if (offCanvas) {
|
|
|
$(offCanvas).offCanvas('close');
|
|
|
return true;
|
|
|
}
|
|
|
var previewImage = $.isFunction($.getPreviewImage) && $.getPreviewImage();
|
|
|
if (previewImage && previewImage.isShown()) {
|
|
|
previewImage.close();
|
|
|
return true;
|
|
|
}
|
|
|
//popup
|
|
|
return $.closePopup();
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
//首次按下back按键的时间
|
|
|
$.__back__first = null;
|
|
|
/**
|
|
|
* 5+ back
|
|
|
*/
|
|
|
$.addBack({
|
|
|
name: '5+',
|
|
|
index: 10,
|
|
|
handle: function() {
|
|
|
if (!window.plus) {
|
|
|
return false;
|
|
|
}
|
|
|
var wobj = plus.webview.currentWebview();
|
|
|
var parent = wobj.parent();
|
|
|
if (parent) {
|
|
|
parent.evalJS('mui&&mui.back();');
|
|
|
} else {
|
|
|
wobj.canBack(function(e) {
|
|
|
//by chb 暂时注释,在碰到类似popover之类的锚点的时候,需多次点击才能返回;
|
|
|
if (e.canBack) { //webview history back
|
|
|
window.history.back();
|
|
|
} else { //webview close or hide
|
|
|
//fixed by fxy 此处不应该用opener判断,因为用户有可能自己close掉当前窗口的opener。这样的话。opener就为空了,导致不能执行close
|
|
|
if (wobj.id === plus.runtime.appid) { //首页
|
|
|
//首页不存在opener的情况下,后退实际上应该是退出应用;
|
|
|
//首次按键,提示‘再按一次退出应用’
|
|
|
if (!$.__back__first) {
|
|
|
$.__back__first = new Date().getTime();
|
|
|
mui.toast('再按一次退出应用');
|
|
|
setTimeout(function() {
|
|
|
$.__back__first = null;
|
|
|
}, 800);
|
|
|
} else {
|
|
|
if (new Date().getTime() - $.__back__first < 2000) {
|
|
|
plus.runtime.quit();
|
|
|
}
|
|
|
}
|
|
|
} else { //其他页面,
|
|
|
if (wobj.preload) {
|
|
|
wobj.hide("auto");
|
|
|
} else {
|
|
|
//关闭页面时,需要将其打开的所有子页面全部关闭;
|
|
|
$.closeAll(wobj);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
|
|
|
$.menu = function() {
|
|
|
var menu = document.querySelector('.mui-action-menu');
|
|
|
if (menu) {
|
|
|
$.trigger(menu, $.EVENT_START); //临时处理menu无touchstart的话,找不到当前targets的问题
|
|
|
$.trigger(menu, 'tap');
|
|
|
} else { //执行父窗口的menu
|
|
|
if (window.plus) {
|
|
|
var wobj = $.currentWebview;
|
|
|
var parent = wobj.parent();
|
|
|
if (parent) { //又得evalJS
|
|
|
parent.evalJS('mui&&mui.menu();');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
var __back = function() {
|
|
|
$.back();
|
|
|
};
|
|
|
var __menu = function() {
|
|
|
$.menu();
|
|
|
};
|
|
|
//默认监听
|
|
|
$.plusReady(function() {
|
|
|
if ($.options.keyEventBind.backbutton) {
|
|
|
plus.key.addEventListener('backbutton', __back, false);
|
|
|
}
|
|
|
if ($.options.keyEventBind.menubutton) {
|
|
|
plus.key.addEventListener('menubutton', __menu, false);
|
|
|
}
|
|
|
});
|
|
|
//处理按键监听事件
|
|
|
$.addInit({
|
|
|
name: 'keyEventBind',
|
|
|
index: 1000,
|
|
|
handle: function() {
|
|
|
$.plusReady(function() {
|
|
|
//如果不为true,则移除默认监听
|
|
|
if (!$.options.keyEventBind.backbutton) {
|
|
|
plus.key.removeEventListener('backbutton', __back);
|
|
|
}
|
|
|
if (!$.options.keyEventBind.menubutton) {
|
|
|
plus.key.removeEventListener('menubutton', __menu);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
})(mui, window);
|
|
|
/**
|
|
|
* mui.init pulldownRefresh
|
|
|
* @param {type} $
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($) {
|
|
|
$.addInit({
|
|
|
name: 'pullrefresh',
|
|
|
index: 1000,
|
|
|
handle: function() {
|
|
|
var options = $.options;
|
|
|
var pullRefreshOptions = options.pullRefresh || {};
|
|
|
var hasPulldown = pullRefreshOptions.down && pullRefreshOptions.down.hasOwnProperty('callback');
|
|
|
var hasPullup = pullRefreshOptions.up && pullRefreshOptions.up.hasOwnProperty('callback');
|
|
|
if(hasPulldown || hasPullup) {
|
|
|
var container = pullRefreshOptions.container;
|
|
|
if(container) {
|
|
|
var $container = $(container);
|
|
|
if($container.length === 1) {
|
|
|
if($.os.plus) { //5+环境
|
|
|
if(hasPulldown && pullRefreshOptions.down.style == "circle") { //原生转圈
|
|
|
$.plusReady(function() {
|
|
|
//这里改写$.fn.pullRefresh
|
|
|
$.fn.pullRefresh = $.fn.pullRefresh_native;
|
|
|
$container.pullRefresh(pullRefreshOptions);
|
|
|
});
|
|
|
|
|
|
} else if($.os.android) { //非原生转圈,但是Android环境
|
|
|
$.plusReady(function() {
|
|
|
//这里改写$.fn.pullRefresh
|
|
|
$.fn.pullRefresh = $.fn.pullRefresh_native
|
|
|
var webview = plus.webview.currentWebview();
|
|
|
if(window.__NWin_Enable__ === false) { //不支持多webview
|
|
|
$container.pullRefresh(pullRefreshOptions);
|
|
|
} else {
|
|
|
if(hasPullup) {
|
|
|
//当前页面初始化pullup
|
|
|
var upOptions = {};
|
|
|
upOptions.up = pullRefreshOptions.up;
|
|
|
upOptions.webviewId = webview.id || webview.getURL();
|
|
|
$container.pullRefresh(upOptions);
|
|
|
}
|
|
|
if(hasPulldown) {
|
|
|
var parent = webview.parent();
|
|
|
var id = webview.id || webview.getURL();
|
|
|
if(parent) {
|
|
|
if(!hasPullup) { //如果没有上拉加载,需要手动初始化一个默认的pullRefresh,以便当前页面容器可以调用endPulldownToRefresh等方法
|
|
|
$container.pullRefresh({
|
|
|
webviewId: id
|
|
|
});
|
|
|
}
|
|
|
var downOptions = {
|
|
|
webviewId: id//子页面id
|
|
|
};
|
|
|
downOptions.down = $.extend({}, pullRefreshOptions.down);
|
|
|
downOptions.down.callback = '_CALLBACK';
|
|
|
//改写父页面的$.fn.pullRefresh
|
|
|
parent.evalJS("mui.fn.pullRefresh=mui.fn.pullRefresh_native");
|
|
|
//父页面初始化pulldown
|
|
|
parent.evalJS("mui&&mui(document.querySelector('.mui-content')).pullRefresh('" + JSON.stringify(downOptions) + "')");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
} else { //非原生转圈,iOS环境
|
|
|
$container.pullRefresh(pullRefreshOptions);
|
|
|
}
|
|
|
} else {
|
|
|
$container.pullRefresh(pullRefreshOptions);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
})(mui);
|
|
|
/**
|
|
|
* mui ajax
|
|
|
* @param {type} $
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window, undefined) {
|
|
|
|
|
|
var jsonType = 'application/json';
|
|
|
var htmlType = 'text/html';
|
|
|
var rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;
|
|
|
var scriptTypeRE = /^(?:text|application)\/javascript/i;
|
|
|
var xmlTypeRE = /^(?:text|application)\/xml/i;
|
|
|
var blankRE = /^\s*$/;
|
|
|
|
|
|
$.ajaxSettings = {
|
|
|
type: 'GET',
|
|
|
beforeSend: $.noop,
|
|
|
success: $.noop,
|
|
|
error: $.noop,
|
|
|
complete: $.noop,
|
|
|
context: null,
|
|
|
xhr: function(protocol) {
|
|
|
return new window.XMLHttpRequest();
|
|
|
},
|
|
|
accepts: {
|
|
|
script: 'text/javascript, application/javascript, application/x-javascript',
|
|
|
json: jsonType,
|
|
|
xml: 'application/xml, text/xml',
|
|
|
html: htmlType,
|
|
|
text: 'text/plain'
|
|
|
},
|
|
|
timeout: 0,
|
|
|
processData: true,
|
|
|
cache: true
|
|
|
};
|
|
|
var ajaxBeforeSend = function(xhr, settings) {
|
|
|
var context = settings.context
|
|
|
if(settings.beforeSend.call(context, xhr, settings) === false) {
|
|
|
return false;
|
|
|
}
|
|
|
};
|
|
|
var ajaxSuccess = function(data, xhr, settings) {
|
|
|
settings.success.call(settings.context, data, 'success', xhr);
|
|
|
ajaxComplete('success', xhr, settings);
|
|
|
};
|
|
|
// type: "timeout", "error", "abort", "parsererror"
|
|
|
var ajaxError = function(error, type, xhr, settings) {
|
|
|
settings.error.call(settings.context, xhr, type, error);
|
|
|
ajaxComplete(type, xhr, settings);
|
|
|
};
|
|
|
// status: "success", "notmodified", "error", "timeout", "abort", "parsererror"
|
|
|
var ajaxComplete = function(status, xhr, settings) {
|
|
|
settings.complete.call(settings.context, xhr, status);
|
|
|
};
|
|
|
|
|
|
var serialize = function(params, obj, traditional, scope) {
|
|
|
var type, array = $.isArray(obj),
|
|
|
hash = $.isPlainObject(obj);
|
|
|
$.each(obj, function(key, value) {
|
|
|
type = $.type(value);
|
|
|
if(scope) {
|
|
|
key = traditional ? scope :
|
|
|
scope + '[' + (hash || type === 'object' || type === 'array' ? key : '') + ']';
|
|
|
}
|
|
|
// handle data in serializeArray() format
|
|
|
if(!scope && array) {
|
|
|
params.add(value.name, value.value);
|
|
|
}
|
|
|
// recurse into nested objects
|
|
|
else if(type === "array" || (!traditional && type === "object")) {
|
|
|
serialize(params, value, traditional, key);
|
|
|
} else {
|
|
|
params.add(key, value);
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
var serializeData = function(options) {
|
|
|
if(options.processData && options.data && typeof options.data !== "string") {
|
|
|
var contentType = options.contentType;
|
|
|
if(!contentType && options.headers) {
|
|
|
contentType = options.headers['Content-Type'];
|
|
|
}
|
|
|
if(contentType && ~contentType.indexOf(jsonType)) { //application/json
|
|
|
options.data = JSON.stringify(options.data);
|
|
|
} else {
|
|
|
options.data = $.param(options.data, options.traditional);
|
|
|
}
|
|
|
}
|
|
|
if(options.data && (!options.type || options.type.toUpperCase() === 'GET')) {
|
|
|
options.url = appendQuery(options.url, options.data);
|
|
|
options.data = undefined;
|
|
|
}
|
|
|
};
|
|
|
var appendQuery = function(url, query) {
|
|
|
if(query === '') {
|
|
|
return url;
|
|
|
}
|
|
|
return(url + '&' + query).replace(/[&?]{1,2}/, '?');
|
|
|
};
|
|
|
var mimeToDataType = function(mime) {
|
|
|
if(mime) {
|
|
|
mime = mime.split(';', 2)[0];
|
|
|
}
|
|
|
return mime && (mime === htmlType ? 'html' :
|
|
|
mime === jsonType ? 'json' :
|
|
|
scriptTypeRE.test(mime) ? 'script' :
|
|
|
xmlTypeRE.test(mime) && 'xml') || 'text';
|
|
|
};
|
|
|
var parseArguments = function(url, data, success, dataType) {
|
|
|
if($.isFunction(data)) {
|
|
|
dataType = success, success = data, data = undefined;
|
|
|
}
|
|
|
if(!$.isFunction(success)) {
|
|
|
dataType = success, success = undefined;
|
|
|
}
|
|
|
return {
|
|
|
url: url,
|
|
|
data: data,
|
|
|
success: success,
|
|
|
dataType: dataType
|
|
|
};
|
|
|
};
|
|
|
$.ajax = function(url, options) {
|
|
|
if(typeof url === "object") {
|
|
|
options = url;
|
|
|
url = undefined;
|
|
|
}
|
|
|
var settings = options || {};
|
|
|
settings.url = url || settings.url;
|
|
|
for(var key in $.ajaxSettings) {
|
|
|
if(settings[key] === undefined) {
|
|
|
settings[key] = $.ajaxSettings[key];
|
|
|
}
|
|
|
}
|
|
|
serializeData(settings);
|
|
|
var dataType = settings.dataType;
|
|
|
|
|
|
if(settings.cache === false || ((!options || options.cache !== true) && ('script' === dataType))) {
|
|
|
settings.url = appendQuery(settings.url, '_=' + $.now());
|
|
|
}
|
|
|
var mime = settings.accepts[dataType && dataType.toLowerCase()];
|
|
|
var headers = {};
|
|
|
var setHeader = function(name, value) {
|
|
|
headers[name.toLowerCase()] = [name, value];
|
|
|
};
|
|
|
var protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol;
|
|
|
var xhr = settings.xhr(settings);
|
|
|
var nativeSetHeader = xhr.setRequestHeader;
|
|
|
var abortTimeout;
|
|
|
|
|
|
setHeader('X-Requested-With', 'XMLHttpRequest');
|
|
|
setHeader('Accept', mime || '*/*');
|
|
|
if(!!(mime = settings.mimeType || mime)) {
|
|
|
if(mime.indexOf(',') > -1) {
|
|
|
mime = mime.split(',', 2)[0];
|
|
|
}
|
|
|
xhr.overrideMimeType && xhr.overrideMimeType(mime);
|
|
|
}
|
|
|
if(settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() !== 'GET')) {
|
|
|
setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded');
|
|
|
}
|
|
|
if(settings.headers) {
|
|
|
for(var name in settings.headers)
|
|
|
setHeader(name, settings.headers[name]);
|
|
|
}
|
|
|
xhr.setRequestHeader = setHeader;
|
|
|
|
|
|
xhr.onreadystatechange = function() {
|
|
|
if(xhr.readyState === 4) {
|
|
|
xhr.onreadystatechange = $.noop;
|
|
|
clearTimeout(abortTimeout);
|
|
|
var result, error = false;
|
|
|
var isLocal = protocol === 'file:';
|
|
|
if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 || (xhr.status === 0 && isLocal && xhr.responseText)) {
|
|
|
dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type'));
|
|
|
result = xhr.responseText;
|
|
|
try {
|
|
|
// http://perfectionkills.com/global-eval-what-are-the-options/
|
|
|
if(dataType === 'script') {
|
|
|
(1, eval)(result);
|
|
|
} else if(dataType === 'xml') {
|
|
|
result = xhr.responseXML;
|
|
|
} else if(dataType === 'json') {
|
|
|
result = blankRE.test(result) ? null : $.parseJSON(result);
|
|
|
}
|
|
|
} catch(e) {
|
|
|
error = e;
|
|
|
}
|
|
|
|
|
|
if(error) {
|
|
|
ajaxError(error, 'parsererror', xhr, settings);
|
|
|
} else {
|
|
|
ajaxSuccess(result, xhr, settings);
|
|
|
}
|
|
|
} else {
|
|
|
var status = xhr.status ? 'error' : 'abort';
|
|
|
var statusText = xhr.statusText || null;
|
|
|
if(isLocal) {
|
|
|
status = 'error';
|
|
|
statusText = '404';
|
|
|
}
|
|
|
ajaxError(statusText, status, xhr, settings);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
if(ajaxBeforeSend(xhr, settings) === false) {
|
|
|
xhr.abort();
|
|
|
ajaxError(null, 'abort', xhr, settings);
|
|
|
return xhr;
|
|
|
}
|
|
|
|
|
|
if(settings.xhrFields) {
|
|
|
for(var name in settings.xhrFields) {
|
|
|
xhr[name] = settings.xhrFields[name];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var async = 'async' in settings ? settings.async : true;
|
|
|
|
|
|
xhr.open(settings.type.toUpperCase(), settings.url, async, settings.username, settings.password);
|
|
|
|
|
|
for(var name in headers) {
|
|
|
if(headers.hasOwnProperty(name)) {
|
|
|
nativeSetHeader.apply(xhr, headers[name]);
|
|
|
}
|
|
|
}
|
|
|
if(settings.timeout > 0) {
|
|
|
abortTimeout = setTimeout(function() {
|
|
|
xhr.onreadystatechange = $.noop;
|
|
|
xhr.abort();
|
|
|
ajaxError(null, 'timeout', xhr, settings);
|
|
|
}, settings.timeout);
|
|
|
}
|
|
|
xhr.send(settings.data ? settings.data : null);
|
|
|
return xhr;
|
|
|
};
|
|
|
|
|
|
$.param = function(obj, traditional) {
|
|
|
var params = [];
|
|
|
params.add = function(k, v) {
|
|
|
this.push(encodeURIComponent(k) + '=' + encodeURIComponent(v));
|
|
|
};
|
|
|
serialize(params, obj, traditional);
|
|
|
return params.join('&').replace(/%20/g, '+');
|
|
|
};
|
|
|
$.get = function( /* url, data, success, dataType */ ) {
|
|
|
return $.ajax(parseArguments.apply(null, arguments));
|
|
|
};
|
|
|
|
|
|
$.post = function( /* url, data, success, dataType */ ) {
|
|
|
var options = parseArguments.apply(null, arguments);
|
|
|
options.type = 'POST';
|
|
|
return $.ajax(options);
|
|
|
};
|
|
|
|
|
|
$.getJSON = function( /* url, data, success */ ) {
|
|
|
var options = parseArguments.apply(null, arguments);
|
|
|
options.dataType = 'json';
|
|
|
return $.ajax(options);
|
|
|
};
|
|
|
|
|
|
$.fn.load = function(url, data, success) {
|
|
|
if(!this.length)
|
|
|
return this;
|
|
|
var self = this,
|
|
|
parts = url.split(/\s/),
|
|
|
selector,
|
|
|
options = parseArguments(url, data, success),
|
|
|
callback = options.success;
|
|
|
if(parts.length > 1)
|
|
|
options.url = parts[0], selector = parts[1];
|
|
|
options.success = function(response) {
|
|
|
if(selector) {
|
|
|
var div = document.createElement('div');
|
|
|
div.innerHTML = response.replace(rscript, "");
|
|
|
var selectorDiv = document.createElement('div');
|
|
|
var childs = div.querySelectorAll(selector);
|
|
|
if(childs && childs.length > 0) {
|
|
|
for(var i = 0, len = childs.length; i < len; i++) {
|
|
|
selectorDiv.appendChild(childs[i]);
|
|
|
}
|
|
|
}
|
|
|
self[0].innerHTML = selectorDiv.innerHTML;
|
|
|
} else {
|
|
|
self[0].innerHTML = response;
|
|
|
}
|
|
|
callback && callback.apply(self, arguments);
|
|
|
};
|
|
|
$.ajax(options);
|
|
|
return this;
|
|
|
};
|
|
|
|
|
|
})(mui, window);
|
|
|
/**
|
|
|
* 5+ ajax
|
|
|
*/
|
|
|
(function($) {
|
|
|
var originAnchor = document.createElement('a');
|
|
|
originAnchor.href = GetHrefUrl();
|
|
|
$.plusReady(function() {
|
|
|
$.ajaxSettings = $.extend($.ajaxSettings, {
|
|
|
xhr: function(settings) {
|
|
|
if (settings.crossDomain) { //强制使用plus跨域
|
|
|
return new plus.net.XMLHttpRequest();
|
|
|
}
|
|
|
//仅在webview的url为远程文件,且ajax请求的资源不同源下使用plus.net.XMLHttpRequest
|
|
|
if (originAnchor.protocol !== 'file:') {
|
|
|
var urlAnchor = document.createElement('a');
|
|
|
urlAnchor.href = settings.url;
|
|
|
urlAnchor.href = urlAnchor.href;
|
|
|
settings.crossDomain = (originAnchor.protocol + '//' + originAnchor.host) !== (urlAnchor.protocol + '//' + urlAnchor.host);
|
|
|
if (settings.crossDomain) {
|
|
|
return new plus.net.XMLHttpRequest();
|
|
|
}
|
|
|
}
|
|
|
if ($.os.ios && window.webkit && window.webkit.messageHandlers) { //wkwebview下同样使用5+ xhr
|
|
|
return new plus.net.XMLHttpRequest();
|
|
|
}
|
|
|
return new window.XMLHttpRequest();
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
})(mui);
|
|
|
/**
|
|
|
* mui layout(offset[,position,width,height...])
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @param {type} undefined
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window, undefined) {
|
|
|
$.offset = function(element) {
|
|
|
var box = {
|
|
|
top : 0,
|
|
|
left : 0
|
|
|
};
|
|
|
if ( typeof element.getBoundingClientRect !== undefined) {
|
|
|
box = element.getBoundingClientRect();
|
|
|
}
|
|
|
return {
|
|
|
top : box.top + window.pageYOffset - element.clientTop,
|
|
|
left : box.left + window.pageXOffset - element.clientLeft
|
|
|
};
|
|
|
};
|
|
|
})(mui, window);
|
|
|
/**
|
|
|
* mui animation
|
|
|
*/
|
|
|
(function($, window) {
|
|
|
/**
|
|
|
* scrollTo
|
|
|
*/
|
|
|
$.scrollTo = function(scrollTop, duration, callback) {
|
|
|
duration = duration || 1000;
|
|
|
var scroll = function(duration) {
|
|
|
if (duration <= 0) {
|
|
|
window.scrollTo(0, scrollTop);
|
|
|
callback && callback();
|
|
|
return;
|
|
|
}
|
|
|
var distaince = scrollTop - window.scrollY;
|
|
|
setTimeout(function() {
|
|
|
window.scrollTo(0, window.scrollY + distaince / duration * 10);
|
|
|
scroll(duration - 10);
|
|
|
}, 16.7);
|
|
|
};
|
|
|
scroll(duration);
|
|
|
};
|
|
|
$.animationFrame = function(cb) {
|
|
|
var args, isQueued, context;
|
|
|
return function() {
|
|
|
args = arguments;
|
|
|
context = this;
|
|
|
if (!isQueued) {
|
|
|
isQueued = true;
|
|
|
requestAnimationFrame(function() {
|
|
|
cb.apply(context, args);
|
|
|
isQueued = false;
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
};
|
|
|
|
|
|
})(mui, window);
|
|
|
(function($) {
|
|
|
var initializing = false,
|
|
|
fnTest = /xyz/.test(function() {
|
|
|
xyz;
|
|
|
}) ? /\b_super\b/ : /.*/;
|
|
|
|
|
|
var Class = function() {};
|
|
|
Class.extend = function(prop) {
|
|
|
var _super = this.prototype;
|
|
|
initializing = true;
|
|
|
var prototype = new this();
|
|
|
initializing = false;
|
|
|
for (var name in prop) {
|
|
|
prototype[name] = typeof prop[name] == "function" &&
|
|
|
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
|
|
|
(function(name, fn) {
|
|
|
return function() {
|
|
|
var tmp = this._super;
|
|
|
|
|
|
this._super = _super[name];
|
|
|
|
|
|
var ret = fn.apply(this, arguments);
|
|
|
this._super = tmp;
|
|
|
|
|
|
return ret;
|
|
|
};
|
|
|
})(name, prop[name]) :
|
|
|
prop[name];
|
|
|
}
|
|
|
function Class() {
|
|
|
if (!initializing && this.init)
|
|
|
this.init.apply(this, arguments);
|
|
|
}
|
|
|
Class.prototype = prototype;
|
|
|
Class.prototype.constructor = Class;
|
|
|
Class.extend = arguments.callee;
|
|
|
return Class;
|
|
|
};
|
|
|
$.Class = Class;
|
|
|
})(mui);
|
|
|
(function($, document, undefined) {
|
|
|
var CLASS_PULL_TOP_POCKET = 'mui-pull-top-pocket';
|
|
|
var CLASS_PULL_BOTTOM_POCKET = 'mui-pull-bottom-pocket';
|
|
|
var CLASS_PULL = 'mui-pull';
|
|
|
var CLASS_PULL_LOADING = 'mui-pull-loading';
|
|
|
var CLASS_PULL_CAPTION = 'mui-pull-caption';
|
|
|
var CLASS_PULL_CAPTION_DOWN = 'mui-pull-caption-down';
|
|
|
var CLASS_PULL_CAPTION_REFRESH = 'mui-pull-caption-refresh';
|
|
|
var CLASS_PULL_CAPTION_NOMORE = 'mui-pull-caption-nomore';
|
|
|
|
|
|
var CLASS_ICON = 'mui-icon';
|
|
|
var CLASS_SPINNER = 'mui-spinner';
|
|
|
var CLASS_ICON_PULLDOWN = 'mui-icon-pulldown';
|
|
|
|
|
|
var CLASS_BLOCK = 'mui-block';
|
|
|
var CLASS_HIDDEN = 'mui-hidden';
|
|
|
var CLASS_VISIBILITY = 'mui-visibility';
|
|
|
|
|
|
var CLASS_LOADING_UP = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_ICON_PULLDOWN;
|
|
|
var CLASS_LOADING_DOWN = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_ICON_PULLDOWN;
|
|
|
var CLASS_LOADING = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_SPINNER;
|
|
|
|
|
|
var pocketHtml = ['<div class="' + CLASS_PULL + '">', '<div class="{icon}"></div>', '<div class="' + CLASS_PULL_CAPTION + '">{contentrefresh}</div>', '</div>'].join('');
|
|
|
|
|
|
var PullRefresh = {
|
|
|
init: function(element, options) {
|
|
|
this._super(element, $.extend(true, {
|
|
|
scrollY: true,
|
|
|
scrollX: false,
|
|
|
indicators: true,
|
|
|
deceleration: 0.003,
|
|
|
down: {
|
|
|
height: 50,
|
|
|
contentinit: '下拉可以刷新',
|
|
|
contentdown: '下拉可以刷新',
|
|
|
contentover: '释放立即刷新',
|
|
|
contentrefresh: '正在刷新...'
|
|
|
},
|
|
|
up: {
|
|
|
height: 50,
|
|
|
auto: false,
|
|
|
contentinit: '上拉显示更多',
|
|
|
contentdown: '上拉显示更多',
|
|
|
contentrefresh: '正在加载...',
|
|
|
contentnomore: '没有更多数据了',
|
|
|
duration: 300
|
|
|
}
|
|
|
}, options));
|
|
|
},
|
|
|
_init: function() {
|
|
|
this._super();
|
|
|
this._initPocket();
|
|
|
},
|
|
|
_initPulldownRefresh: function() {
|
|
|
this.pulldown = true;
|
|
|
if (this.topPocket) {
|
|
|
this.pullPocket = this.topPocket;
|
|
|
this.pullPocket.classList.add(CLASS_BLOCK);
|
|
|
this.pullPocket.classList.add(CLASS_VISIBILITY);
|
|
|
this.pullCaption = this.topCaption;
|
|
|
this.pullLoading = this.topLoading;
|
|
|
}
|
|
|
},
|
|
|
_initPullupRefresh: function() {
|
|
|
this.pulldown = false;
|
|
|
if (this.bottomPocket) {
|
|
|
this.pullPocket = this.bottomPocket;
|
|
|
this.pullPocket.classList.add(CLASS_BLOCK);
|
|
|
this.pullPocket.classList.add(CLASS_VISIBILITY);
|
|
|
this.pullCaption = this.bottomCaption;
|
|
|
this.pullLoading = this.bottomLoading;
|
|
|
}
|
|
|
},
|
|
|
_initPocket: function() {
|
|
|
var options = this.options;
|
|
|
if (options.down && options.down.hasOwnProperty('callback')) {
|
|
|
this.topPocket = this.scroller.querySelector('.' + CLASS_PULL_TOP_POCKET);
|
|
|
if (!this.topPocket) {
|
|
|
this.topPocket = this._createPocket(CLASS_PULL_TOP_POCKET, options.down, CLASS_LOADING_DOWN);
|
|
|
this.wrapper.insertBefore(this.topPocket, this.wrapper.firstChild);
|
|
|
}
|
|
|
this.topLoading = this.topPocket.querySelector('.' + CLASS_PULL_LOADING);
|
|
|
this.topCaption = this.topPocket.querySelector('.' + CLASS_PULL_CAPTION);
|
|
|
}
|
|
|
if (options.up && options.up.hasOwnProperty('callback')) {
|
|
|
this.bottomPocket = this.scroller.querySelector('.' + CLASS_PULL_BOTTOM_POCKET);
|
|
|
if (!this.bottomPocket) {
|
|
|
this.bottomPocket = this._createPocket(CLASS_PULL_BOTTOM_POCKET, options.up, CLASS_LOADING);
|
|
|
this.scroller.appendChild(this.bottomPocket);
|
|
|
}
|
|
|
this.bottomLoading = this.bottomPocket.querySelector('.' + CLASS_PULL_LOADING);
|
|
|
this.bottomCaption = this.bottomPocket.querySelector('.' + CLASS_PULL_CAPTION);
|
|
|
//TODO only for h5
|
|
|
this.wrapper.addEventListener('scrollbottom', this);
|
|
|
}
|
|
|
},
|
|
|
_createPocket: function(clazz, options, iconClass) {
|
|
|
var pocket = document.createElement('div');
|
|
|
pocket.className = clazz;
|
|
|
pocket.innerHTML = pocketHtml.replace('{contentrefresh}', options.contentinit).replace('{icon}', iconClass);
|
|
|
return pocket;
|
|
|
},
|
|
|
_resetPullDownLoading: function() {
|
|
|
var loading = this.pullLoading;
|
|
|
if (loading) {
|
|
|
this.pullCaption.innerHTML = this.options.down.contentdown;
|
|
|
loading.style.webkitTransition = "";
|
|
|
loading.style.webkitTransform = "";
|
|
|
loading.style.webkitAnimation = "";
|
|
|
loading.className = CLASS_LOADING_DOWN;
|
|
|
}
|
|
|
},
|
|
|
_setCaptionClass: function(isPulldown, caption, title) {
|
|
|
if (!isPulldown) {
|
|
|
switch (title) {
|
|
|
case this.options.up.contentdown:
|
|
|
caption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_DOWN;
|
|
|
break;
|
|
|
case this.options.up.contentrefresh:
|
|
|
caption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_REFRESH
|
|
|
break;
|
|
|
case this.options.up.contentnomore:
|
|
|
caption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_NOMORE;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
_setCaption: function(title, reset) {
|
|
|
if (this.loading) {
|
|
|
return;
|
|
|
}
|
|
|
var options = this.options;
|
|
|
var pocket = this.pullPocket;
|
|
|
var caption = this.pullCaption;
|
|
|
var loading = this.pullLoading;
|
|
|
var isPulldown = this.pulldown;
|
|
|
var self = this;
|
|
|
if (pocket) {
|
|
|
if (reset) {
|
|
|
setTimeout(function() {
|
|
|
caption.innerHTML = self.lastTitle = title;
|
|
|
if (isPulldown) {
|
|
|
loading.className = CLASS_LOADING_DOWN;
|
|
|
} else {
|
|
|
self._setCaptionClass(false, caption, title);
|
|
|
loading.className = CLASS_LOADING;
|
|
|
}
|
|
|
loading.style.webkitAnimation = "";
|
|
|
loading.style.webkitTransition = "";
|
|
|
loading.style.webkitTransform = "";
|
|
|
}, 100);
|
|
|
} else {
|
|
|
if (title !== this.lastTitle) {
|
|
|
caption.innerHTML = title;
|
|
|
if (isPulldown) {
|
|
|
if (title === options.down.contentrefresh) {
|
|
|
loading.className = CLASS_LOADING;
|
|
|
loading.style.webkitAnimation = "spinner-spin 1s step-end infinite";
|
|
|
} else if (title === options.down.contentover) {
|
|
|
loading.className = CLASS_LOADING_UP;
|
|
|
loading.style.webkitTransition = "-webkit-transform 0.3s ease-in";
|
|
|
loading.style.webkitTransform = "rotate(180deg)";
|
|
|
} else if (title === options.down.contentdown) {
|
|
|
loading.className = CLASS_LOADING_DOWN;
|
|
|
loading.style.webkitTransition = "-webkit-transform 0.3s ease-in";
|
|
|
loading.style.webkitTransform = "rotate(0deg)";
|
|
|
}
|
|
|
} else {
|
|
|
if (title === options.up.contentrefresh) {
|
|
|
loading.className = CLASS_LOADING + ' ' + CLASS_VISIBILITY;
|
|
|
} else {
|
|
|
loading.className = CLASS_LOADING + ' ' + CLASS_HIDDEN;
|
|
|
}
|
|
|
self._setCaptionClass(false, caption, title);
|
|
|
}
|
|
|
this.lastTitle = title;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
$.PullRefresh = PullRefresh;
|
|
|
})(mui, document);
|
|
|
(function($, window, document, undefined) {
|
|
|
var CLASS_SCROLL = 'mui-scroll';
|
|
|
var CLASS_SCROLLBAR = 'mui-scrollbar';
|
|
|
var CLASS_INDICATOR = 'mui-scrollbar-indicator';
|
|
|
var CLASS_SCROLLBAR_VERTICAL = CLASS_SCROLLBAR + '-vertical';
|
|
|
var CLASS_SCROLLBAR_HORIZONTAL = CLASS_SCROLLBAR + '-horizontal';
|
|
|
|
|
|
var CLASS_ACTIVE = 'mui-active';
|
|
|
|
|
|
var ease = {
|
|
|
quadratic: {
|
|
|
style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
|
|
|
fn: function(k) {
|
|
|
return k * (2 - k);
|
|
|
}
|
|
|
},
|
|
|
circular: {
|
|
|
style: 'cubic-bezier(0.1, 0.57, 0.1, 1)',
|
|
|
fn: function(k) {
|
|
|
return Math.sqrt(1 - (--k * k));
|
|
|
}
|
|
|
},
|
|
|
outCirc: {
|
|
|
style: 'cubic-bezier(0.075, 0.82, 0.165, 1)'
|
|
|
},
|
|
|
outCubic: {
|
|
|
style: 'cubic-bezier(0.165, 0.84, 0.44, 1)'
|
|
|
}
|
|
|
}
|
|
|
var Scroll = $.Class.extend({
|
|
|
init: function(element, options) {
|
|
|
this.wrapper = this.element = element;
|
|
|
this.scroller = this.wrapper.children[0];
|
|
|
this.scrollerStyle = this.scroller && this.scroller.style;
|
|
|
this.stopped = false;
|
|
|
|
|
|
this.options = $.extend(true, {
|
|
|
scrollY: true, //是否竖向滚动
|
|
|
scrollX: false, //是否横向滚动
|
|
|
startX: 0, //初始化时滚动至x
|
|
|
startY: 0, //初始化时滚动至y
|
|
|
|
|
|
indicators: true, //是否显示滚动条
|
|
|
stopPropagation: false,
|
|
|
hardwareAccelerated: true,
|
|
|
fixedBadAndorid: false,
|
|
|
preventDefaultException: {
|
|
|
tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|VIDEO)$/
|
|
|
},
|
|
|
momentum: true,
|
|
|
|
|
|
snapX: 0.5, //横向切换距离(以当前容器宽度为基准)
|
|
|
snap: false, //图片轮播,拖拽式选项卡
|
|
|
|
|
|
bounce: true, //是否启用回弹
|
|
|
bounceTime: 500, //回弹动画时间
|
|
|
bounceEasing: ease.outCirc, //回弹动画曲线
|
|
|
|
|
|
scrollTime: 500,
|
|
|
scrollEasing: ease.outCubic, //轮播动画曲线
|
|
|
|
|
|
directionLockThreshold: 5,
|
|
|
|
|
|
parallaxElement: false, //视差元素
|
|
|
parallaxRatio: 0.5
|
|
|
}, options);
|
|
|
|
|
|
this.x = 0;
|
|
|
this.y = 0;
|
|
|
this.translateZ = this.options.hardwareAccelerated ? ' translateZ(0)' : '';
|
|
|
|
|
|
this._init();
|
|
|
if (this.scroller) {
|
|
|
this.refresh();
|
|
|
// if (this.options.startX !== 0 || this.options.startY !== 0) { //需要判断吗?后续根据实际情况再看看
|
|
|
this.scrollTo(this.options.startX, this.options.startY);
|
|
|
// }
|
|
|
}
|
|
|
},
|
|
|
_init: function() {
|
|
|
this._initParallax();
|
|
|
this._initIndicators();
|
|
|
this._initEvent();
|
|
|
},
|
|
|
_initParallax: function() {
|
|
|
if (this.options.parallaxElement) {
|
|
|
this.parallaxElement = document.querySelector(this.options.parallaxElement);
|
|
|
this.parallaxStyle = this.parallaxElement.style;
|
|
|
this.parallaxHeight = this.parallaxElement.offsetHeight;
|
|
|
this.parallaxImgStyle = this.parallaxElement.querySelector('img').style;
|
|
|
}
|
|
|
},
|
|
|
_initIndicators: function() {
|
|
|
var self = this;
|
|
|
self.indicators = [];
|
|
|
if (!this.options.indicators) {
|
|
|
return;
|
|
|
}
|
|
|
var indicators = [],
|
|
|
indicator;
|
|
|
|
|
|
// Vertical scrollbar
|
|
|
if (self.options.scrollY) {
|
|
|
indicator = {
|
|
|
el: this._createScrollBar(CLASS_SCROLLBAR_VERTICAL),
|
|
|
listenX: false
|
|
|
};
|
|
|
|
|
|
this.wrapper.appendChild(indicator.el);
|
|
|
indicators.push(indicator);
|
|
|
}
|
|
|
|
|
|
// Horizontal scrollbar
|
|
|
if (this.options.scrollX) {
|
|
|
indicator = {
|
|
|
el: this._createScrollBar(CLASS_SCROLLBAR_HORIZONTAL),
|
|
|
listenY: false
|
|
|
};
|
|
|
|
|
|
this.wrapper.appendChild(indicator.el);
|
|
|
indicators.push(indicator);
|
|
|
}
|
|
|
|
|
|
for (var i = indicators.length; i--;) {
|
|
|
this.indicators.push(new Indicator(this, indicators[i]));
|
|
|
}
|
|
|
|
|
|
},
|
|
|
_initSnap: function() {
|
|
|
this.currentPage = {};
|
|
|
this.pages = [];
|
|
|
var snaps = this.snaps;
|
|
|
var length = snaps.length;
|
|
|
var m = 0;
|
|
|
var n = -1;
|
|
|
var x = 0;
|
|
|
var leftX = 0;
|
|
|
var rightX = 0;
|
|
|
var snapX = 0;
|
|
|
for (var i = 0; i < length; i++) {
|
|
|
var snap = snaps[i];
|
|
|
var offsetLeft = snap.offsetLeft;
|
|
|
var offsetWidth = snap.offsetWidth;
|
|
|
if (i === 0 || offsetLeft <= snaps[i - 1].offsetLeft) {
|
|
|
m = 0;
|
|
|
n++;
|
|
|
}
|
|
|
if (!this.pages[m]) {
|
|
|
this.pages[m] = [];
|
|
|
}
|
|
|
x = this._getSnapX(offsetLeft);
|
|
|
snapX = Math.round((offsetWidth) * this.options.snapX);
|
|
|
leftX = x - snapX;
|
|
|
rightX = x - offsetWidth + snapX;
|
|
|
this.pages[m][n] = {
|
|
|
x: x,
|
|
|
leftX: leftX,
|
|
|
rightX: rightX,
|
|
|
pageX: m,
|
|
|
element: snap
|
|
|
}
|
|
|
if (snap.classList.contains(CLASS_ACTIVE)) {
|
|
|
this.currentPage = this.pages[m][0];
|
|
|
}
|
|
|
if (x >= this.maxScrollX) {
|
|
|
m++;
|
|
|
}
|
|
|
}
|
|
|
this.options.startX = this.currentPage.x || 0;
|
|
|
},
|
|
|
_getSnapX: function(offsetLeft) {
|
|
|
return Math.max(Math.min(0, -offsetLeft + (this.wrapperWidth / 2)), this.maxScrollX);
|
|
|
},
|
|
|
_gotoPage: function(index) {
|
|
|
this.currentPage = this.pages[Math.min(index, this.pages.length - 1)][0];
|
|
|
for (var i = 0, len = this.snaps.length; i < len; i++) {
|
|
|
if (i === index) {
|
|
|
this.snaps[i].classList.add(CLASS_ACTIVE);
|
|
|
} else {
|
|
|
this.snaps[i].classList.remove(CLASS_ACTIVE);
|
|
|
}
|
|
|
}
|
|
|
this.scrollTo(this.currentPage.x, 0, this.options.scrollTime);
|
|
|
},
|
|
|
_nearestSnap: function(x) {
|
|
|
if (!this.pages.length) {
|
|
|
return {
|
|
|
x: 0,
|
|
|
pageX: 0
|
|
|
};
|
|
|
}
|
|
|
var i = 0;
|
|
|
var length = this.pages.length;
|
|
|
if (x > 0) {
|
|
|
x = 0;
|
|
|
} else if (x < this.maxScrollX) {
|
|
|
x = this.maxScrollX;
|
|
|
}
|
|
|
for (; i < length; i++) {
|
|
|
var nearestX = this.direction === 'left' ? this.pages[i][0].leftX : this.pages[i][0].rightX;
|
|
|
if (x >= nearestX) {
|
|
|
return this.pages[i][0];
|
|
|
}
|
|
|
}
|
|
|
return {
|
|
|
x: 0,
|
|
|
pageX: 0
|
|
|
};
|
|
|
},
|
|
|
_initEvent: function(detach) {
|
|
|
var action = detach ? 'removeEventListener' : 'addEventListener';
|
|
|
window[action]('orientationchange', this);
|
|
|
window[action]('resize', this);
|
|
|
|
|
|
this.scroller[action]('webkitTransitionEnd', this);
|
|
|
|
|
|
this.wrapper[action]($.EVENT_START, this);
|
|
|
this.wrapper[action]($.EVENT_CANCEL, this);
|
|
|
this.wrapper[action]($.EVENT_END, this);
|
|
|
this.wrapper[action]('drag', this);
|
|
|
this.wrapper[action]('dragend', this);
|
|
|
this.wrapper[action]('flick', this);
|
|
|
this.wrapper[action]('scrollend', this);
|
|
|
if (this.options.scrollX) {
|
|
|
this.wrapper[action]('swiperight', this);
|
|
|
}
|
|
|
var segmentedControl = this.wrapper.querySelector('.mui-segmented-control');
|
|
|
if (segmentedControl) { //靠,这个bug排查了一下午,阻止hash跳转,一旦hash跳转会导致可拖拽选项卡的tab不见
|
|
|
mui(segmentedControl)[detach ? 'off' : 'on']('click', 'a', $.preventDefault);
|
|
|
}
|
|
|
|
|
|
this.wrapper[action]('scrollstart', this);
|
|
|
this.wrapper[action]('refresh', this);
|
|
|
},
|
|
|
_handleIndicatorScrollend: function() {
|
|
|
this.indicators.map(function(indicator) {
|
|
|
indicator.fade();
|
|
|
});
|
|
|
},
|
|
|
_handleIndicatorScrollstart: function() {
|
|
|
this.indicators.map(function(indicator) {
|
|
|
indicator.fade(1);
|
|
|
});
|
|
|
},
|
|
|
_handleIndicatorRefresh: function() {
|
|
|
this.indicators.map(function(indicator) {
|
|
|
indicator.refresh();
|
|
|
});
|
|
|
},
|
|
|
handleEvent: function(e) {
|
|
|
if (this.stopped) {
|
|
|
this.resetPosition();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
switch (e.type) {
|
|
|
case $.EVENT_START:
|
|
|
this._start(e);
|
|
|
break;
|
|
|
case 'drag':
|
|
|
this.options.stopPropagation && e.stopPropagation();
|
|
|
this._drag(e);
|
|
|
break;
|
|
|
case 'dragend':
|
|
|
case 'flick':
|
|
|
this.options.stopPropagation && e.stopPropagation();
|
|
|
this._flick(e);
|
|
|
break;
|
|
|
case $.EVENT_CANCEL:
|
|
|
case $.EVENT_END:
|
|
|
this._end(e);
|
|
|
break;
|
|
|
case 'webkitTransitionEnd':
|
|
|
this.transitionTimer && this.transitionTimer.cancel();
|
|
|
this._transitionEnd(e);
|
|
|
break;
|
|
|
case 'scrollstart':
|
|
|
this._handleIndicatorScrollstart(e);
|
|
|
break;
|
|
|
case 'scrollend':
|
|
|
this._handleIndicatorScrollend(e);
|
|
|
this._scrollend(e);
|
|
|
e.stopPropagation();
|
|
|
break;
|
|
|
case 'orientationchange':
|
|
|
case 'resize':
|
|
|
this._resize();
|
|
|
break;
|
|
|
case 'swiperight':
|
|
|
e.stopPropagation();
|
|
|
break;
|
|
|
case 'refresh':
|
|
|
this._handleIndicatorRefresh(e);
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
},
|
|
|
_start: function(e) {
|
|
|
this.moved = this.needReset = false;
|
|
|
this._transitionTime();
|
|
|
if (this.isInTransition) {
|
|
|
this.needReset = true;
|
|
|
this.isInTransition = false;
|
|
|
var pos = $.parseTranslateMatrix($.getStyles(this.scroller, 'webkitTransform'));
|
|
|
this.setTranslate(Math.round(pos.x), Math.round(pos.y));
|
|
|
// this.resetPosition(); //reset
|
|
|
$.trigger(this.scroller, 'scrollend', this);
|
|
|
// e.stopPropagation();
|
|
|
e.preventDefault();
|
|
|
}
|
|
|
this.reLayout();
|
|
|
$.trigger(this.scroller, 'beforescrollstart', this);
|
|
|
},
|
|
|
_getDirectionByAngle: function(angle) {
|
|
|
if (angle < -80 && angle > -100) {
|
|
|
return 'up';
|
|
|
} else if (angle >= 80 && angle < 100) {
|
|
|
return 'down';
|
|
|
} else if (angle >= 170 || angle <= -170) {
|
|
|
return 'left';
|
|
|
} else if (angle >= -35 && angle <= 10) {
|
|
|
return 'right';
|
|
|
}
|
|
|
return null;
|
|
|
},
|
|
|
_drag: function(e) {
|
|
|
// if (this.needReset) {
|
|
|
// e.stopPropagation(); //disable parent drag(nested scroller)
|
|
|
// return;
|
|
|
// }
|
|
|
var detail = e.detail;
|
|
|
if (this.options.scrollY || detail.direction === 'up' || detail.direction === 'down') { //如果是竖向滚动或手势方向是上或下
|
|
|
//ios8 hack
|
|
|
if ($.os.ios && parseFloat($.os.version) >= 8) { //多webview时,离开当前webview会导致后续touch事件不触发
|
|
|
var clientY = detail.gesture.touches[0].clientY;
|
|
|
//下拉刷新 or 上拉加载
|
|
|
if ((clientY + 10) > window.innerHeight || clientY < 10) {
|
|
|
this.resetPosition(this.options.bounceTime);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
var isPreventDefault = isReturn = false;
|
|
|
var direction = this._getDirectionByAngle(detail.angle);
|
|
|
if (detail.direction === 'left' || detail.direction === 'right') {
|
|
|
if (this.options.scrollX) {
|
|
|
isPreventDefault = true;
|
|
|
if (!this.moved) { //识别角度(该角度导致轮播不灵敏)
|
|
|
// if (direction !== 'left' && direction !== 'right') {
|
|
|
// isReturn = true;
|
|
|
// } else {
|
|
|
$.gestures.session.lockDirection = true; //锁定方向
|
|
|
$.gestures.session.startDirection = detail.direction;
|
|
|
// }
|
|
|
}
|
|
|
} else if (this.options.scrollY && !this.moved) {
|
|
|
isReturn = true;
|
|
|
}
|
|
|
} else if (detail.direction === 'up' || detail.direction === 'down') {
|
|
|
if (this.options.scrollY) {
|
|
|
isPreventDefault = true;
|
|
|
// if (!this.moved) { //识别角度,竖向滚动似乎没必要进行小角度验证
|
|
|
// if (direction !== 'up' && direction !== 'down') {
|
|
|
// isReturn = true;
|
|
|
// }
|
|
|
// }
|
|
|
if (!this.moved) {
|
|
|
$.gestures.session.lockDirection = true; //锁定方向
|
|
|
$.gestures.session.startDirection = detail.direction;
|
|
|
}
|
|
|
} else if (this.options.scrollX && !this.moved) {
|
|
|
isReturn = true;
|
|
|
}
|
|
|
} else {
|
|
|
isReturn = true;
|
|
|
}
|
|
|
if (this.moved || isPreventDefault) {
|
|
|
e.stopPropagation(); //阻止冒泡(scroll类嵌套)
|
|
|
detail.gesture && detail.gesture.preventDefault();
|
|
|
}
|
|
|
if (isReturn) { //禁止非法方向滚动
|
|
|
return;
|
|
|
}
|
|
|
if (!this.moved) {
|
|
|
$.trigger(this.scroller, 'scrollstart', this);
|
|
|
} else {
|
|
|
e.stopPropagation(); //move期间阻止冒泡(scroll嵌套)
|
|
|
}
|
|
|
var deltaX = 0;
|
|
|
var deltaY = 0;
|
|
|
if (!this.moved) { //start
|
|
|
deltaX = detail.deltaX;
|
|
|
deltaY = detail.deltaY;
|
|
|
} else { //move
|
|
|
deltaX = detail.deltaX - $.gestures.session.prevTouch.deltaX;
|
|
|
deltaY = detail.deltaY - $.gestures.session.prevTouch.deltaY;
|
|
|
}
|
|
|
var absDeltaX = Math.abs(detail.deltaX);
|
|
|
var absDeltaY = Math.abs(detail.deltaY);
|
|
|
if (absDeltaX > absDeltaY + this.options.directionLockThreshold) {
|
|
|
deltaY = 0;
|
|
|
} else if (absDeltaY >= absDeltaX + this.options.directionLockThreshold) {
|
|
|
deltaX = 0;
|
|
|
}
|
|
|
|
|
|
deltaX = this.hasHorizontalScroll ? deltaX : 0;
|
|
|
deltaY = this.hasVerticalScroll ? deltaY : 0;
|
|
|
var newX = this.x + deltaX;
|
|
|
var newY = this.y + deltaY;
|
|
|
// Slow down if outside of the boundaries
|
|
|
if (newX > 0 || newX < this.maxScrollX) {
|
|
|
newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
|
|
|
}
|
|
|
if (newY > 0 || newY < this.maxScrollY) {
|
|
|
newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
|
|
|
}
|
|
|
|
|
|
if (!this.requestAnimationFrame) {
|
|
|
this._updateTranslate();
|
|
|
}
|
|
|
this.direction = detail.deltaX > 0 ? 'right' : 'left';
|
|
|
this.moved = true;
|
|
|
this.x = newX;
|
|
|
this.y = newY;
|
|
|
$.trigger(this.scroller, 'scroll', this);
|
|
|
},
|
|
|
_flick: function(e) {
|
|
|
// if (!this.moved || this.needReset) {
|
|
|
// return;
|
|
|
// }
|
|
|
if (!this.moved) {
|
|
|
return;
|
|
|
}
|
|
|
e.stopPropagation();
|
|
|
var detail = e.detail;
|
|
|
this._clearRequestAnimationFrame();
|
|
|
if (e.type === 'dragend' && detail.flick) { //dragend
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
var newX = Math.round(this.x);
|
|
|
var newY = Math.round(this.y);
|
|
|
|
|
|
this.isInTransition = false;
|
|
|
// reset if we are outside of the boundaries
|
|
|
if (this.resetPosition(this.options.bounceTime)) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
this.scrollTo(newX, newY); // ensures that the last position is rounded
|
|
|
|
|
|
if (e.type === 'dragend') { //dragend
|
|
|
$.trigger(this.scroller, 'scrollend', this);
|
|
|
return;
|
|
|
}
|
|
|
var time = 0;
|
|
|
var easing = '';
|
|
|
// start momentum animation if needed
|
|
|
if (this.options.momentum && detail.flickTime < 300) {
|
|
|
momentumX = this.hasHorizontalScroll ? this._momentum(this.x, detail.flickDistanceX, detail.flickTime, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : {
|
|
|
destination: newX,
|
|
|
duration: 0
|
|
|
};
|
|
|
momentumY = this.hasVerticalScroll ? this._momentum(this.y, detail.flickDistanceY, detail.flickTime, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : {
|
|
|
destination: newY,
|
|
|
duration: 0
|
|
|
};
|
|
|
newX = momentumX.destination;
|
|
|
newY = momentumY.destination;
|
|
|
time = Math.max(momentumX.duration, momentumY.duration);
|
|
|
this.isInTransition = true;
|
|
|
}
|
|
|
|
|
|
if (newX != this.x || newY != this.y) {
|
|
|
if (newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY) {
|
|
|
easing = ease.quadratic;
|
|
|
}
|
|
|
this.scrollTo(newX, newY, time, easing);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
$.trigger(this.scroller, 'scrollend', this);
|
|
|
// e.stopPropagation();
|
|
|
},
|
|
|
_end: function(e) {
|
|
|
this.needReset = false;
|
|
|
if ((!this.moved && this.needReset) || e.type === $.EVENT_CANCEL) {
|
|
|
this.resetPosition();
|
|
|
}
|
|
|
},
|
|
|
_transitionEnd: function(e) {
|
|
|
if (e.target != this.scroller || !this.isInTransition) {
|
|
|
return;
|
|
|
}
|
|
|
this._transitionTime();
|
|
|
if (!this.resetPosition(this.options.bounceTime)) {
|
|
|
this.isInTransition = false;
|
|
|
$.trigger(this.scroller, 'scrollend', this);
|
|
|
}
|
|
|
},
|
|
|
_scrollend: function(e) {
|
|
|
if ((this.y === 0 && this.maxScrollY === 0) || (Math.abs(this.y) > 0 && this.y <= this.maxScrollY)) {
|
|
|
$.trigger(this.scroller, 'scrollbottom', this);
|
|
|
}
|
|
|
},
|
|
|
_resize: function() {
|
|
|
var that = this;
|
|
|
clearTimeout(that.resizeTimeout);
|
|
|
that.resizeTimeout = setTimeout(function() {
|
|
|
that.refresh();
|
|
|
}, that.options.resizePolling);
|
|
|
},
|
|
|
_transitionTime: function(time) {
|
|
|
time = time || 0;
|
|
|
this.scrollerStyle['webkitTransitionDuration'] = time + 'ms';
|
|
|
if (this.parallaxElement && this.options.scrollY) { //目前仅支持竖向视差效果
|
|
|
this.parallaxStyle['webkitTransitionDuration'] = time + 'ms';
|
|
|
}
|
|
|
if (this.options.fixedBadAndorid && !time && $.os.isBadAndroid) {
|
|
|
this.scrollerStyle['webkitTransitionDuration'] = '0.001s';
|
|
|
if (this.parallaxElement && this.options.scrollY) { //目前仅支持竖向视差效果
|
|
|
this.parallaxStyle['webkitTransitionDuration'] = '0.001s';
|
|
|
}
|
|
|
}
|
|
|
if (this.indicators) {
|
|
|
for (var i = this.indicators.length; i--;) {
|
|
|
this.indicators[i].transitionTime(time);
|
|
|
}
|
|
|
}
|
|
|
if (time) { //自定义timer,保证webkitTransitionEnd始终触发
|
|
|
this.transitionTimer && this.transitionTimer.cancel();
|
|
|
this.transitionTimer = $.later(function() {
|
|
|
$.trigger(this.scroller, 'webkitTransitionEnd');
|
|
|
}, time + 100, this);
|
|
|
}
|
|
|
},
|
|
|
_transitionTimingFunction: function(easing) {
|
|
|
this.scrollerStyle['webkitTransitionTimingFunction'] = easing;
|
|
|
if (this.parallaxElement && this.options.scrollY) { //目前仅支持竖向视差效果
|
|
|
this.parallaxStyle['webkitTransitionDuration'] = easing;
|
|
|
}
|
|
|
if (this.indicators) {
|
|
|
for (var i = this.indicators.length; i--;) {
|
|
|
this.indicators[i].transitionTimingFunction(easing);
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
_translate: function(x, y) {
|
|
|
this.x = x;
|
|
|
this.y = y;
|
|
|
},
|
|
|
_clearRequestAnimationFrame: function() {
|
|
|
if (this.requestAnimationFrame) {
|
|
|
cancelAnimationFrame(this.requestAnimationFrame);
|
|
|
this.requestAnimationFrame = null;
|
|
|
}
|
|
|
},
|
|
|
_updateTranslate: function() {
|
|
|
var self = this;
|
|
|
if (self.x !== self.lastX || self.y !== self.lastY) {
|
|
|
self.setTranslate(self.x, self.y);
|
|
|
}
|
|
|
self.requestAnimationFrame = requestAnimationFrame(function() {
|
|
|
self._updateTranslate();
|
|
|
});
|
|
|
},
|
|
|
_createScrollBar: function(clazz) {
|
|
|
var scrollbar = document.createElement('div');
|
|
|
var indicator = document.createElement('div');
|
|
|
scrollbar.className = CLASS_SCROLLBAR + ' ' + clazz;
|
|
|
indicator.className = CLASS_INDICATOR;
|
|
|
scrollbar.appendChild(indicator);
|
|
|
if (clazz === CLASS_SCROLLBAR_VERTICAL) {
|
|
|
this.scrollbarY = scrollbar;
|
|
|
this.scrollbarIndicatorY = indicator;
|
|
|
} else if (clazz === CLASS_SCROLLBAR_HORIZONTAL) {
|
|
|
this.scrollbarX = scrollbar;
|
|
|
this.scrollbarIndicatorX = indicator;
|
|
|
}
|
|
|
this.wrapper.appendChild(scrollbar);
|
|
|
return scrollbar;
|
|
|
},
|
|
|
_preventDefaultException: function(el, exceptions) {
|
|
|
for (var i in exceptions) {
|
|
|
if (exceptions[i].test(el[i])) {
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
},
|
|
|
_reLayout: function() {
|
|
|
if (!this.hasHorizontalScroll) {
|
|
|
this.maxScrollX = 0;
|
|
|
this.scrollerWidth = this.wrapperWidth;
|
|
|
}
|
|
|
|
|
|
if (!this.hasVerticalScroll) {
|
|
|
this.maxScrollY = 0;
|
|
|
this.scrollerHeight = this.wrapperHeight;
|
|
|
}
|
|
|
|
|
|
this.indicators.map(function(indicator) {
|
|
|
indicator.refresh();
|
|
|
});
|
|
|
|
|
|
//以防slider类嵌套使用
|
|
|
if (this.options.snap && typeof this.options.snap === 'string') {
|
|
|
var items = this.scroller.querySelectorAll(this.options.snap);
|
|
|
this.itemLength = 0;
|
|
|
this.snaps = [];
|
|
|
for (var i = 0, len = items.length; i < len; i++) {
|
|
|
var item = items[i];
|
|
|
if (item.parentNode === this.scroller) {
|
|
|
this.itemLength++;
|
|
|
this.snaps.push(item);
|
|
|
}
|
|
|
}
|
|
|
this._initSnap(); //需要每次都_initSnap么。其实init的时候执行一次,后续resize的时候执行一次就行了吧.先这么做吧,如果影响性能,再调整
|
|
|
}
|
|
|
},
|
|
|
_momentum: function(current, distance, time, lowerMargin, wrapperSize, deceleration) {
|
|
|
var speed = parseFloat(Math.abs(distance) / time),
|
|
|
destination,
|
|
|
duration;
|
|
|
|
|
|
deceleration = deceleration === undefined ? 0.0006 : deceleration;
|
|
|
destination = current + (speed * speed) / (2 * deceleration) * (distance < 0 ? -1 : 1);
|
|
|
duration = speed / deceleration;
|
|
|
if (destination < lowerMargin) {
|
|
|
destination = wrapperSize ? lowerMargin - (wrapperSize / 2.5 * (speed / 8)) : lowerMargin;
|
|
|
distance = Math.abs(destination - current);
|
|
|
duration = distance / speed;
|
|
|
} else if (destination > 0) {
|
|
|
destination = wrapperSize ? wrapperSize / 2.5 * (speed / 8) : 0;
|
|
|
distance = Math.abs(current) + destination;
|
|
|
duration = distance / speed;
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
destination: Math.round(destination),
|
|
|
duration: duration
|
|
|
};
|
|
|
},
|
|
|
_getTranslateStr: function(x, y) {
|
|
|
if (this.options.hardwareAccelerated) {
|
|
|
return 'translate3d(' + x + 'px,' + y + 'px,0px) ' + this.translateZ;
|
|
|
}
|
|
|
return 'translate(' + x + 'px,' + y + 'px) ';
|
|
|
},
|
|
|
//API
|
|
|
setStopped: function(stopped) {
|
|
|
// this.stopped = !!stopped;
|
|
|
|
|
|
// fixed ios双webview模式下拉刷新
|
|
|
if(stopped) {
|
|
|
this.disablePullupToRefresh();
|
|
|
this.disablePulldownToRefresh();
|
|
|
} else {
|
|
|
this.enablePullupToRefresh();
|
|
|
this.enablePulldownToRefresh();
|
|
|
}
|
|
|
},
|
|
|
setTranslate: function(x, y) {
|
|
|
this.x = x;
|
|
|
this.y = y;
|
|
|
this.scrollerStyle['webkitTransform'] = this._getTranslateStr(x, y);
|
|
|
if (this.parallaxElement && this.options.scrollY) { //目前仅支持竖向视差效果
|
|
|
var parallaxY = y * this.options.parallaxRatio;
|
|
|
var scale = 1 + parallaxY / ((this.parallaxHeight - parallaxY) / 2);
|
|
|
if (scale > 1) {
|
|
|
this.parallaxImgStyle['opacity'] = 1 - parallaxY / 100 * this.options.parallaxRatio;
|
|
|
this.parallaxStyle['webkitTransform'] = this._getTranslateStr(0, -parallaxY) + ' scale(' + scale + ',' + scale + ')';
|
|
|
} else {
|
|
|
this.parallaxImgStyle['opacity'] = 1;
|
|
|
this.parallaxStyle['webkitTransform'] = this._getTranslateStr(0, -1) + ' scale(1,1)';
|
|
|
}
|
|
|
}
|
|
|
if (this.indicators) {
|
|
|
for (var i = this.indicators.length; i--;) {
|
|
|
this.indicators[i].updatePosition();
|
|
|
}
|
|
|
}
|
|
|
this.lastX = this.x;
|
|
|
this.lastY = this.y;
|
|
|
$.trigger(this.scroller, 'scroll', this);
|
|
|
},
|
|
|
reLayout: function() {
|
|
|
this.wrapper.offsetHeight;
|
|
|
|
|
|
var paddingLeft = parseFloat($.getStyles(this.wrapper, 'padding-left')) || 0;
|
|
|
var paddingRight = parseFloat($.getStyles(this.wrapper, 'padding-right')) || 0;
|
|
|
var paddingTop = parseFloat($.getStyles(this.wrapper, 'padding-top')) || 0;
|
|
|
var paddingBottom = parseFloat($.getStyles(this.wrapper, 'padding-bottom')) || 0;
|
|
|
|
|
|
var clientWidth = this.wrapper.clientWidth;
|
|
|
var clientHeight = this.wrapper.clientHeight;
|
|
|
|
|
|
this.scrollerWidth = this.scroller.offsetWidth;
|
|
|
this.scrollerHeight = this.scroller.offsetHeight;
|
|
|
|
|
|
this.wrapperWidth = clientWidth - paddingLeft - paddingRight;
|
|
|
this.wrapperHeight = clientHeight - paddingTop - paddingBottom;
|
|
|
|
|
|
this.maxScrollX = Math.min(this.wrapperWidth - this.scrollerWidth, 0);
|
|
|
this.maxScrollY = Math.min(this.wrapperHeight - this.scrollerHeight, 0);
|
|
|
this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0;
|
|
|
this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0;
|
|
|
this._reLayout();
|
|
|
},
|
|
|
resetPosition: function(time) {
|
|
|
var x = this.x,
|
|
|
y = this.y;
|
|
|
|
|
|
time = time || 0;
|
|
|
if (!this.hasHorizontalScroll || this.x > 0) {
|
|
|
x = 0;
|
|
|
} else if (this.x < this.maxScrollX) {
|
|
|
x = this.maxScrollX;
|
|
|
}
|
|
|
|
|
|
if (!this.hasVerticalScroll || this.y > 0) {
|
|
|
y = 0;
|
|
|
} else if (this.y < this.maxScrollY) {
|
|
|
y = this.maxScrollY;
|
|
|
}
|
|
|
|
|
|
if (x == this.x && y == this.y) {
|
|
|
return false;
|
|
|
}
|
|
|
this.scrollTo(x, y, time, this.options.scrollEasing);
|
|
|
|
|
|
return true;
|
|
|
},
|
|
|
_reInit: function() {
|
|
|
var groups = this.wrapper.querySelectorAll('.' + CLASS_SCROLL);
|
|
|
for (var i = 0, len = groups.length; i < len; i++) {
|
|
|
if (groups[i].parentNode === this.wrapper) {
|
|
|
this.scroller = groups[i];
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
this.scrollerStyle = this.scroller && this.scroller.style;
|
|
|
},
|
|
|
refresh: function() {
|
|
|
this._reInit();
|
|
|
this.reLayout();
|
|
|
$.trigger(this.scroller, 'refresh', this);
|
|
|
this.resetPosition();
|
|
|
},
|
|
|
scrollTo: function(x, y, time, easing) {
|
|
|
var easing = easing || ease.circular;
|
|
|
// this.isInTransition = time > 0 && (this.lastX != x || this.lastY != y);
|
|
|
//暂不严格判断x,y,否则会导致部分版本上不正常触发轮播
|
|
|
this.isInTransition = time > 0;
|
|
|
if (this.isInTransition) {
|
|
|
this._clearRequestAnimationFrame();
|
|
|
this._transitionTimingFunction(easing.style);
|
|
|
this._transitionTime(time);
|
|
|
this.setTranslate(x, y);
|
|
|
} else {
|
|
|
this.setTranslate(x, y);
|
|
|
}
|
|
|
|
|
|
},
|
|
|
scrollToBottom: function(time, easing) {
|
|
|
time = time || this.options.scrollTime;
|
|
|
this.scrollTo(0, this.maxScrollY, time, easing);
|
|
|
},
|
|
|
gotoPage: function(index) {
|
|
|
this._gotoPage(index);
|
|
|
},
|
|
|
destroy: function() {
|
|
|
this._initEvent(true); //detach
|
|
|
delete $.data[this.wrapper.getAttribute('data-scroll')];
|
|
|
this.wrapper.setAttribute('data-scroll', '');
|
|
|
}
|
|
|
});
|
|
|
//Indicator
|
|
|
var Indicator = function(scroller, options) {
|
|
|
this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
|
|
|
this.wrapperStyle = this.wrapper.style;
|
|
|
this.indicator = this.wrapper.children[0];
|
|
|
this.indicatorStyle = this.indicator.style;
|
|
|
this.scroller = scroller;
|
|
|
|
|
|
this.options = $.extend({
|
|
|
listenX: true,
|
|
|
listenY: true,
|
|
|
fade: false,
|
|
|
speedRatioX: 0,
|
|
|
speedRatioY: 0
|
|
|
}, options);
|
|
|
|
|
|
this.sizeRatioX = 1;
|
|
|
this.sizeRatioY = 1;
|
|
|
this.maxPosX = 0;
|
|
|
this.maxPosY = 0;
|
|
|
|
|
|
if (this.options.fade) {
|
|
|
this.wrapperStyle['webkitTransform'] = this.scroller.translateZ;
|
|
|
this.wrapperStyle['webkitTransitionDuration'] = this.options.fixedBadAndorid && $.os.isBadAndroid ? '0.001s' : '0ms';
|
|
|
this.wrapperStyle.opacity = '0';
|
|
|
}
|
|
|
}
|
|
|
Indicator.prototype = {
|
|
|
handleEvent: function(e) {
|
|
|
|
|
|
},
|
|
|
transitionTime: function(time) {
|
|
|
time = time || 0;
|
|
|
this.indicatorStyle['webkitTransitionDuration'] = time + 'ms';
|
|
|
if (this.scroller.options.fixedBadAndorid && !time && $.os.isBadAndroid) {
|
|
|
this.indicatorStyle['webkitTransitionDuration'] = '0.001s';
|
|
|
}
|
|
|
},
|
|
|
transitionTimingFunction: function(easing) {
|
|
|
this.indicatorStyle['webkitTransitionTimingFunction'] = easing;
|
|
|
},
|
|
|
refresh: function() {
|
|
|
this.transitionTime();
|
|
|
|
|
|
if (this.options.listenX && !this.options.listenY) {
|
|
|
this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
|
|
|
} else if (this.options.listenY && !this.options.listenX) {
|
|
|
this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
|
|
|
} else {
|
|
|
this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
|
|
|
}
|
|
|
|
|
|
this.wrapper.offsetHeight; // force refresh
|
|
|
|
|
|
if (this.options.listenX) {
|
|
|
this.wrapperWidth = this.wrapper.clientWidth;
|
|
|
this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
|
|
|
this.indicatorStyle.width = this.indicatorWidth + 'px';
|
|
|
|
|
|
this.maxPosX = this.wrapperWidth - this.indicatorWidth;
|
|
|
|
|
|
this.minBoundaryX = 0;
|
|
|
this.maxBoundaryX = this.maxPosX;
|
|
|
|
|
|
this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
|
|
|
}
|
|
|
|
|
|
if (this.options.listenY) {
|
|
|
this.wrapperHeight = this.wrapper.clientHeight;
|
|
|
this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
|
|
|
this.indicatorStyle.height = this.indicatorHeight + 'px';
|
|
|
|
|
|
this.maxPosY = this.wrapperHeight - this.indicatorHeight;
|
|
|
|
|
|
this.minBoundaryY = 0;
|
|
|
this.maxBoundaryY = this.maxPosY;
|
|
|
|
|
|
this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
|
|
|
}
|
|
|
|
|
|
this.updatePosition();
|
|
|
},
|
|
|
|
|
|
updatePosition: function() {
|
|
|
var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
|
|
|
y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;
|
|
|
|
|
|
if (x < this.minBoundaryX) {
|
|
|
this.width = Math.max(this.indicatorWidth + x, 8);
|
|
|
this.indicatorStyle.width = this.width + 'px';
|
|
|
x = this.minBoundaryX;
|
|
|
} else if (x > this.maxBoundaryX) {
|
|
|
this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
|
|
|
this.indicatorStyle.width = this.width + 'px';
|
|
|
x = this.maxPosX + this.indicatorWidth - this.width;
|
|
|
} else if (this.width != this.indicatorWidth) {
|
|
|
this.width = this.indicatorWidth;
|
|
|
this.indicatorStyle.width = this.width + 'px';
|
|
|
}
|
|
|
|
|
|
if (y < this.minBoundaryY) {
|
|
|
this.height = Math.max(this.indicatorHeight + y * 3, 8);
|
|
|
this.indicatorStyle.height = this.height + 'px';
|
|
|
y = this.minBoundaryY;
|
|
|
} else if (y > this.maxBoundaryY) {
|
|
|
this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
|
|
|
this.indicatorStyle.height = this.height + 'px';
|
|
|
y = this.maxPosY + this.indicatorHeight - this.height;
|
|
|
} else if (this.height != this.indicatorHeight) {
|
|
|
this.height = this.indicatorHeight;
|
|
|
this.indicatorStyle.height = this.height + 'px';
|
|
|
}
|
|
|
|
|
|
this.x = x;
|
|
|
this.y = y;
|
|
|
|
|
|
this.indicatorStyle['webkitTransform'] = this.scroller._getTranslateStr(x, y);
|
|
|
|
|
|
},
|
|
|
fade: function(val, hold) {
|
|
|
if (hold && !this.visible) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
clearTimeout(this.fadeTimeout);
|
|
|
this.fadeTimeout = null;
|
|
|
|
|
|
var time = val ? 250 : 500,
|
|
|
delay = val ? 0 : 300;
|
|
|
|
|
|
val = val ? '1' : '0';
|
|
|
|
|
|
this.wrapperStyle['webkitTransitionDuration'] = time + 'ms';
|
|
|
|
|
|
this.fadeTimeout = setTimeout((function(val) {
|
|
|
this.wrapperStyle.opacity = val;
|
|
|
this.visible = +val;
|
|
|
}).bind(this, val), delay);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
$.Scroll = Scroll;
|
|
|
|
|
|
$.fn.scroll = function(options) {
|
|
|
var scrollApis = [];
|
|
|
this.each(function() {
|
|
|
var scrollApi = null;
|
|
|
var self = this;
|
|
|
var id = self.getAttribute('data-scroll');
|
|
|
if (!id) {
|
|
|
id = ++$.uuid;
|
|
|
var _options = $.extend({}, options);
|
|
|
if (self.classList.contains('mui-segmented-control')) {
|
|
|
_options = $.extend(_options, {
|
|
|
scrollY: false,
|
|
|
scrollX: true,
|
|
|
indicators: false,
|
|
|
snap: '.mui-control-item'
|
|
|
});
|
|
|
}
|
|
|
$.data[id] = scrollApi = new Scroll(self, _options);
|
|
|
self.setAttribute('data-scroll', id);
|
|
|
} else {
|
|
|
scrollApi = $.data[id];
|
|
|
}
|
|
|
scrollApis.push(scrollApi);
|
|
|
});
|
|
|
return scrollApis.length === 1 ? scrollApis[0] : scrollApis;
|
|
|
};
|
|
|
})(mui, window, document);
|
|
|
(function($, window, document, undefined) {
|
|
|
|
|
|
var CLASS_VISIBILITY = 'mui-visibility';
|
|
|
var CLASS_HIDDEN = 'mui-hidden';
|
|
|
|
|
|
var PullRefresh = $.Scroll.extend($.extend({
|
|
|
handleEvent: function(e) {
|
|
|
this._super(e);
|
|
|
if (e.type === 'scrollbottom') {
|
|
|
if (e.target === this.scroller) {
|
|
|
this._scrollbottom();
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
_scrollbottom: function() {
|
|
|
if (!this.pulldown && !this.loading) {
|
|
|
this.pulldown = false;
|
|
|
this._initPullupRefresh();
|
|
|
this.pullupLoading();
|
|
|
}
|
|
|
},
|
|
|
_start: function(e) {
|
|
|
//仅下拉刷新在start阻止默认事件
|
|
|
if (e.touches && e.touches.length && e.touches[0].clientX > 30) {
|
|
|
e.target && !this._preventDefaultException(e.target, this.options.preventDefaultException) && e.preventDefault();
|
|
|
}
|
|
|
if (!this.loading) {
|
|
|
this.pulldown = this.pullPocket = this.pullCaption = this.pullLoading = false
|
|
|
}
|
|
|
this._super(e);
|
|
|
},
|
|
|
_drag: function(e) {
|
|
|
if (this.y >= 0 && this.disablePulldown && e.detail.direction === 'down') { //禁用下拉刷新
|
|
|
return;
|
|
|
}
|
|
|
this._super(e);
|
|
|
if (!this.pulldown && !this.loading && this.topPocket && e.detail.direction === 'down' && this.y >= 0) {
|
|
|
this._initPulldownRefresh();
|
|
|
}
|
|
|
if (this.pulldown) {
|
|
|
this._setCaption(this.y > this.options.down.height ? this.options.down.contentover : this.options.down.contentdown);
|
|
|
}
|
|
|
},
|
|
|
|
|
|
_reLayout: function() {
|
|
|
this.hasVerticalScroll = true;
|
|
|
this._super();
|
|
|
},
|
|
|
//API
|
|
|
resetPosition: function(time) {
|
|
|
if (this.pulldown && !this.disablePulldown) {
|
|
|
if (this.y >= this.options.down.height) {
|
|
|
this.pulldownLoading(undefined, time || 0);
|
|
|
return true;
|
|
|
} else {
|
|
|
!this.loading && this.topPocket.classList.remove(CLASS_VISIBILITY);
|
|
|
}
|
|
|
}
|
|
|
return this._super(time);
|
|
|
},
|
|
|
pulldownLoading: function(y, time) {
|
|
|
typeof y === 'undefined' && (y = this.options.down.height); //默认高度
|
|
|
this.scrollTo(0, y, time, this.options.bounceEasing);
|
|
|
if (this.loading) {
|
|
|
return;
|
|
|
}
|
|
|
// if (!this.pulldown) {
|
|
|
this._initPulldownRefresh();
|
|
|
// }
|
|
|
this._setCaption(this.options.down.contentrefresh);
|
|
|
this.loading = true;
|
|
|
this.indicators.map(function(indicator) {
|
|
|
indicator.fade(0);
|
|
|
});
|
|
|
var callback = this.options.down.callback;
|
|
|
callback && callback.call(this);
|
|
|
},
|
|
|
endPulldownToRefresh: function() {
|
|
|
var self = this;
|
|
|
if (self.topPocket && self.loading && this.pulldown) {
|
|
|
self.scrollTo(0, 0, self.options.bounceTime, self.options.bounceEasing);
|
|
|
self.loading = false;
|
|
|
self._setCaption(self.options.down.contentdown, true);
|
|
|
setTimeout(function() {
|
|
|
self.loading || self.topPocket.classList.remove(CLASS_VISIBILITY);
|
|
|
}, 350);
|
|
|
}
|
|
|
},
|
|
|
pullupLoading: function(callback, x, time) {
|
|
|
x = x || 0;
|
|
|
this.scrollTo(x, this.maxScrollY, time, this.options.bounceEasing);
|
|
|
if (this.loading) {
|
|
|
return;
|
|
|
}
|
|
|
this._initPullupRefresh();
|
|
|
this._setCaption(this.options.up.contentrefresh);
|
|
|
this.indicators.map(function(indicator) {
|
|
|
indicator.fade(0);
|
|
|
});
|
|
|
this.loading = true;
|
|
|
callback = callback || this.options.up.callback;
|
|
|
callback && callback.call(this);
|
|
|
},
|
|
|
endPullupToRefresh: function(finished) {
|
|
|
var self = this;
|
|
|
if (self.bottomPocket) { // && self.loading && !this.pulldown
|
|
|
self.loading = false;
|
|
|
if (finished) {
|
|
|
this.finished = true;
|
|
|
self._setCaption(self.options.up.contentnomore);
|
|
|
// self.bottomPocket.classList.remove(CLASS_VISIBILITY);
|
|
|
// self.bottomPocket.classList.add(CLASS_HIDDEN);
|
|
|
self.wrapper.removeEventListener('scrollbottom', self);
|
|
|
} else {
|
|
|
self._setCaption(self.options.up.contentdown);
|
|
|
// setTimeout(function() {
|
|
|
self.loading || self.bottomPocket.classList.remove(CLASS_VISIBILITY);
|
|
|
// }, 300);
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
disablePullupToRefresh: function() {
|
|
|
this._initPullupRefresh();
|
|
|
this.bottomPocket.className = 'mui-pull-bottom-pocket' + ' ' + CLASS_HIDDEN;
|
|
|
this.wrapper.removeEventListener('scrollbottom', this);
|
|
|
},
|
|
|
disablePulldownToRefresh: function() {
|
|
|
this._initPulldownRefresh();
|
|
|
this.topPocket.className = 'mui-pull-top-pocket' + ' ' + CLASS_HIDDEN;
|
|
|
this.disablePulldown = true;
|
|
|
},
|
|
|
enablePulldownToRefresh: function() {
|
|
|
this._initPulldownRefresh();
|
|
|
this.topPocket.classList.remove(CLASS_HIDDEN);
|
|
|
this._setCaption(this.options.down.contentdown);
|
|
|
this.disablePulldown = false;
|
|
|
},
|
|
|
enablePullupToRefresh: function() {
|
|
|
this._initPullupRefresh();
|
|
|
this.bottomPocket.classList.remove(CLASS_HIDDEN);
|
|
|
this._setCaption(this.options.up.contentdown);
|
|
|
this.wrapper.addEventListener('scrollbottom', this);
|
|
|
},
|
|
|
refresh: function(isReset) {
|
|
|
if (isReset && this.finished) {
|
|
|
this.enablePullupToRefresh();
|
|
|
this.finished = false;
|
|
|
}
|
|
|
this._super();
|
|
|
},
|
|
|
}, $.PullRefresh));
|
|
|
$.fn.pullRefresh = function(options) {
|
|
|
if (this.length === 1) {
|
|
|
var self = this[0];
|
|
|
var pullRefreshApi = null;
|
|
|
var id = self.getAttribute('data-pullrefresh');
|
|
|
if (!id && typeof options === 'undefined') {
|
|
|
return false;
|
|
|
}
|
|
|
options = options || {};
|
|
|
if (!id) {
|
|
|
id = ++$.uuid;
|
|
|
$.data[id] = pullRefreshApi = new PullRefresh(self, options);
|
|
|
self.setAttribute('data-pullrefresh', id);
|
|
|
} else {
|
|
|
pullRefreshApi = $.data[id];
|
|
|
}
|
|
|
if (options.down && options.down.auto) { //如果设置了auto,则自动下拉一次
|
|
|
pullRefreshApi.pulldownLoading(options.down.autoY);
|
|
|
} else if (options.up && options.up.auto) { //如果设置了auto,则自动上拉一次
|
|
|
pullRefreshApi.pullupLoading();
|
|
|
}
|
|
|
//暂不提供这种调用方式吧
|
|
|
// if (typeof options === 'string') {
|
|
|
// var methodValue = pullRefreshApi[options].apply(pullRefreshApi, $.slice.call(arguments, 1));
|
|
|
// if (methodValue !== undefined) {
|
|
|
// return methodValue;
|
|
|
// }
|
|
|
// }
|
|
|
return pullRefreshApi;
|
|
|
}
|
|
|
};
|
|
|
})(mui, window, document);
|
|
|
/**
|
|
|
* snap 重构
|
|
|
* @param {Object} $
|
|
|
* @param {Object} window
|
|
|
*/
|
|
|
(function($, window) {
|
|
|
var CLASS_SLIDER = 'mui-slider';
|
|
|
var CLASS_SLIDER_GROUP = 'mui-slider-group';
|
|
|
var CLASS_SLIDER_LOOP = 'mui-slider-loop';
|
|
|
var CLASS_SLIDER_INDICATOR = 'mui-slider-indicator';
|
|
|
var CLASS_ACTION_PREVIOUS = 'mui-action-previous';
|
|
|
var CLASS_ACTION_NEXT = 'mui-action-next';
|
|
|
var CLASS_SLIDER_ITEM = 'mui-slider-item';
|
|
|
|
|
|
var CLASS_ACTIVE = 'mui-active';
|
|
|
|
|
|
var SELECTOR_SLIDER_ITEM = '.' + CLASS_SLIDER_ITEM;
|
|
|
var SELECTOR_SLIDER_INDICATOR = '.' + CLASS_SLIDER_INDICATOR;
|
|
|
var SELECTOR_SLIDER_PROGRESS_BAR = '.mui-slider-progress-bar';
|
|
|
|
|
|
var Slider = $.Slider = $.Scroll.extend({
|
|
|
init: function(element, options) {
|
|
|
this._super(element, $.extend(true, {
|
|
|
fingers: 1,
|
|
|
interval: 0, //设置为0,则不定时轮播
|
|
|
scrollY: false,
|
|
|
scrollX: true,
|
|
|
indicators: false,
|
|
|
scrollTime: 1000,
|
|
|
startX: false,
|
|
|
slideTime: 0, //滑动动画时间
|
|
|
snap: SELECTOR_SLIDER_ITEM
|
|
|
}, options));
|
|
|
if (this.options.startX) {
|
|
|
// $.trigger(this.wrapper, 'scrollend', this);
|
|
|
}
|
|
|
},
|
|
|
_init: function() {
|
|
|
this._reInit();
|
|
|
if (this.scroller) {
|
|
|
this.scrollerStyle = this.scroller.style;
|
|
|
this.progressBar = this.wrapper.querySelector(SELECTOR_SLIDER_PROGRESS_BAR);
|
|
|
if (this.progressBar) {
|
|
|
this.progressBarWidth = this.progressBar.offsetWidth;
|
|
|
this.progressBarStyle = this.progressBar.style;
|
|
|
}
|
|
|
//忘记这个代码是干什么的了?
|
|
|
// this.x = this._getScroll();
|
|
|
// if (this.options.startX === false) {
|
|
|
// this.options.startX = this.x;
|
|
|
// }
|
|
|
//根据active修正startX
|
|
|
|
|
|
this._super();
|
|
|
this._initTimer();
|
|
|
}
|
|
|
},
|
|
|
_triggerSlide: function() {
|
|
|
var self = this;
|
|
|
self.isInTransition = false;
|
|
|
var page = self.currentPage;
|
|
|
self.slideNumber = self._fixedSlideNumber();
|
|
|
if (self.loop) {
|
|
|
if (self.slideNumber === 0) {
|
|
|
self.setTranslate(self.pages[1][0].x, 0);
|
|
|
} else if (self.slideNumber === self.itemLength - 3) {
|
|
|
self.setTranslate(self.pages[self.itemLength - 2][0].x, 0);
|
|
|
}
|
|
|
}
|
|
|
if (self.lastSlideNumber != self.slideNumber) {
|
|
|
self.lastSlideNumber = self.slideNumber;
|
|
|
self.lastPage = self.currentPage;
|
|
|
$.trigger(self.wrapper, 'slide', {
|
|
|
slideNumber: self.slideNumber
|
|
|
});
|
|
|
}
|
|
|
self._initTimer();
|
|
|
},
|
|
|
_handleSlide: function(e) {
|
|
|
var self = this;
|
|
|
if (e.target !== self.wrapper) {
|
|
|
return;
|
|
|
}
|
|
|
var detail = e.detail;
|
|
|
detail.slideNumber = detail.slideNumber || 0;
|
|
|
var temps = self.scroller.querySelectorAll(SELECTOR_SLIDER_ITEM);
|
|
|
var items = [];
|
|
|
for (var i = 0, len = temps.length; i < len; i++) {
|
|
|
var item = temps[i];
|
|
|
if (item.parentNode === self.scroller) {
|
|
|
items.push(item);
|
|
|
}
|
|
|
}
|
|
|
var _slideNumber = detail.slideNumber;
|
|
|
if (self.loop) {
|
|
|
_slideNumber += 1;
|
|
|
}
|
|
|
if (!self.wrapper.classList.contains('mui-segmented-control')) {
|
|
|
for (var i = 0, len = items.length; i < len; i++) {
|
|
|
var item = items[i];
|
|
|
if (item.parentNode === self.scroller) {
|
|
|
if (i === _slideNumber) {
|
|
|
item.classList.add(CLASS_ACTIVE);
|
|
|
} else {
|
|
|
item.classList.remove(CLASS_ACTIVE);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
var indicatorWrap = self.wrapper.querySelector('.mui-slider-indicator');
|
|
|
if (indicatorWrap) {
|
|
|
if (indicatorWrap.getAttribute('data-scroll')) { //scroll
|
|
|
$(indicatorWrap).scroll().gotoPage(detail.slideNumber);
|
|
|
}
|
|
|
var indicators = indicatorWrap.querySelectorAll('.mui-indicator');
|
|
|
if (indicators.length > 0) { //图片轮播
|
|
|
for (var i = 0, len = indicators.length; i < len; i++) {
|
|
|
indicators[i].classList[i === detail.slideNumber ? 'add' : 'remove'](CLASS_ACTIVE);
|
|
|
}
|
|
|
} else {
|
|
|
var number = indicatorWrap.querySelector('.mui-number span');
|
|
|
if (number) { //图文表格
|
|
|
number.innerText = (detail.slideNumber + 1);
|
|
|
} else { //segmented controls
|
|
|
var controlItems = indicatorWrap.querySelectorAll('.mui-control-item');
|
|
|
for (var i = 0, len = controlItems.length; i < len; i++) {
|
|
|
controlItems[i].classList[i === detail.slideNumber ? 'add' : 'remove'](CLASS_ACTIVE);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
e.stopPropagation();
|
|
|
},
|
|
|
_handleTabShow: function(e) {
|
|
|
var self = this;
|
|
|
self.gotoItem((e.detail.tabNumber || 0), self.options.slideTime);
|
|
|
},
|
|
|
_handleIndicatorTap: function(event) {
|
|
|
var self = this;
|
|
|
var target = event.target;
|
|
|
if (target.classList.contains(CLASS_ACTION_PREVIOUS) || target.classList.contains(CLASS_ACTION_NEXT)) {
|
|
|
self[target.classList.contains(CLASS_ACTION_PREVIOUS) ? 'prevItem' : 'nextItem']();
|
|
|
event.stopPropagation();
|
|
|
}
|
|
|
},
|
|
|
_initEvent: function(detach) {
|
|
|
var self = this;
|
|
|
self._super(detach);
|
|
|
var action = detach ? 'removeEventListener' : 'addEventListener';
|
|
|
self.wrapper[action]('slide', this);
|
|
|
self.wrapper[action]($.eventName('shown', 'tab'), this);
|
|
|
},
|
|
|
handleEvent: function(e) {
|
|
|
this._super(e);
|
|
|
switch (e.type) {
|
|
|
case 'slide':
|
|
|
this._handleSlide(e);
|
|
|
break;
|
|
|
case $.eventName('shown', 'tab'):
|
|
|
if (~this.snaps.indexOf(e.target)) { //避免嵌套监听错误的tab show
|
|
|
this._handleTabShow(e);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
},
|
|
|
_scrollend: function(e) {
|
|
|
this._super(e);
|
|
|
this._triggerSlide(e);
|
|
|
},
|
|
|
_drag: function(e) {
|
|
|
this._super(e);
|
|
|
var direction = e.detail.direction;
|
|
|
if (direction === 'left' || direction === 'right') {
|
|
|
//拖拽期间取消定时
|
|
|
var slidershowTimer = this.wrapper.getAttribute('data-slidershowTimer');
|
|
|
slidershowTimer && window.clearTimeout(slidershowTimer);
|
|
|
|
|
|
e.stopPropagation();
|
|
|
}
|
|
|
},
|
|
|
_initTimer: function() {
|
|
|
var self = this;
|
|
|
var slider = self.wrapper;
|
|
|
var interval = self.options.interval;
|
|
|
var slidershowTimer = slider.getAttribute('data-slidershowTimer');
|
|
|
slidershowTimer && window.clearTimeout(slidershowTimer);
|
|
|
if (interval) {
|
|
|
slidershowTimer = window.setTimeout(function() {
|
|
|
if (!slider) {
|
|
|
return;
|
|
|
}
|
|
|
//仅slider显示状态进行自动轮播
|
|
|
if (!!(slider.offsetWidth || slider.offsetHeight)) {
|
|
|
self.nextItem(true);
|
|
|
//下一个
|
|
|
}
|
|
|
self._initTimer();
|
|
|
}, interval);
|
|
|
slider.setAttribute('data-slidershowTimer', slidershowTimer);
|
|
|
}
|
|
|
},
|
|
|
|
|
|
_fixedSlideNumber: function(page) {
|
|
|
page = page || this.currentPage;
|
|
|
var slideNumber = page.pageX;
|
|
|
if (this.loop) {
|
|
|
if (page.pageX === 0) {
|
|
|
slideNumber = this.itemLength - 3;
|
|
|
} else if (page.pageX === (this.itemLength - 1)) {
|
|
|
slideNumber = 0;
|
|
|
} else {
|
|
|
slideNumber = page.pageX - 1;
|
|
|
}
|
|
|
}
|
|
|
return slideNumber;
|
|
|
},
|
|
|
_reLayout: function() {
|
|
|
this.hasHorizontalScroll = true;
|
|
|
this.loop = this.scroller.classList.contains(CLASS_SLIDER_LOOP);
|
|
|
this._super();
|
|
|
},
|
|
|
_getScroll: function() {
|
|
|
var result = $.parseTranslateMatrix($.getStyles(this.scroller, 'webkitTransform'));
|
|
|
return result ? result.x : 0;
|
|
|
},
|
|
|
_transitionEnd: function(e) {
|
|
|
if (e.target !== this.scroller || !this.isInTransition) {
|
|
|
return;
|
|
|
}
|
|
|
this._transitionTime();
|
|
|
this.isInTransition = false;
|
|
|
$.trigger(this.wrapper, 'scrollend', this);
|
|
|
},
|
|
|
_flick: function(e) {
|
|
|
if (!this.moved) { //无moved
|
|
|
return;
|
|
|
}
|
|
|
var detail = e.detail;
|
|
|
var direction = detail.direction;
|
|
|
this._clearRequestAnimationFrame();
|
|
|
this.isInTransition = true;
|
|
|
// if (direction === 'up' || direction === 'down') {
|
|
|
// this.resetPosition(this.options.bounceTime);
|
|
|
// return;
|
|
|
// }
|
|
|
if (e.type === 'flick') {
|
|
|
if (detail.deltaTime < 200) { //flick,太容易触发,额外校验一下deltaTime
|
|
|
this.x = this._getPage((this.slideNumber + (direction === 'right' ? -1 : 1)), true).x;
|
|
|
}
|
|
|
this.resetPosition(this.options.bounceTime);
|
|
|
} else if (e.type === 'dragend' && !detail.flick) {
|
|
|
this.resetPosition(this.options.bounceTime);
|
|
|
}
|
|
|
e.stopPropagation();
|
|
|
},
|
|
|
_initSnap: function() {
|
|
|
this.scrollerWidth = this.itemLength * this.scrollerWidth;
|
|
|
this.maxScrollX = Math.min(this.wrapperWidth - this.scrollerWidth, 0);
|
|
|
this._super();
|
|
|
if (!this.currentPage.x) {
|
|
|
//当slider处于隐藏状态时,导致snap计算是错误的,临时先这么判断一下,后续要考虑解决所有scroll在隐藏状态下初始化属性不正确的问题
|
|
|
var currentPage = this.pages[this.loop ? 1 : 0];
|
|
|
currentPage = currentPage || this.pages[0];
|
|
|
if (!currentPage) {
|
|
|
return;
|
|
|
}
|
|
|
this.currentPage = currentPage[0];
|
|
|
this.slideNumber = 0;
|
|
|
this.lastSlideNumber = typeof this.lastSlideNumber === 'undefined' ? 0 : this.lastSlideNumber;
|
|
|
} else {
|
|
|
this.slideNumber = this._fixedSlideNumber();
|
|
|
this.lastSlideNumber = typeof this.lastSlideNumber === 'undefined' ? this.slideNumber : this.lastSlideNumber;
|
|
|
}
|
|
|
this.options.startX = this.currentPage.x || 0;
|
|
|
},
|
|
|
_getSnapX: function(offsetLeft) {
|
|
|
return Math.max(-offsetLeft, this.maxScrollX);
|
|
|
},
|
|
|
_getPage: function(slideNumber, isFlick) {
|
|
|
if (this.loop) {
|
|
|
if (slideNumber > (this.itemLength - (isFlick ? 2 : 3))) {
|
|
|
slideNumber = 1;
|
|
|
time = 0;
|
|
|
} else if (slideNumber < (isFlick ? -1 : 0)) {
|
|
|
slideNumber = this.itemLength - 2;
|
|
|
time = 0;
|
|
|
} else {
|
|
|
slideNumber += 1;
|
|
|
}
|
|
|
} else {
|
|
|
if (!isFlick) {
|
|
|
if (slideNumber > (this.itemLength - 1)) {
|
|
|
slideNumber = 0;
|
|
|
time = 0;
|
|
|
} else if (slideNumber < 0) {
|
|
|
slideNumber = this.itemLength - 1;
|
|
|
time = 0;
|
|
|
}
|
|
|
}
|
|
|
slideNumber = Math.min(Math.max(0, slideNumber), this.itemLength - 1);
|
|
|
}
|
|
|
return this.pages[slideNumber][0];
|
|
|
},
|
|
|
_gotoItem: function(slideNumber, time) {
|
|
|
this.currentPage = this._getPage(slideNumber, true); //此处传true。可保证程序切换时,动画与人手操作一致(第一张,最后一张的切换动画)
|
|
|
this.scrollTo(this.currentPage.x, 0, time, this.options.scrollEasing);
|
|
|
if (time === 0) {
|
|
|
$.trigger(this.wrapper, 'scrollend', this);
|
|
|
}
|
|
|
},
|
|
|
//API
|
|
|
setTranslate: function(x, y) {
|
|
|
this._super(x, y);
|
|
|
var progressBar = this.progressBar;
|
|
|
if (progressBar) {
|
|
|
this.progressBarStyle.webkitTransform = this._getTranslateStr((-x * (this.progressBarWidth / this.wrapperWidth)), 0);
|
|
|
}
|
|
|
},
|
|
|
resetPosition: function(time) {
|
|
|
time = time || 0;
|
|
|
if (this.x > 0) {
|
|
|
this.x = 0;
|
|
|
} else if (this.x < this.maxScrollX) {
|
|
|
this.x = this.maxScrollX;
|
|
|
}
|
|
|
this.currentPage = this._nearestSnap(this.x);
|
|
|
this.scrollTo(this.currentPage.x, 0, time, this.options.scrollEasing);
|
|
|
return true;
|
|
|
},
|
|
|
gotoItem: function(slideNumber, time) {
|
|
|
this._gotoItem(slideNumber, typeof time === 'undefined' ? this.options.scrollTime : time);
|
|
|
},
|
|
|
nextItem: function() {
|
|
|
this._gotoItem(this.slideNumber + 1, this.options.scrollTime);
|
|
|
},
|
|
|
prevItem: function() {
|
|
|
this._gotoItem(this.slideNumber - 1, this.options.scrollTime);
|
|
|
},
|
|
|
getSlideNumber: function() {
|
|
|
return this.slideNumber || 0;
|
|
|
},
|
|
|
_reInit: function() {
|
|
|
var groups = this.wrapper.querySelectorAll('.' + CLASS_SLIDER_GROUP);
|
|
|
for (var i = 0, len = groups.length; i < len; i++) {
|
|
|
if (groups[i].parentNode === this.wrapper) {
|
|
|
this.scroller = groups[i];
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
this.scrollerStyle = this.scroller && this.scroller.style;
|
|
|
if (this.progressBar) {
|
|
|
this.progressBarWidth = this.progressBar.offsetWidth;
|
|
|
this.progressBarStyle = this.progressBar.style;
|
|
|
}
|
|
|
},
|
|
|
refresh: function(options) {
|
|
|
if (options) {
|
|
|
$.extend(this.options, options);
|
|
|
this._super();
|
|
|
this._initTimer();
|
|
|
} else {
|
|
|
this._super();
|
|
|
}
|
|
|
},
|
|
|
destroy: function() {
|
|
|
this._initEvent(true); //detach
|
|
|
delete $.data[this.wrapper.getAttribute('data-slider')];
|
|
|
this.wrapper.setAttribute('data-slider', '');
|
|
|
}
|
|
|
});
|
|
|
$.fn.slider = function(options) {
|
|
|
var slider = null;
|
|
|
this.each(function() {
|
|
|
var sliderElement = this;
|
|
|
if (!this.classList.contains(CLASS_SLIDER)) {
|
|
|
sliderElement = this.querySelector('.' + CLASS_SLIDER);
|
|
|
}
|
|
|
if (sliderElement && sliderElement.querySelector(SELECTOR_SLIDER_ITEM)) {
|
|
|
var id = sliderElement.getAttribute('data-slider');
|
|
|
if (!id) {
|
|
|
id = ++$.uuid;
|
|
|
$.data[id] = slider = new Slider(sliderElement, options);
|
|
|
sliderElement.setAttribute('data-slider', id);
|
|
|
} else {
|
|
|
slider = $.data[id];
|
|
|
if (slider && options) {
|
|
|
slider.refresh(options);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
return slider;
|
|
|
};
|
|
|
$.ready(function() {
|
|
|
// setTimeout(function() {
|
|
|
$('.mui-slider').slider();
|
|
|
$('.mui-scroll-wrapper.mui-slider-indicator.mui-segmented-control').scroll({
|
|
|
scrollY: false,
|
|
|
scrollX: true,
|
|
|
indicators: false,
|
|
|
snap: '.mui-control-item'
|
|
|
});
|
|
|
// }, 500); //临时处理slider宽度计算不正确的问题(初步确认是scrollbar导致的)
|
|
|
|
|
|
});
|
|
|
})(mui, window);
|
|
|
/**
|
|
|
* pullRefresh 5+
|
|
|
* @param {type} $
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, document) {
|
|
|
if (!($.os.plus)) { //仅在5+android支持多webview的使用
|
|
|
return;
|
|
|
}
|
|
|
$.plusReady(function() {
|
|
|
if (window.__NWin_Enable__ === false) { //不支持多webview,则不用5+下拉刷新
|
|
|
return;
|
|
|
}
|
|
|
var CLASS_PLUS_PULLREFRESH = 'mui-plus-pullrefresh';
|
|
|
var CLASS_VISIBILITY = 'mui-visibility';
|
|
|
var CLASS_HIDDEN = 'mui-hidden';
|
|
|
var CLASS_BLOCK = 'mui-block';
|
|
|
|
|
|
var CLASS_PULL_CAPTION = 'mui-pull-caption';
|
|
|
var CLASS_PULL_CAPTION_DOWN = 'mui-pull-caption-down';
|
|
|
var CLASS_PULL_CAPTION_REFRESH = 'mui-pull-caption-refresh';
|
|
|
var CLASS_PULL_CAPTION_NOMORE = 'mui-pull-caption-nomore';
|
|
|
|
|
|
var PlusPullRefresh = $.Class.extend({
|
|
|
init: function(element, options) {
|
|
|
this.element = element;
|
|
|
this.options = options;
|
|
|
this.wrapper = this.scroller = element;
|
|
|
this._init();
|
|
|
this._initPulldownRefreshEvent();
|
|
|
},
|
|
|
_init: function() {
|
|
|
var self = this;
|
|
|
//document.addEventListener('plusscrollbottom', this);
|
|
|
window.addEventListener('dragup', self);
|
|
|
document.addEventListener("plusscrollbottom", self);
|
|
|
self.scrollInterval = window.setInterval(function() {
|
|
|
if (self.isScroll && !self.loading) {
|
|
|
if (window.pageYOffset + window.innerHeight + 10 >= document.documentElement.scrollHeight) {
|
|
|
self.isScroll = false; //放在这里是因为快速滚动的话,有可能检测时,还没到底,所以只要有滚动,没到底之前一直检测高度变化
|
|
|
if (self.bottomPocket) {
|
|
|
self.pullupLoading();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}, 100);
|
|
|
},
|
|
|
_initPulldownRefreshEvent: function() {
|
|
|
var self = this;
|
|
|
$.plusReady(function() {
|
|
|
if (self.options.down.style == "circle") {
|
|
|
//单webview、原生转圈
|
|
|
self.options.webview = plus.webview.currentWebview();
|
|
|
self.options.webview.setPullToRefresh({
|
|
|
support: true,
|
|
|
color: self.options.down.color || '#2BD009',
|
|
|
height: self.options.down.height || '50px',
|
|
|
range: self.options.down.range || '100px',
|
|
|
style: 'circle',
|
|
|
offset: self.options.down.offset || '0px'
|
|
|
}, function() {
|
|
|
self.options.down.callback();
|
|
|
});
|
|
|
} else if (self.topPocket && self.options.webviewId) {
|
|
|
var webview = plus.webview.getWebviewById(self.options.webviewId); //子窗口
|
|
|
if (!webview) {
|
|
|
return;
|
|
|
}
|
|
|
self.options.webview = webview;
|
|
|
var downOptions = self.options.down;
|
|
|
var height = downOptions.height;
|
|
|
webview.addEventListener('close', function() {
|
|
|
var attrWebviewId = self.options.webviewId && self.options.webviewId.replace(/\//g, "_"); //替换所有"/"
|
|
|
self.element.removeAttribute('data-pullrefresh-plus-' + attrWebviewId);
|
|
|
});
|
|
|
webview.addEventListener("dragBounce", function(e) {
|
|
|
if (!self.pulldown) {
|
|
|
self._initPulldownRefresh();
|
|
|
} else {
|
|
|
self.pullPocket.classList.add(CLASS_BLOCK);
|
|
|
}
|
|
|
switch (e.status) {
|
|
|
case "beforeChangeOffset": //下拉可刷新状态
|
|
|
self._setCaption(downOptions.contentdown);
|
|
|
break;
|
|
|
case "afterChangeOffset": //松开可刷新状态
|
|
|
self._setCaption(downOptions.contentover);
|
|
|
break;
|
|
|
case "dragEndAfterChangeOffset": //正在刷新状态
|
|
|
//执行下拉刷新所在webview的回调函数
|
|
|
webview.evalJS("window.mui&&mui.options.pullRefresh.down.callback()");
|
|
|
self._setCaption(downOptions.contentrefresh);
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
}, false);
|
|
|
|
|
|
webview.setBounce({
|
|
|
position: {
|
|
|
top: height * 2 + 'px'
|
|
|
},
|
|
|
changeoffset: {
|
|
|
top: height + 'px'
|
|
|
}
|
|
|
});
|
|
|
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
handleEvent: function(e) {
|
|
|
var self = this;
|
|
|
if (self.stopped) {
|
|
|
return;
|
|
|
}
|
|
|
self.isScroll = false;
|
|
|
if (e.type === 'dragup' || e.type === 'plusscrollbottom') {
|
|
|
self.isScroll = true;
|
|
|
setTimeout(function() {
|
|
|
self.isScroll = false;
|
|
|
}, 1000);
|
|
|
}
|
|
|
}
|
|
|
}).extend($.extend({
|
|
|
setStopped: function(stopped) { //该方法是子页面调用的
|
|
|
this.stopped = !!stopped;
|
|
|
// TODO 此处需要设置当前webview的bounce为none,目前5+有BUG
|
|
|
if (this.stopped) {
|
|
|
this.disablePullupToRefresh();
|
|
|
this.disablePulldownToRefresh();
|
|
|
} else {
|
|
|
this.enablePullupToRefresh();
|
|
|
this.enablePulldownToRefresh();
|
|
|
}
|
|
|
},
|
|
|
beginPulldown: function() {
|
|
|
var self = this;
|
|
|
$.plusReady(function() {
|
|
|
//这里延时的目的是为了保证下拉刷新组件初始化完成,后续应该做成有状态的
|
|
|
setTimeout(function() {
|
|
|
if (self.options.down.style == "circle") { //单webview下拉刷新
|
|
|
plus.webview.currentWebview().beginPullToRefresh();
|
|
|
} else { //双webview模式
|
|
|
var webview = self.options.webview;
|
|
|
if (webview) {
|
|
|
webview.setBounce({
|
|
|
offset: {
|
|
|
top: self.options.down.height + "px"
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
}, 15);
|
|
|
}.bind(this));
|
|
|
},
|
|
|
pulldownLoading: function() { //该方法是子页面调用的,兼容老的历史API
|
|
|
this.beginPulldown();
|
|
|
},
|
|
|
_pulldownLoading: function() { //该方法是父页面调用的
|
|
|
var self = this;
|
|
|
$.plusReady(function() {
|
|
|
var childWebview = plus.webview.getWebviewById(self.options.webviewId);
|
|
|
childWebview && childWebview.setBounce({
|
|
|
offset: {
|
|
|
top: self.options.down.height + "px"
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
},
|
|
|
endPulldown: function() {
|
|
|
var _wv = plus.webview.currentWebview();
|
|
|
//双webview的下拉刷新,需要修改父窗口提示信息
|
|
|
if (_wv.parent() && this.options.down.style !== "circle") {
|
|
|
_wv.parent().evalJS("mui&&mui(document.querySelector('.mui-content')).pullRefresh('" + JSON.stringify({
|
|
|
webviewId: _wv.id
|
|
|
}) + "')._endPulldownToRefresh()");
|
|
|
} else {
|
|
|
_wv.endPullToRefresh();
|
|
|
}
|
|
|
},
|
|
|
endPulldownToRefresh: function() { //该方法是子页面调用的,兼容老的历史API
|
|
|
this.endPulldown();
|
|
|
},
|
|
|
_endPulldownToRefresh: function() { //该方法是父页面调用的
|
|
|
var self = this;
|
|
|
if (self.topPocket && self.options.webview) {
|
|
|
self.options.webview.endPullToRefresh(); //下拉刷新所在webview回弹
|
|
|
self.loading = false;
|
|
|
self._setCaption(self.options.down.contentdown, true);
|
|
|
setTimeout(function() {
|
|
|
self.loading || self.topPocket.classList.remove(CLASS_BLOCK);
|
|
|
}, 350);
|
|
|
}
|
|
|
},
|
|
|
beginPullup: function(callback) { //开始上拉加载
|
|
|
var self = this;
|
|
|
if (self.isLoading) return;
|
|
|
self.isLoading = true;
|
|
|
if (self.pulldown !== false) {
|
|
|
self._initPullupRefresh();
|
|
|
} else {
|
|
|
this.pullPocket.classList.add(CLASS_BLOCK);
|
|
|
}
|
|
|
setTimeout(function() {
|
|
|
self.pullLoading.classList.add(CLASS_VISIBILITY);
|
|
|
self.pullLoading.classList.remove(CLASS_HIDDEN);
|
|
|
self.pullCaption.innerHTML = ''; //修正5+里边第一次加载时,文字显示的bug(还会显示出来个“多”,猜测应该是渲染问题导致的)
|
|
|
self.pullCaption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_REFRESH;
|
|
|
self.pullCaption.innerHTML = self.options.up.contentrefresh;
|
|
|
callback = callback || self.options.up.callback;
|
|
|
callback && callback.call(self);
|
|
|
}, 300);
|
|
|
},
|
|
|
pullupLoading: function(callback) { //兼容老的API
|
|
|
this.beginPullup(callback);
|
|
|
},
|
|
|
endPullup: function(finished) { //上拉加载结束
|
|
|
var self = this;
|
|
|
if (self.pullLoading) {
|
|
|
self.pullLoading.classList.remove(CLASS_VISIBILITY);
|
|
|
self.pullLoading.classList.add(CLASS_HIDDEN);
|
|
|
self.isLoading = false;
|
|
|
if (finished) {
|
|
|
self.finished = true;
|
|
|
self.pullCaption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_NOMORE;
|
|
|
self.pullCaption.innerHTML = self.options.up.contentnomore;
|
|
|
//取消5+的plusscrollbottom事件
|
|
|
document.removeEventListener('plusscrollbottom', self);
|
|
|
window.removeEventListener('dragup', self);
|
|
|
} else { //初始化时隐藏,后续不再隐藏
|
|
|
self.pullCaption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_DOWN;
|
|
|
self.pullCaption.innerHTML = self.options.up.contentdown;
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
endPullupToRefresh: function(finished) { //上拉加载结束,兼容老的API
|
|
|
this.endPullup(finished);
|
|
|
},
|
|
|
disablePulldownToRefresh: function() {
|
|
|
var webview = plus.webview.currentWebview();
|
|
|
if (this.options.down.style && this.options.down.style == 'circle') { // 单webview模式禁止原生下拉刷新
|
|
|
this.options.webview.setPullToRefresh({
|
|
|
support: false,
|
|
|
style: 'circle'
|
|
|
});
|
|
|
} else { // 双webview模式禁止下拉刷新
|
|
|
webview.setStyle({
|
|
|
bounce: 'none'
|
|
|
});
|
|
|
webview.setBounce({
|
|
|
position: {
|
|
|
top: 'none'
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
},
|
|
|
enablePulldownToRefresh: function() {
|
|
|
var self = this,
|
|
|
webview = plus.webview.currentWebview(),
|
|
|
height = this.options.down.height;
|
|
|
// 单webview模式禁止原生下拉刷新
|
|
|
if (this.options.down.style && this.options.down.style == 'circle') {
|
|
|
webview.setPullToRefresh({
|
|
|
support: true,
|
|
|
height: height || '50px',
|
|
|
range: self.options.down.range || '100px',
|
|
|
style: 'circle',
|
|
|
offset: self.options.down.offset || '0px'
|
|
|
});
|
|
|
} else { // 重新初始化双webview模式下拉刷新
|
|
|
webview.setStyle({
|
|
|
bounce: 'vertical'
|
|
|
});
|
|
|
webview.setBounce({
|
|
|
position: {
|
|
|
top: height * 2 + 'px'
|
|
|
},
|
|
|
changeoffset: {
|
|
|
top: height + 'px'
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
},
|
|
|
disablePullupToRefresh: function() {
|
|
|
this._initPullupRefresh();
|
|
|
this.bottomPocket.className = 'mui-pull-bottom-pocket' + ' ' + CLASS_HIDDEN;
|
|
|
window.removeEventListener('dragup', this);
|
|
|
},
|
|
|
enablePullupToRefresh: function() {
|
|
|
this._initPullupRefresh();
|
|
|
this.bottomPocket.classList.remove(CLASS_HIDDEN);
|
|
|
this.pullCaption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_DOWN;
|
|
|
this.pullCaption.innerHTML = this.options.up.contentdown;
|
|
|
document.addEventListener("plusscrollbottom", this);
|
|
|
window.addEventListener('dragup', this);
|
|
|
},
|
|
|
scrollTo: function(x, y, time) {
|
|
|
$.scrollTo(y, time);
|
|
|
},
|
|
|
scrollToBottom: function(time) {
|
|
|
$.scrollTo(document.documentElement.scrollHeight, time);
|
|
|
},
|
|
|
refresh: function(isReset) {
|
|
|
if (isReset && this.finished) {
|
|
|
this.enablePullupToRefresh();
|
|
|
this.finished = false;
|
|
|
}
|
|
|
}
|
|
|
}, $.PullRefresh));
|
|
|
|
|
|
//override h5 pullRefresh
|
|
|
$.fn.pullRefresh_native = function(options) {
|
|
|
var self;
|
|
|
if (this.length === 0) {
|
|
|
self = document.createElement('div');
|
|
|
self.className = 'mui-content';
|
|
|
document.body.appendChild(self);
|
|
|
} else {
|
|
|
self = this[0];
|
|
|
}
|
|
|
var args = options;
|
|
|
//一个父需要支持多个子下拉刷新
|
|
|
options = options || {}
|
|
|
if (typeof options === 'string') {
|
|
|
options = $.parseJSON(options);
|
|
|
};
|
|
|
!options.webviewId && (options.webviewId = (plus.webview.currentWebview().id || plus.webview.currentWebview().getURL()));
|
|
|
var pullRefreshApi = null;
|
|
|
var attrWebviewId = options.webviewId && options.webviewId.replace(/\//g, "_"); //替换所有"/"
|
|
|
var id = self.getAttribute('data-pullrefresh-plus-' + attrWebviewId);
|
|
|
if (!id && typeof args === 'undefined') {
|
|
|
return false;
|
|
|
}
|
|
|
if (!id) { //避免重复初始化5+ pullrefresh
|
|
|
id = ++$.uuid;
|
|
|
self.setAttribute('data-pullrefresh-plus-' + attrWebviewId, id);
|
|
|
document.body.classList.add(CLASS_PLUS_PULLREFRESH);
|
|
|
$.data[id] = pullRefreshApi = new PlusPullRefresh(self, options);
|
|
|
} else {
|
|
|
pullRefreshApi = $.data[id];
|
|
|
}
|
|
|
if (options.down && options.down.auto) { //如果设置了auto,则自动下拉一次
|
|
|
//pullRefreshApi._pulldownLoading(); //parent webview
|
|
|
pullRefreshApi.beginPulldown();
|
|
|
} else if (options.up && options.up.auto) { //如果设置了auto,则自动上拉一次
|
|
|
pullRefreshApi.beginPullup();
|
|
|
}
|
|
|
return pullRefreshApi;
|
|
|
};
|
|
|
});
|
|
|
|
|
|
})(mui, document);
|
|
|
/**
|
|
|
* off-canvas
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @param {type} document
|
|
|
* @param {type} action
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window, document, name) {
|
|
|
var CLASS_OFF_CANVAS_LEFT = 'mui-off-canvas-left';
|
|
|
var CLASS_OFF_CANVAS_RIGHT = 'mui-off-canvas-right';
|
|
|
var CLASS_ACTION_BACKDROP = 'mui-off-canvas-backdrop';
|
|
|
var CLASS_OFF_CANVAS_WRAP = 'mui-off-canvas-wrap';
|
|
|
|
|
|
var CLASS_SLIDE_IN = 'mui-slide-in';
|
|
|
var CLASS_ACTIVE = 'mui-active';
|
|
|
|
|
|
|
|
|
var CLASS_TRANSITIONING = 'mui-transitioning';
|
|
|
|
|
|
var SELECTOR_INNER_WRAP = '.mui-inner-wrap';
|
|
|
|
|
|
|
|
|
var OffCanvas = $.Class.extend({
|
|
|
init: function(element, options) {
|
|
|
this.wrapper = this.element = element;
|
|
|
this.scroller = this.wrapper.querySelector(SELECTOR_INNER_WRAP);
|
|
|
this.classList = this.wrapper.classList;
|
|
|
if (this.scroller) {
|
|
|
this.options = $.extend(true, {
|
|
|
dragThresholdX: 10,
|
|
|
scale: 0.8,
|
|
|
opacity: 0.1,
|
|
|
preventDefaultException: {
|
|
|
tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|VIDEO)$/
|
|
|
},
|
|
|
}, options);
|
|
|
document.body.classList.add('mui-fullscreen'); //fullscreen
|
|
|
this.refresh();
|
|
|
this.initEvent();
|
|
|
}
|
|
|
},
|
|
|
_preventDefaultException: function(el, exceptions) {
|
|
|
for (var i in exceptions) {
|
|
|
if (exceptions[i].test(el[i])) {
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
},
|
|
|
refresh: function(offCanvas) {
|
|
|
// offCanvas && !offCanvas.classList.contains(CLASS_ACTIVE) && this.classList.remove(CLASS_ACTIVE);
|
|
|
this.slideIn = this.classList.contains(CLASS_SLIDE_IN);
|
|
|
this.scalable = this.classList.contains('mui-scalable') && !this.slideIn;
|
|
|
this.scroller = this.wrapper.querySelector(SELECTOR_INNER_WRAP);
|
|
|
// !offCanvas && this.scroller.classList.remove(CLASS_TRANSITIONING);
|
|
|
// !offCanvas && this.scroller.setAttribute('style', '');
|
|
|
this.offCanvasLefts = this.wrapper.querySelectorAll('.' + CLASS_OFF_CANVAS_LEFT);
|
|
|
this.offCanvasRights = this.wrapper.querySelectorAll('.' + CLASS_OFF_CANVAS_RIGHT);
|
|
|
if (offCanvas) {
|
|
|
if (offCanvas.classList.contains(CLASS_OFF_CANVAS_LEFT)) {
|
|
|
this.offCanvasLeft = offCanvas;
|
|
|
} else if (offCanvas.classList.contains(CLASS_OFF_CANVAS_RIGHT)) {
|
|
|
this.offCanvasRight = offCanvas;
|
|
|
}
|
|
|
} else {
|
|
|
this.offCanvasRight = this.wrapper.querySelector('.' + CLASS_OFF_CANVAS_RIGHT);
|
|
|
this.offCanvasLeft = this.wrapper.querySelector('.' + CLASS_OFF_CANVAS_LEFT);
|
|
|
}
|
|
|
this.offCanvasRightWidth = this.offCanvasLeftWidth = 0;
|
|
|
this.offCanvasLeftSlideIn = this.offCanvasRightSlideIn = false;
|
|
|
if (this.offCanvasRight) {
|
|
|
this.offCanvasRightWidth = this.offCanvasRight.offsetWidth;
|
|
|
this.offCanvasRightSlideIn = this.slideIn && (this.offCanvasRight.parentNode === this.wrapper);
|
|
|
// this.offCanvasRight.classList.remove(CLASS_TRANSITIONING);
|
|
|
// this.offCanvasRight.classList.remove(CLASS_ACTIVE);
|
|
|
// this.offCanvasRight.setAttribute('style', '');
|
|
|
}
|
|
|
if (this.offCanvasLeft) {
|
|
|
this.offCanvasLeftWidth = this.offCanvasLeft.offsetWidth;
|
|
|
this.offCanvasLeftSlideIn = this.slideIn && (this.offCanvasLeft.parentNode === this.wrapper);
|
|
|
// this.offCanvasLeft.classList.remove(CLASS_TRANSITIONING);
|
|
|
// this.offCanvasLeft.classList.remove(CLASS_ACTIVE);
|
|
|
// this.offCanvasLeft.setAttribute('style', '');
|
|
|
}
|
|
|
this.backdrop = this.scroller.querySelector('.' + CLASS_ACTION_BACKDROP);
|
|
|
|
|
|
this.options.dragThresholdX = this.options.dragThresholdX || 10;
|
|
|
|
|
|
this.visible = false;
|
|
|
this.startX = null;
|
|
|
this.lastX = null;
|
|
|
this.offsetX = null;
|
|
|
this.lastTranslateX = null;
|
|
|
},
|
|
|
handleEvent: function(e) {
|
|
|
switch (e.type) {
|
|
|
case $.EVENT_START:
|
|
|
e.target && !this._preventDefaultException(e.target, this.options.preventDefaultException) && e.preventDefault();
|
|
|
break;
|
|
|
case 'webkitTransitionEnd': //有个bug需要处理,需要考虑假设没有触发webkitTransitionEnd的情况
|
|
|
if (e.target === this.scroller) {
|
|
|
this._dispatchEvent();
|
|
|
}
|
|
|
break;
|
|
|
case 'drag':
|
|
|
var detail = e.detail;
|
|
|
if (!this.startX) {
|
|
|
this.startX = detail.center.x;
|
|
|
this.lastX = this.startX;
|
|
|
} else {
|
|
|
this.lastX = detail.center.x;
|
|
|
}
|
|
|
if (!this.isDragging && Math.abs(this.lastX - this.startX) > this.options.dragThresholdX && (detail.direction === 'left' || (detail.direction === 'right'))) {
|
|
|
if (this.slideIn) {
|
|
|
this.scroller = this.wrapper.querySelector(SELECTOR_INNER_WRAP);
|
|
|
if (this.classList.contains(CLASS_ACTIVE)) {
|
|
|
if (this.offCanvasRight && this.offCanvasRight.classList.contains(CLASS_ACTIVE)) {
|
|
|
this.offCanvas = this.offCanvasRight;
|
|
|
this.offCanvasWidth = this.offCanvasRightWidth;
|
|
|
} else {
|
|
|
this.offCanvas = this.offCanvasLeft;
|
|
|
this.offCanvasWidth = this.offCanvasLeftWidth;
|
|
|
}
|
|
|
} else {
|
|
|
if (detail.direction === 'left' && this.offCanvasRight) {
|
|
|
this.offCanvas = this.offCanvasRight;
|
|
|
this.offCanvasWidth = this.offCanvasRightWidth;
|
|
|
} else if (detail.direction === 'right' && this.offCanvasLeft) {
|
|
|
this.offCanvas = this.offCanvasLeft;
|
|
|
this.offCanvasWidth = this.offCanvasLeftWidth;
|
|
|
} else {
|
|
|
this.scroller = null;
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
if (this.classList.contains(CLASS_ACTIVE)) {
|
|
|
if (detail.direction === 'left') {
|
|
|
this.offCanvas = this.offCanvasLeft;
|
|
|
this.offCanvasWidth = this.offCanvasLeftWidth;
|
|
|
} else {
|
|
|
this.offCanvas = this.offCanvasRight;
|
|
|
this.offCanvasWidth = this.offCanvasRightWidth;
|
|
|
}
|
|
|
} else {
|
|
|
if (detail.direction === 'right') {
|
|
|
this.offCanvas = this.offCanvasLeft;
|
|
|
this.offCanvasWidth = this.offCanvasLeftWidth;
|
|
|
} else {
|
|
|
this.offCanvas = this.offCanvasRight;
|
|
|
this.offCanvasWidth = this.offCanvasRightWidth;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (this.offCanvas && this.scroller) {
|
|
|
this.startX = this.lastX;
|
|
|
this.isDragging = true;
|
|
|
|
|
|
$.gestures.session.lockDirection = true; //锁定方向
|
|
|
$.gestures.session.startDirection = detail.direction;
|
|
|
|
|
|
this.offCanvas.classList.remove(CLASS_TRANSITIONING);
|
|
|
this.scroller.classList.remove(CLASS_TRANSITIONING);
|
|
|
this.offsetX = this.getTranslateX();
|
|
|
this._initOffCanvasVisible();
|
|
|
}
|
|
|
}
|
|
|
if (this.isDragging) {
|
|
|
this.updateTranslate(this.offsetX + (this.lastX - this.startX));
|
|
|
detail.gesture.preventDefault();
|
|
|
e.stopPropagation();
|
|
|
}
|
|
|
break;
|
|
|
case 'dragend':
|
|
|
if (this.isDragging) {
|
|
|
var detail = e.detail;
|
|
|
var direction = detail.direction;
|
|
|
this.isDragging = false;
|
|
|
this.offCanvas.classList.add(CLASS_TRANSITIONING);
|
|
|
this.scroller.classList.add(CLASS_TRANSITIONING);
|
|
|
var ratio = 0;
|
|
|
var x = this.getTranslateX();
|
|
|
if (!this.slideIn) {
|
|
|
if (x >= 0) {
|
|
|
ratio = (this.offCanvasLeftWidth && (x / this.offCanvasLeftWidth)) || 0;
|
|
|
} else {
|
|
|
ratio = (this.offCanvasRightWidth && (x / this.offCanvasRightWidth)) || 0;
|
|
|
}
|
|
|
if (ratio === 0) {
|
|
|
this.openPercentage(0);
|
|
|
this._dispatchEvent(); //此处不触发webkitTransitionEnd,所以手动dispatch
|
|
|
return;
|
|
|
}
|
|
|
if (direction === 'right' && ratio >= 0 && (ratio >= 0.5 || detail.swipe)) { //右滑打开
|
|
|
this.openPercentage(100);
|
|
|
} else if (direction === 'right' && ratio < 0 && (ratio > -0.5 || detail.swipe)) { //右滑关闭
|
|
|
this.openPercentage(0);
|
|
|
} else if (direction === 'right' && ratio > 0 && ratio < 0.5) { //右滑还原关闭
|
|
|
this.openPercentage(0);
|
|
|
} else if (direction === 'right' && ratio < 0.5) { //右滑还原打开
|
|
|
this.openPercentage(-100);
|
|
|
} else if (direction === 'left' && ratio <= 0 && (ratio <= -0.5 || detail.swipe)) { //左滑打开
|
|
|
this.openPercentage(-100);
|
|
|
} else if (direction === 'left' && ratio > 0 && (ratio <= 0.5 || detail.swipe)) { //左滑关闭
|
|
|
this.openPercentage(0);
|
|
|
} else if (direction === 'left' && ratio < 0 && ratio >= -0.5) { //左滑还原关闭
|
|
|
this.openPercentage(0);
|
|
|
} else if (direction === 'left' && ratio > 0.5) { //左滑还原打开
|
|
|
this.openPercentage(100);
|
|
|
} else { //默认关闭
|
|
|
this.openPercentage(0);
|
|
|
}
|
|
|
if (ratio === 1 || ratio === -1) { //此处不触发webkitTransitionEnd,所以手动dispatch
|
|
|
this._dispatchEvent();
|
|
|
}
|
|
|
} else {
|
|
|
if (x >= 0) {
|
|
|
ratio = (this.offCanvasRightWidth && (x / this.offCanvasRightWidth)) || 0;
|
|
|
} else {
|
|
|
ratio = (this.offCanvasLeftWidth && (x / this.offCanvasLeftWidth)) || 0;
|
|
|
}
|
|
|
if (direction === 'right' && ratio <= 0 && (ratio >= -0.5 || detail.swipe)) { //右滑打开
|
|
|
this.openPercentage(100);
|
|
|
} else if (direction === 'right' && ratio > 0 && (ratio >= 0.5 || detail.swipe)) { //右滑关闭
|
|
|
this.openPercentage(0);
|
|
|
} else if (direction === 'right' && ratio <= -0.5) { //右滑还原关闭
|
|
|
this.openPercentage(0);
|
|
|
} else if (direction === 'right' && ratio > 0 && ratio <= 0.5) { //右滑还原打开
|
|
|
this.openPercentage(-100);
|
|
|
} else if (direction === 'left' && ratio >= 0 && (ratio <= 0.5 || detail.swipe)) { //左滑打开
|
|
|
this.openPercentage(-100);
|
|
|
} else if (direction === 'left' && ratio < 0 && (ratio <= -0.5 || detail.swipe)) { //左滑关闭
|
|
|
this.openPercentage(0);
|
|
|
} else if (direction === 'left' && ratio >= 0.5) { //左滑还原关闭
|
|
|
this.openPercentage(0);
|
|
|
} else if (direction === 'left' && ratio >= -0.5 && ratio < 0) { //左滑还原打开
|
|
|
this.openPercentage(100);
|
|
|
} else {
|
|
|
this.openPercentage(0);
|
|
|
}
|
|
|
if (ratio === 1 || ratio === -1 || ratio === 0) {
|
|
|
this._dispatchEvent();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
},
|
|
|
_dispatchEvent: function() {
|
|
|
if (this.classList.contains(CLASS_ACTIVE)) {
|
|
|
$.trigger(this.wrapper, 'shown', this);
|
|
|
} else {
|
|
|
$.trigger(this.wrapper, 'hidden', this);
|
|
|
}
|
|
|
},
|
|
|
_initOffCanvasVisible: function() {
|
|
|
if (!this.visible) {
|
|
|
this.visible = true;
|
|
|
if (this.offCanvasLeft) {
|
|
|
this.offCanvasLeft.style.visibility = 'visible';
|
|
|
}
|
|
|
if (this.offCanvasRight) {
|
|
|
this.offCanvasRight.style.visibility = 'visible';
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
initEvent: function() {
|
|
|
var self = this;
|
|
|
if (self.backdrop) {
|
|
|
self.backdrop.addEventListener('tap', function(e) {
|
|
|
self.close();
|
|
|
e.detail.gesture.preventDefault();
|
|
|
});
|
|
|
}
|
|
|
if (this.classList.contains('mui-draggable')) {
|
|
|
this.wrapper.addEventListener($.EVENT_START, this); //临时处理
|
|
|
this.wrapper.addEventListener('drag', this);
|
|
|
this.wrapper.addEventListener('dragend', this);
|
|
|
}
|
|
|
this.wrapper.addEventListener('webkitTransitionEnd', this);
|
|
|
},
|
|
|
openPercentage: function(percentage) {
|
|
|
var p = percentage / 100;
|
|
|
if (!this.slideIn) {
|
|
|
if (this.offCanvasLeft && percentage >= 0) {
|
|
|
this.updateTranslate(this.offCanvasLeftWidth * p);
|
|
|
this.offCanvasLeft.classList[p !== 0 ? 'add' : 'remove'](CLASS_ACTIVE);
|
|
|
} else if (this.offCanvasRight && percentage <= 0) {
|
|
|
this.updateTranslate(this.offCanvasRightWidth * p);
|
|
|
this.offCanvasRight.classList[p !== 0 ? 'add' : 'remove'](CLASS_ACTIVE);
|
|
|
}
|
|
|
this.classList[p !== 0 ? 'add' : 'remove'](CLASS_ACTIVE);
|
|
|
} else {
|
|
|
if (this.offCanvasLeft && percentage >= 0) {
|
|
|
p = p === 0 ? -1 : 0;
|
|
|
this.updateTranslate(this.offCanvasLeftWidth * p);
|
|
|
this.offCanvasLeft.classList[percentage !== 0 ? 'add' : 'remove'](CLASS_ACTIVE);
|
|
|
} else if (this.offCanvasRight && percentage <= 0) {
|
|
|
p = p === 0 ? 1 : 0;
|
|
|
this.updateTranslate(this.offCanvasRightWidth * p);
|
|
|
this.offCanvasRight.classList[percentage !== 0 ? 'add' : 'remove'](CLASS_ACTIVE);
|
|
|
}
|
|
|
this.classList[percentage !== 0 ? 'add' : 'remove'](CLASS_ACTIVE);
|
|
|
}
|
|
|
},
|
|
|
updateTranslate: function(x) {
|
|
|
if (x !== this.lastTranslateX) {
|
|
|
if (!this.slideIn) {
|
|
|
if ((!this.offCanvasLeft && x > 0) || (!this.offCanvasRight && x < 0)) {
|
|
|
this.setTranslateX(0);
|
|
|
return;
|
|
|
}
|
|
|
if (this.leftShowing && x > this.offCanvasLeftWidth) {
|
|
|
this.setTranslateX(this.offCanvasLeftWidth);
|
|
|
return;
|
|
|
}
|
|
|
if (this.rightShowing && x < -this.offCanvasRightWidth) {
|
|
|
this.setTranslateX(-this.offCanvasRightWidth);
|
|
|
return;
|
|
|
}
|
|
|
this.setTranslateX(x);
|
|
|
if (x >= 0) {
|
|
|
this.leftShowing = true;
|
|
|
this.rightShowing = false;
|
|
|
if (x > 0) {
|
|
|
if (this.offCanvasLeft) {
|
|
|
$.each(this.offCanvasLefts, function(index, offCanvas) {
|
|
|
if (offCanvas === this.offCanvasLeft) {
|
|
|
this.offCanvasLeft.style.zIndex = 0;
|
|
|
} else {
|
|
|
offCanvas.style.zIndex = -1;
|
|
|
}
|
|
|
}.bind(this));
|
|
|
}
|
|
|
if (this.offCanvasRight) {
|
|
|
this.offCanvasRight.style.zIndex = -1;
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
this.rightShowing = true;
|
|
|
this.leftShowing = false;
|
|
|
if (this.offCanvasRight) {
|
|
|
$.each(this.offCanvasRights, function(index, offCanvas) {
|
|
|
if (offCanvas === this.offCanvasRight) {
|
|
|
offCanvas.style.zIndex = 0;
|
|
|
} else {
|
|
|
offCanvas.style.zIndex = -1;
|
|
|
}
|
|
|
}.bind(this));
|
|
|
}
|
|
|
if (this.offCanvasLeft) {
|
|
|
this.offCanvasLeft.style.zIndex = -1;
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
if (this.offCanvas.classList.contains(CLASS_OFF_CANVAS_RIGHT)) {
|
|
|
if (x < 0) {
|
|
|
this.setTranslateX(0);
|
|
|
return;
|
|
|
}
|
|
|
if (x > this.offCanvasRightWidth) {
|
|
|
this.setTranslateX(this.offCanvasRightWidth);
|
|
|
return;
|
|
|
}
|
|
|
} else {
|
|
|
if (x > 0) {
|
|
|
this.setTranslateX(0);
|
|
|
return;
|
|
|
}
|
|
|
if (x < -this.offCanvasLeftWidth) {
|
|
|
this.setTranslateX(-this.offCanvasLeftWidth);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
this.setTranslateX(x);
|
|
|
}
|
|
|
this.lastTranslateX = x;
|
|
|
}
|
|
|
},
|
|
|
setTranslateX: $.animationFrame(function(x) {
|
|
|
if (this.scroller) {
|
|
|
if (this.scalable && this.offCanvas.parentNode === this.wrapper) {
|
|
|
var percent = Math.abs(x) / this.offCanvasWidth;
|
|
|
var zoomOutScale = 1 - (1 - this.options.scale) * percent;
|
|
|
var zoomInScale = this.options.scale + (1 - this.options.scale) * percent;
|
|
|
var zoomOutOpacity = 1 - (1 - this.options.opacity) * percent;
|
|
|
var zoomInOpacity = this.options.opacity + (1 - this.options.opacity) * percent;
|
|
|
if (this.offCanvas.classList.contains(CLASS_OFF_CANVAS_LEFT)) {
|
|
|
this.offCanvas.style.webkitTransformOrigin = '-100%';
|
|
|
this.scroller.style.webkitTransformOrigin = 'left';
|
|
|
} else {
|
|
|
this.offCanvas.style.webkitTransformOrigin = '200%';
|
|
|
this.scroller.style.webkitTransformOrigin = 'right';
|
|
|
}
|
|
|
this.offCanvas.style.opacity = zoomInOpacity;
|
|
|
this.offCanvas.style.webkitTransform = 'translate3d(0,0,0) scale(' + zoomInScale + ')';
|
|
|
this.scroller.style.webkitTransform = 'translate3d(' + x + 'px,0,0) scale(' + zoomOutScale + ')';
|
|
|
} else {
|
|
|
if (this.slideIn) {
|
|
|
this.offCanvas.style.webkitTransform = 'translate3d(' + x + 'px,0,0)';
|
|
|
} else {
|
|
|
this.scroller.style.webkitTransform = 'translate3d(' + x + 'px,0,0)';
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}),
|
|
|
getTranslateX: function() {
|
|
|
if (this.offCanvas) {
|
|
|
var scroller = this.slideIn ? this.offCanvas : this.scroller;
|
|
|
var result = $.parseTranslateMatrix($.getStyles(scroller, 'webkitTransform'));
|
|
|
return (result && result.x) || 0;
|
|
|
}
|
|
|
return 0;
|
|
|
},
|
|
|
isShown: function(direction) {
|
|
|
var shown = false;
|
|
|
if (!this.slideIn) {
|
|
|
var x = this.getTranslateX();
|
|
|
if (direction === 'right') {
|
|
|
shown = this.classList.contains(CLASS_ACTIVE) && x < 0;
|
|
|
} else if (direction === 'left') {
|
|
|
shown = this.classList.contains(CLASS_ACTIVE) && x > 0;
|
|
|
} else {
|
|
|
shown = this.classList.contains(CLASS_ACTIVE) && x !== 0;
|
|
|
}
|
|
|
} else {
|
|
|
if (direction === 'left') {
|
|
|
shown = this.classList.contains(CLASS_ACTIVE) && this.wrapper.querySelector('.' + CLASS_OFF_CANVAS_LEFT + '.' + CLASS_ACTIVE);
|
|
|
} else if (direction === 'right') {
|
|
|
shown = this.classList.contains(CLASS_ACTIVE) && this.wrapper.querySelector('.' + CLASS_OFF_CANVAS_RIGHT + '.' + CLASS_ACTIVE);
|
|
|
} else {
|
|
|
shown = this.classList.contains(CLASS_ACTIVE) && (this.wrapper.querySelector('.' + CLASS_OFF_CANVAS_LEFT + '.' + CLASS_ACTIVE) || this.wrapper.querySelector('.' + CLASS_OFF_CANVAS_RIGHT + '.' + CLASS_ACTIVE));
|
|
|
}
|
|
|
}
|
|
|
return shown;
|
|
|
},
|
|
|
close: function() {
|
|
|
this._initOffCanvasVisible();
|
|
|
this.offCanvas = this.wrapper.querySelector('.' + CLASS_OFF_CANVAS_RIGHT + '.' + CLASS_ACTIVE) || this.wrapper.querySelector('.' + CLASS_OFF_CANVAS_LEFT + '.' + CLASS_ACTIVE);
|
|
|
this.offCanvasWidth = this.offCanvas.offsetWidth;
|
|
|
if (this.scroller) {
|
|
|
this.offCanvas.offsetHeight;
|
|
|
this.offCanvas.classList.add(CLASS_TRANSITIONING);
|
|
|
this.scroller.classList.add(CLASS_TRANSITIONING);
|
|
|
this.openPercentage(0);
|
|
|
}
|
|
|
},
|
|
|
show: function(direction) {
|
|
|
this._initOffCanvasVisible();
|
|
|
if (this.isShown(direction)) {
|
|
|
return false;
|
|
|
}
|
|
|
if (!direction) {
|
|
|
direction = this.wrapper.querySelector('.' + CLASS_OFF_CANVAS_RIGHT) ? 'right' : 'left';
|
|
|
}
|
|
|
if (direction === 'right') {
|
|
|
this.offCanvas = this.offCanvasRight;
|
|
|
this.offCanvasWidth = this.offCanvasRightWidth;
|
|
|
} else {
|
|
|
this.offCanvas = this.offCanvasLeft;
|
|
|
this.offCanvasWidth = this.offCanvasLeftWidth;
|
|
|
}
|
|
|
if (this.scroller) {
|
|
|
this.offCanvas.offsetHeight;
|
|
|
this.offCanvas.classList.add(CLASS_TRANSITIONING);
|
|
|
this.scroller.classList.add(CLASS_TRANSITIONING);
|
|
|
this.openPercentage(direction === 'left' ? 100 : -100);
|
|
|
}
|
|
|
return true;
|
|
|
},
|
|
|
toggle: function(directionOrOffCanvas) {
|
|
|
var direction = directionOrOffCanvas;
|
|
|
if (directionOrOffCanvas && directionOrOffCanvas.classList) {
|
|
|
direction = directionOrOffCanvas.classList.contains(CLASS_OFF_CANVAS_LEFT) ? 'left' : 'right';
|
|
|
this.refresh(directionOrOffCanvas);
|
|
|
}
|
|
|
if (!this.show(direction)) {
|
|
|
this.close();
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
//hash to offcanvas
|
|
|
var findOffCanvasContainer = function(target) {
|
|
|
parentNode = target.parentNode;
|
|
|
if (parentNode) {
|
|
|
if (parentNode.classList.contains(CLASS_OFF_CANVAS_WRAP)) {
|
|
|
return parentNode;
|
|
|
} else {
|
|
|
parentNode = parentNode.parentNode;
|
|
|
if (parentNode.classList.contains(CLASS_OFF_CANVAS_WRAP)) {
|
|
|
return parentNode;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
var handle = function(event, target) {
|
|
|
if (target.tagName === 'A' && target.hash) {
|
|
|
var offcanvas = document.getElementById(target.hash.replace('#', ''));
|
|
|
if (offcanvas) {
|
|
|
var container = findOffCanvasContainer(offcanvas);
|
|
|
if (container) {
|
|
|
$.targets._container = container;
|
|
|
return offcanvas;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
$.registerTarget({
|
|
|
name: name,
|
|
|
index: 60,
|
|
|
handle: handle,
|
|
|
target: false,
|
|
|
isReset: false,
|
|
|
isContinue: true
|
|
|
});
|
|
|
|
|
|
window.addEventListener('tap', function(e) {
|
|
|
if (!$.targets.offcanvas) {
|
|
|
return;
|
|
|
}
|
|
|
//TODO 此处类型的代码后续考虑统一优化(target机制),现在的实现费力不讨好
|
|
|
var target = e.target;
|
|
|
for (; target && target !== document; target = target.parentNode) {
|
|
|
if (target.tagName === 'A' && target.hash && target.hash === ('#' + $.targets.offcanvas.id)) {
|
|
|
e.detail && e.detail.gesture && e.detail.gesture.preventDefault(); //fixed hashchange
|
|
|
$($.targets._container).offCanvas().toggle($.targets.offcanvas);
|
|
|
$.targets.offcanvas = $.targets._container = null;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
$.fn.offCanvas = function(options) {
|
|
|
var offCanvasApis = [];
|
|
|
this.each(function() {
|
|
|
var offCanvasApi = null;
|
|
|
var self = this;
|
|
|
//hack old version
|
|
|
if (!self.classList.contains(CLASS_OFF_CANVAS_WRAP)) {
|
|
|
self = findOffCanvasContainer(self);
|
|
|
}
|
|
|
var id = self.getAttribute('data-offCanvas');
|
|
|
if (!id) {
|
|
|
id = ++$.uuid;
|
|
|
$.data[id] = offCanvasApi = new OffCanvas(self, options);
|
|
|
self.setAttribute('data-offCanvas', id);
|
|
|
} else {
|
|
|
offCanvasApi = $.data[id];
|
|
|
}
|
|
|
if (options === 'show' || options === 'close' || options === 'toggle') {
|
|
|
offCanvasApi.toggle();
|
|
|
}
|
|
|
offCanvasApis.push(offCanvasApi);
|
|
|
});
|
|
|
return offCanvasApis.length === 1 ? offCanvasApis[0] : offCanvasApis;
|
|
|
};
|
|
|
$.ready(function() {
|
|
|
$('.mui-off-canvas-wrap').offCanvas();
|
|
|
});
|
|
|
})(mui, window, document, 'offcanvas');
|
|
|
/**
|
|
|
* actions
|
|
|
* @param {type} $
|
|
|
* @param {type} name
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, name) {
|
|
|
var CLASS_ACTION = 'mui-action';
|
|
|
|
|
|
var handle = function(event, target) {
|
|
|
var className = target.className || '';
|
|
|
if (typeof className !== 'string') { //svg className(SVGAnimatedString)
|
|
|
className = '';
|
|
|
}
|
|
|
if (className && ~className.indexOf(CLASS_ACTION)) {
|
|
|
if (target.classList.contains('mui-action-back')) {
|
|
|
event.preventDefault();
|
|
|
}
|
|
|
return target;
|
|
|
}
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
$.registerTarget({
|
|
|
name: name,
|
|
|
index: 50,
|
|
|
handle: handle,
|
|
|
target: false,
|
|
|
isContinue: true
|
|
|
});
|
|
|
|
|
|
})(mui, 'action');
|
|
|
/**
|
|
|
* Modals
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @param {type} document
|
|
|
* @param {type} name
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window, document, name) {
|
|
|
var CLASS_MODAL = 'mui-modal';
|
|
|
|
|
|
var handle = function(event, target) {
|
|
|
if (target.tagName === 'A' && target.hash) {
|
|
|
var modal = document.getElementById(target.hash.replace('#', ''));
|
|
|
if (modal && modal.classList.contains(CLASS_MODAL)) {
|
|
|
return modal;
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
$.registerTarget({
|
|
|
name: name,
|
|
|
index: 50,
|
|
|
handle: handle,
|
|
|
target: false,
|
|
|
isReset: false,
|
|
|
isContinue: true
|
|
|
});
|
|
|
|
|
|
window.addEventListener('tap', function(event) {
|
|
|
if ($.targets.modal) {
|
|
|
event.detail.gesture.preventDefault(); //fixed hashchange
|
|
|
$.targets.modal.classList.toggle('mui-active');
|
|
|
}
|
|
|
});
|
|
|
})(mui, window, document, 'modal');
|
|
|
/**
|
|
|
* Popovers
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @param {type} document
|
|
|
* @param {type} name
|
|
|
* @param {type} undefined
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window, document, name) {
|
|
|
|
|
|
var CLASS_POPOVER = 'mui-popover';
|
|
|
var CLASS_POPOVER_ARROW = 'mui-popover-arrow';
|
|
|
var CLASS_ACTION_POPOVER = 'mui-popover-action';
|
|
|
var CLASS_BACKDROP = 'mui-backdrop';
|
|
|
var CLASS_BAR_POPOVER = 'mui-bar-popover';
|
|
|
var CLASS_BAR_BACKDROP = 'mui-bar-backdrop';
|
|
|
var CLASS_ACTION_BACKDROP = 'mui-backdrop-action';
|
|
|
var CLASS_ACTIVE = 'mui-active';
|
|
|
var CLASS_BOTTOM = 'mui-bottom';
|
|
|
|
|
|
|
|
|
|
|
|
var handle = function(event, target) {
|
|
|
if (target.tagName === 'A' && target.hash) {
|
|
|
$.targets._popover = document.getElementById(target.hash.replace('#', ''));
|
|
|
if ($.targets._popover && $.targets._popover.classList.contains(CLASS_POPOVER)) {
|
|
|
return target;
|
|
|
} else {
|
|
|
$.targets._popover = null;
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
$.registerTarget({
|
|
|
name: name,
|
|
|
index: 60,
|
|
|
handle: handle,
|
|
|
target: false,
|
|
|
isReset: false,
|
|
|
isContinue: true
|
|
|
});
|
|
|
|
|
|
var onPopoverShown = function(e) {
|
|
|
this.removeEventListener('webkitTransitionEnd', onPopoverShown);
|
|
|
this.addEventListener($.EVENT_MOVE, $.preventDefault);
|
|
|
$.trigger(this, 'shown', this);
|
|
|
}
|
|
|
var onPopoverHidden = function(e) {
|
|
|
setStyle(this, 'none');
|
|
|
this.removeEventListener('webkitTransitionEnd', onPopoverHidden);
|
|
|
this.removeEventListener($.EVENT_MOVE, $.preventDefault);
|
|
|
$.trigger(this, 'hidden', this);
|
|
|
};
|
|
|
|
|
|
var backdrop = (function() {
|
|
|
var element = document.createElement('div');
|
|
|
element.classList.add(CLASS_BACKDROP);
|
|
|
element.addEventListener($.EVENT_MOVE, $.preventDefault);
|
|
|
element.addEventListener('tap', function(e) {
|
|
|
var popover = $.targets._popover;
|
|
|
if (popover) {
|
|
|
popover.addEventListener('webkitTransitionEnd', onPopoverHidden);
|
|
|
popover.classList.remove(CLASS_ACTIVE);
|
|
|
removeBackdrop(popover);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
return element;
|
|
|
}());
|
|
|
var removeBackdropTimer;
|
|
|
var removeBackdrop = function(popover) {
|
|
|
backdrop.setAttribute('style', 'opacity:0');
|
|
|
$.targets.popover = $.targets._popover = null; //reset
|
|
|
removeBackdropTimer = $.later(function() {
|
|
|
if (!popover.classList.contains(CLASS_ACTIVE) && backdrop.parentNode && backdrop.parentNode === document.body) {
|
|
|
document.body.removeChild(backdrop);
|
|
|
}
|
|
|
}, 350);
|
|
|
};
|
|
|
window.addEventListener('tap', function(e) {
|
|
|
if (!$.targets.popover) {
|
|
|
return;
|
|
|
}
|
|
|
var toggle = false;
|
|
|
var target = e.target;
|
|
|
for (; target && target !== document; target = target.parentNode) {
|
|
|
if (target === $.targets.popover) {
|
|
|
toggle = true;
|
|
|
}
|
|
|
}
|
|
|
if (toggle) {
|
|
|
e.detail.gesture.preventDefault(); //fixed hashchange
|
|
|
togglePopover($.targets._popover, $.targets.popover);
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
var togglePopover = function(popover, anchor, state) {
|
|
|
if ((state === 'show' && popover.classList.contains(CLASS_ACTIVE)) || (state === 'hide' && !popover.classList.contains(CLASS_ACTIVE))) {
|
|
|
return;
|
|
|
}
|
|
|
removeBackdropTimer && removeBackdropTimer.cancel(); //取消remove的timer
|
|
|
//remove一遍,以免来回快速切换,导致webkitTransitionEnd不触发,无法remove
|
|
|
popover.removeEventListener('webkitTransitionEnd', onPopoverShown);
|
|
|
popover.removeEventListener('webkitTransitionEnd', onPopoverHidden);
|
|
|
backdrop.classList.remove(CLASS_BAR_BACKDROP);
|
|
|
backdrop.classList.remove(CLASS_ACTION_BACKDROP);
|
|
|
var _popover = document.querySelector('.mui-popover.mui-active');
|
|
|
if (_popover) {
|
|
|
// _popover.setAttribute('style', '');
|
|
|
_popover.addEventListener('webkitTransitionEnd', onPopoverHidden);
|
|
|
_popover.classList.remove(CLASS_ACTIVE);
|
|
|
// _popover.removeEventListener('webkitTransitionEnd', onPopoverHidden);
|
|
|
//同一个弹出则直接返回,解决同一个popover的toggle
|
|
|
if (popover === _popover) {
|
|
|
removeBackdrop(_popover);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
var isActionSheet = false;
|
|
|
if (popover.classList.contains(CLASS_BAR_POPOVER) || popover.classList.contains(CLASS_ACTION_POPOVER)) { //navBar
|
|
|
if (popover.classList.contains(CLASS_ACTION_POPOVER)) { //action sheet popover
|
|
|
isActionSheet = true;
|
|
|
backdrop.classList.add(CLASS_ACTION_BACKDROP);
|
|
|
} else { //bar popover
|
|
|
backdrop.classList.add(CLASS_BAR_BACKDROP);
|
|
|
// if (anchor) {
|
|
|
// if (anchor.parentNode) {
|
|
|
// var offsetWidth = anchor.offsetWidth;
|
|
|
// var offsetLeft = anchor.offsetLeft;
|
|
|
// var innerWidth = window.innerWidth;
|
|
|
// popover.style.left = (Math.min(Math.max(offsetLeft, defaultPadding), innerWidth - offsetWidth - defaultPadding)) + "px";
|
|
|
// } else {
|
|
|
// //TODO anchor is position:{left,top,bottom,right}
|
|
|
// }
|
|
|
// }
|
|
|
}
|
|
|
}
|
|
|
setStyle(popover, 'block'); //actionsheet transform
|
|
|
popover.offsetHeight;
|
|
|
popover.classList.add(CLASS_ACTIVE);
|
|
|
backdrop.setAttribute('style', '');
|
|
|
document.body.appendChild(backdrop);
|
|
|
calPosition(popover, anchor, isActionSheet); //position
|
|
|
backdrop.classList.add(CLASS_ACTIVE);
|
|
|
popover.addEventListener('webkitTransitionEnd', onPopoverShown);
|
|
|
};
|
|
|
var setStyle = function(popover, display, top, left) {
|
|
|
var style = popover.style;
|
|
|
if (typeof display !== 'undefined')
|
|
|
style.display = display;
|
|
|
if (typeof top !== 'undefined')
|
|
|
style.top = top + 'px';
|
|
|
if (typeof left !== 'undefined')
|
|
|
style.left = left + 'px';
|
|
|
};
|
|
|
var calPosition = function(popover, anchor, isActionSheet) {
|
|
|
if (!popover || !anchor) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (isActionSheet) { //actionsheet
|
|
|
setStyle(popover, 'block')
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
var wWidth = window.innerWidth;
|
|
|
var wHeight = window.innerHeight;
|
|
|
|
|
|
var pWidth = popover.offsetWidth;
|
|
|
var pHeight = popover.offsetHeight;
|
|
|
|
|
|
var aWidth = anchor.offsetWidth;
|
|
|
var aHeight = anchor.offsetHeight;
|
|
|
var offset = $.offset(anchor);
|
|
|
|
|
|
var arrow = popover.querySelector('.' + CLASS_POPOVER_ARROW);
|
|
|
if (!arrow) {
|
|
|
arrow = document.createElement('div');
|
|
|
arrow.className = CLASS_POPOVER_ARROW;
|
|
|
popover.appendChild(arrow);
|
|
|
}
|
|
|
var arrowSize = arrow && arrow.offsetWidth / 2 || 0;
|
|
|
|
|
|
|
|
|
|
|
|
var pTop = 0;
|
|
|
var pLeft = 0;
|
|
|
var diff = 0;
|
|
|
var arrowLeft = 0;
|
|
|
var defaultPadding = popover.classList.contains(CLASS_ACTION_POPOVER) ? 0 : 5;
|
|
|
|
|
|
var position = 'top';
|
|
|
if ((pHeight + arrowSize) < (offset.top - window.pageYOffset)) { //top
|
|
|
pTop = offset.top - pHeight - arrowSize;
|
|
|
} else if ((pHeight + arrowSize) < (wHeight - (offset.top - window.pageYOffset) - aHeight)) { //bottom
|
|
|
position = 'bottom';
|
|
|
pTop = offset.top + aHeight + arrowSize;
|
|
|
} else { //middle
|
|
|
position = 'middle';
|
|
|
pTop = Math.max((wHeight - pHeight) / 2 + window.pageYOffset, 0);
|
|
|
pLeft = Math.max((wWidth - pWidth) / 2 + window.pageXOffset, 0);
|
|
|
}
|
|
|
if (position === 'top' || position === 'bottom') {
|
|
|
pLeft = aWidth / 2 + offset.left - pWidth / 2;
|
|
|
diff = pLeft;
|
|
|
if (pLeft < defaultPadding) pLeft = defaultPadding;
|
|
|
if (pLeft + pWidth > wWidth) pLeft = wWidth - pWidth - defaultPadding;
|
|
|
|
|
|
if (arrow) {
|
|
|
if (position === 'top') {
|
|
|
arrow.classList.add(CLASS_BOTTOM);
|
|
|
} else {
|
|
|
arrow.classList.remove(CLASS_BOTTOM);
|
|
|
}
|
|
|
diff = diff - pLeft;
|
|
|
arrowLeft = (pWidth / 2 - arrowSize / 2 + diff);
|
|
|
arrowLeft = Math.max(Math.min(arrowLeft, pWidth - arrowSize * 2 - 6), 6);
|
|
|
arrow.setAttribute('style', 'left:' + arrowLeft + 'px');
|
|
|
}
|
|
|
} else if (position === 'middle') {
|
|
|
arrow.setAttribute('style', 'display:none');
|
|
|
}
|
|
|
setStyle(popover, 'block', pTop, pLeft);
|
|
|
};
|
|
|
|
|
|
$.createMask = function(callback) {
|
|
|
var element = document.createElement('div');
|
|
|
element.classList.add(CLASS_BACKDROP);
|
|
|
element.addEventListener($.EVENT_MOVE, $.preventDefault);
|
|
|
element.addEventListener('tap', function() {
|
|
|
mask.close();
|
|
|
});
|
|
|
var mask = [element];
|
|
|
mask._show = false;
|
|
|
mask.show = function() {
|
|
|
mask._show = true;
|
|
|
element.setAttribute('style', 'opacity:1');
|
|
|
document.body.appendChild(element);
|
|
|
return mask;
|
|
|
};
|
|
|
mask._remove = function() {
|
|
|
if (mask._show) {
|
|
|
mask._show = false;
|
|
|
element.setAttribute('style', 'opacity:0');
|
|
|
$.later(function() {
|
|
|
var body = document.body;
|
|
|
element.parentNode === body && body.removeChild(element);
|
|
|
}, 350);
|
|
|
}
|
|
|
return mask;
|
|
|
};
|
|
|
mask.close = function() {
|
|
|
if (callback) {
|
|
|
if (callback() !== false) {
|
|
|
mask._remove();
|
|
|
}
|
|
|
} else {
|
|
|
mask._remove();
|
|
|
}
|
|
|
};
|
|
|
return mask;
|
|
|
};
|
|
|
$.fn.popover = function() {
|
|
|
var args = arguments;
|
|
|
this.each(function() {
|
|
|
$.targets._popover = this;
|
|
|
if (args[0] === 'show' || args[0] === 'hide' || args[0] === 'toggle') {
|
|
|
togglePopover(this, args[1], args[0]);
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
|
|
|
})(mui, window, document, 'popover');
|
|
|
/**
|
|
|
* segmented-controllers
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @param {type} document
|
|
|
* @param {type} undefined
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window, document, name, undefined) {
|
|
|
|
|
|
var CLASS_CONTROL_ITEM = 'mui-control-item';
|
|
|
var CLASS_SEGMENTED_CONTROL = 'mui-segmented-control';
|
|
|
var CLASS_SEGMENTED_CONTROL_VERTICAL = 'mui-segmented-control-vertical';
|
|
|
var CLASS_CONTROL_CONTENT = 'mui-control-content';
|
|
|
var CLASS_TAB_BAR = 'mui-bar-tab';
|
|
|
var CLASS_TAB_ITEM = 'mui-tab-item';
|
|
|
var CLASS_SLIDER_ITEM = 'mui-slider-item';
|
|
|
|
|
|
var handle = function(event, target) {
|
|
|
if (target.classList && (target.classList.contains(CLASS_CONTROL_ITEM) || target.classList.contains(CLASS_TAB_ITEM))) {
|
|
|
if (target.parentNode && target.parentNode.classList && target.parentNode.classList.contains(CLASS_SEGMENTED_CONTROL_VERTICAL)) {
|
|
|
//vertical 如果preventDefault会导致无法滚动
|
|
|
} else {
|
|
|
|
|
|
event.preventDefault();
|
|
|
// if(target.tagName == 'A') {
|
|
|
// // fixed 底部选项卡href 无法跳转 && stop hash change
|
|
|
// var curr_href = location.hostname + location.pathname,
|
|
|
// target_href = target.hostname + target.pathname;
|
|
|
|
|
|
// if (curr_href == target_href && target.hash !== "") {
|
|
|
// event.preventDefault();
|
|
|
// return target;
|
|
|
// }else{
|
|
|
// return false
|
|
|
// }
|
|
|
// }
|
|
|
}
|
|
|
// if (target.hash) {
|
|
|
return target;
|
|
|
// }
|
|
|
}
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
$.registerTarget({
|
|
|
name: name,
|
|
|
index: 80,
|
|
|
handle: handle,
|
|
|
target: false
|
|
|
});
|
|
|
|
|
|
window.addEventListener('tap', function(e) {
|
|
|
|
|
|
var targetTab = $.targets.tab;
|
|
|
if (!targetTab) {
|
|
|
return;
|
|
|
}
|
|
|
var activeTab;
|
|
|
var activeBodies;
|
|
|
var targetBody;
|
|
|
var className = 'mui-active';
|
|
|
var classSelector = '.' + className;
|
|
|
var segmentedControl = targetTab.parentNode;
|
|
|
|
|
|
for (; segmentedControl && segmentedControl !== document; segmentedControl = segmentedControl.parentNode) {
|
|
|
if (segmentedControl.classList.contains(CLASS_SEGMENTED_CONTROL)) {
|
|
|
activeTab = segmentedControl.querySelector(classSelector + '.' + CLASS_CONTROL_ITEM);
|
|
|
break;
|
|
|
} else if (segmentedControl.classList.contains(CLASS_TAB_BAR)) {
|
|
|
activeTab = segmentedControl.querySelector(classSelector + '.' + CLASS_TAB_ITEM);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (activeTab) {
|
|
|
activeTab.classList.remove(className);
|
|
|
}
|
|
|
|
|
|
var isLastActive = targetTab === activeTab;
|
|
|
if (targetTab) {
|
|
|
targetTab.classList.add(className);
|
|
|
}
|
|
|
|
|
|
if (!targetTab.hash) {
|
|
|
return;
|
|
|
}
|
|
|
targetBody = document.getElementById(targetTab.hash.replace('#', ''));
|
|
|
|
|
|
if (!targetBody) {
|
|
|
return;
|
|
|
}
|
|
|
if (!targetBody.classList.contains(CLASS_CONTROL_CONTENT)) { //tab bar popover
|
|
|
targetTab.classList[isLastActive ? 'remove' : 'add'](className);
|
|
|
return;
|
|
|
}
|
|
|
if (isLastActive) { //same
|
|
|
return;
|
|
|
}
|
|
|
var parentNode = targetBody.parentNode;
|
|
|
activeBodies = parentNode.querySelectorAll('.' + CLASS_CONTROL_CONTENT + classSelector);
|
|
|
for (var i = 0; i < activeBodies.length; i++) {
|
|
|
var activeBody = activeBodies[i];
|
|
|
activeBody.parentNode === parentNode && activeBody.classList.remove(className);
|
|
|
}
|
|
|
|
|
|
targetBody.classList.add(className);
|
|
|
|
|
|
var contents = [];
|
|
|
var _contents = parentNode.querySelectorAll('.' + CLASS_CONTROL_CONTENT);
|
|
|
for (var i = 0; i < _contents.length; i++) { //查找直属子节点
|
|
|
_contents[i].parentNode === parentNode && (contents.push(_contents[i]));
|
|
|
}
|
|
|
$.trigger(targetBody, $.eventName('shown', name), {
|
|
|
tabNumber: Array.prototype.indexOf.call(contents, targetBody)
|
|
|
});
|
|
|
e.detail && e.detail.gesture.preventDefault(); //fixed hashchange
|
|
|
});
|
|
|
|
|
|
})(mui, window, document, 'tab');
|
|
|
/**
|
|
|
* Toggles switch
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @param {type} name
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window, name) {
|
|
|
|
|
|
var CLASS_SWITCH = 'mui-switch';
|
|
|
var CLASS_SWITCH_HANDLE = 'mui-switch-handle';
|
|
|
var CLASS_ACTIVE = 'mui-active';
|
|
|
var CLASS_DRAGGING = 'mui-dragging';
|
|
|
|
|
|
var CLASS_DISABLED = 'mui-disabled';
|
|
|
|
|
|
var SELECTOR_SWITCH_HANDLE = '.' + CLASS_SWITCH_HANDLE;
|
|
|
|
|
|
var handle = function(event, target) {
|
|
|
if (target.classList && target.classList.contains(CLASS_SWITCH)) {
|
|
|
return target;
|
|
|
}
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
$.registerTarget({
|
|
|
name: name,
|
|
|
index: 100,
|
|
|
handle: handle,
|
|
|
target: false
|
|
|
});
|
|
|
|
|
|
|
|
|
var Toggle = function(element) {
|
|
|
this.element = element;
|
|
|
this.classList = this.element.classList;
|
|
|
this.handle = this.element.querySelector(SELECTOR_SWITCH_HANDLE);
|
|
|
this.init();
|
|
|
this.initEvent();
|
|
|
};
|
|
|
Toggle.prototype.init = function() {
|
|
|
this.toggleWidth = this.element.offsetWidth;
|
|
|
this.handleWidth = this.handle.offsetWidth;
|
|
|
this.handleX = this.toggleWidth - this.handleWidth - 3;
|
|
|
};
|
|
|
Toggle.prototype.initEvent = function() {
|
|
|
this.element.addEventListener($.EVENT_START, this);
|
|
|
this.element.addEventListener('drag', this);
|
|
|
this.element.addEventListener('swiperight', this);
|
|
|
this.element.addEventListener($.EVENT_END, this);
|
|
|
this.element.addEventListener($.EVENT_CANCEL, this);
|
|
|
|
|
|
};
|
|
|
Toggle.prototype.handleEvent = function(e) {
|
|
|
if (this.classList.contains(CLASS_DISABLED)) {
|
|
|
return;
|
|
|
}
|
|
|
switch (e.type) {
|
|
|
case $.EVENT_START:
|
|
|
this.start(e);
|
|
|
break;
|
|
|
case 'drag':
|
|
|
this.drag(e);
|
|
|
break;
|
|
|
case 'swiperight':
|
|
|
this.swiperight();
|
|
|
break;
|
|
|
case $.EVENT_END:
|
|
|
case $.EVENT_CANCEL:
|
|
|
this.end(e);
|
|
|
break;
|
|
|
}
|
|
|
};
|
|
|
Toggle.prototype.start = function(e) {
|
|
|
this.handle.style.webkitTransitionDuration = this.element.style.webkitTransitionDuration = '.2s';
|
|
|
this.classList.add(CLASS_DRAGGING);
|
|
|
if (this.toggleWidth === 0 || this.handleWidth === 0) { //当switch处于隐藏状态时,width为0,需要重新初始化
|
|
|
this.init();
|
|
|
}
|
|
|
};
|
|
|
Toggle.prototype.drag = function(e) {
|
|
|
var detail = e.detail;
|
|
|
if (!this.isDragging) {
|
|
|
if (detail.direction === 'left' || detail.direction === 'right') {
|
|
|
this.isDragging = true;
|
|
|
this.lastChanged = undefined;
|
|
|
this.initialState = this.classList.contains(CLASS_ACTIVE);
|
|
|
}
|
|
|
}
|
|
|
if (this.isDragging) {
|
|
|
this.setTranslateX(detail.deltaX);
|
|
|
e.stopPropagation();
|
|
|
detail.gesture.preventDefault();
|
|
|
}
|
|
|
};
|
|
|
Toggle.prototype.swiperight = function(e) {
|
|
|
if (this.isDragging) {
|
|
|
e.stopPropagation();
|
|
|
}
|
|
|
};
|
|
|
Toggle.prototype.end = function(e) {
|
|
|
this.classList.remove(CLASS_DRAGGING);
|
|
|
if (this.isDragging) {
|
|
|
this.isDragging = false;
|
|
|
e.stopPropagation();
|
|
|
$.trigger(this.element, 'toggle', {
|
|
|
isActive: this.classList.contains(CLASS_ACTIVE)
|
|
|
});
|
|
|
} else {
|
|
|
this.toggle();
|
|
|
}
|
|
|
};
|
|
|
Toggle.prototype.toggle = function(animate) {
|
|
|
var classList = this.classList;
|
|
|
if (animate === false) {
|
|
|
this.handle.style.webkitTransitionDuration = this.element.style.webkitTransitionDuration = '0s';
|
|
|
} else {
|
|
|
this.handle.style.webkitTransitionDuration = this.element.style.webkitTransitionDuration = '.2s';
|
|
|
}
|
|
|
if (classList.contains(CLASS_ACTIVE)) {
|
|
|
classList.remove(CLASS_ACTIVE);
|
|
|
this.handle.style.webkitTransform = 'translate(0,0)';
|
|
|
} else {
|
|
|
classList.add(CLASS_ACTIVE);
|
|
|
this.handle.style.webkitTransform = 'translate(' + this.handleX + 'px,0)';
|
|
|
}
|
|
|
$.trigger(this.element, 'toggle', {
|
|
|
isActive: this.classList.contains(CLASS_ACTIVE)
|
|
|
});
|
|
|
};
|
|
|
Toggle.prototype.setTranslateX = $.animationFrame(function(x) {
|
|
|
if (!this.isDragging) {
|
|
|
return;
|
|
|
}
|
|
|
var isChanged = false;
|
|
|
if ((this.initialState && -x > (this.handleX / 2)) || (!this.initialState && x > (this.handleX / 2))) {
|
|
|
isChanged = true;
|
|
|
}
|
|
|
if (this.lastChanged !== isChanged) {
|
|
|
if (isChanged) {
|
|
|
this.handle.style.webkitTransform = 'translate(' + (this.initialState ? 0 : this.handleX) + 'px,0)';
|
|
|
this.classList[this.initialState ? 'remove' : 'add'](CLASS_ACTIVE);
|
|
|
} else {
|
|
|
this.handle.style.webkitTransform = 'translate(' + (this.initialState ? this.handleX : 0) + 'px,0)';
|
|
|
this.classList[this.initialState ? 'add' : 'remove'](CLASS_ACTIVE);
|
|
|
}
|
|
|
this.lastChanged = isChanged;
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
$.fn['switch'] = function(options) {
|
|
|
var switchApis = [];
|
|
|
this.each(function() {
|
|
|
var switchApi = null;
|
|
|
var id = this.getAttribute('data-switch');
|
|
|
if (!id) {
|
|
|
id = ++$.uuid;
|
|
|
$.data[id] = new Toggle(this);
|
|
|
this.setAttribute('data-switch', id);
|
|
|
} else {
|
|
|
switchApi = $.data[id];
|
|
|
}
|
|
|
switchApis.push(switchApi);
|
|
|
});
|
|
|
return switchApis.length > 1 ? switchApis : switchApis[0];
|
|
|
};
|
|
|
$.ready(function() {
|
|
|
$('.' + CLASS_SWITCH)['switch']();
|
|
|
});
|
|
|
})(mui, window, 'toggle');
|
|
|
/**
|
|
|
* Tableviews
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @param {type} document
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window, document) {
|
|
|
|
|
|
var CLASS_ACTIVE = 'mui-active';
|
|
|
var CLASS_SELECTED = 'mui-selected';
|
|
|
var CLASS_GRID_VIEW = 'mui-grid-view';
|
|
|
var CLASS_RADIO_VIEW = 'mui-table-view-radio';
|
|
|
var CLASS_TABLE_VIEW_CELL = 'mui-table-view-cell';
|
|
|
var CLASS_COLLAPSE_CONTENT = 'mui-collapse-content';
|
|
|
var CLASS_DISABLED = 'mui-disabled';
|
|
|
var CLASS_TOGGLE = 'mui-switch';
|
|
|
var CLASS_BTN = 'mui-btn';
|
|
|
|
|
|
var CLASS_SLIDER_HANDLE = 'mui-slider-handle';
|
|
|
var CLASS_SLIDER_LEFT = 'mui-slider-left';
|
|
|
var CLASS_SLIDER_RIGHT = 'mui-slider-right';
|
|
|
var CLASS_TRANSITIONING = 'mui-transitioning';
|
|
|
|
|
|
|
|
|
var SELECTOR_SLIDER_HANDLE = '.' + CLASS_SLIDER_HANDLE;
|
|
|
var SELECTOR_SLIDER_LEFT = '.' + CLASS_SLIDER_LEFT;
|
|
|
var SELECTOR_SLIDER_RIGHT = '.' + CLASS_SLIDER_RIGHT;
|
|
|
var SELECTOR_SELECTED = '.' + CLASS_SELECTED;
|
|
|
var SELECTOR_BUTTON = '.' + CLASS_BTN;
|
|
|
var overFactor = 0.8;
|
|
|
var cell, a;
|
|
|
|
|
|
var isMoved = isOpened = openedActions = progress = false;
|
|
|
var sliderHandle = sliderActionLeft = sliderActionRight = buttonsLeft = buttonsRight = sliderDirection = sliderRequestAnimationFrame = false;
|
|
|
var timer = translateX = lastTranslateX = sliderActionLeftWidth = sliderActionRightWidth = 0;
|
|
|
|
|
|
|
|
|
|
|
|
var toggleActive = function(isActive) {
|
|
|
if (isActive) {
|
|
|
if (a) {
|
|
|
a.classList.add(CLASS_ACTIVE);
|
|
|
} else if (cell) {
|
|
|
cell.classList.add(CLASS_ACTIVE);
|
|
|
}
|
|
|
} else {
|
|
|
timer && timer.cancel();
|
|
|
if (a) {
|
|
|
a.classList.remove(CLASS_ACTIVE);
|
|
|
} else if (cell) {
|
|
|
cell.classList.remove(CLASS_ACTIVE);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
var updateTranslate = function() {
|
|
|
if (translateX !== lastTranslateX) {
|
|
|
if (buttonsRight && buttonsRight.length > 0) {
|
|
|
progress = translateX / sliderActionRightWidth;
|
|
|
if (translateX < -sliderActionRightWidth) {
|
|
|
translateX = -sliderActionRightWidth - Math.pow(-translateX - sliderActionRightWidth, overFactor);
|
|
|
}
|
|
|
for (var i = 0, len = buttonsRight.length; i < len; i++) {
|
|
|
var buttonRight = buttonsRight[i];
|
|
|
if (typeof buttonRight._buttonOffset === 'undefined') {
|
|
|
buttonRight._buttonOffset = buttonRight.offsetLeft;
|
|
|
}
|
|
|
buttonOffset = buttonRight._buttonOffset;
|
|
|
setTranslate(buttonRight, (translateX - buttonOffset * (1 + Math.max(progress, -1))));
|
|
|
}
|
|
|
}
|
|
|
if (buttonsLeft && buttonsLeft.length > 0) {
|
|
|
progress = translateX / sliderActionLeftWidth;
|
|
|
if (translateX > sliderActionLeftWidth) {
|
|
|
translateX = sliderActionLeftWidth + Math.pow(translateX - sliderActionLeftWidth, overFactor);
|
|
|
}
|
|
|
for (var i = 0, len = buttonsLeft.length; i < len; i++) {
|
|
|
var buttonLeft = buttonsLeft[i];
|
|
|
if (typeof buttonLeft._buttonOffset === 'undefined') {
|
|
|
buttonLeft._buttonOffset = sliderActionLeftWidth - buttonLeft.offsetLeft - buttonLeft.offsetWidth;
|
|
|
}
|
|
|
buttonOffset = buttonLeft._buttonOffset;
|
|
|
if (buttonsLeft.length > 1) {
|
|
|
buttonLeft.style.zIndex = buttonsLeft.length - i;
|
|
|
}
|
|
|
setTranslate(buttonLeft, (translateX + buttonOffset * (1 - Math.min(progress, 1))));
|
|
|
}
|
|
|
}
|
|
|
setTranslate(sliderHandle, translateX);
|
|
|
lastTranslateX = translateX;
|
|
|
}
|
|
|
sliderRequestAnimationFrame = requestAnimationFrame(function() {
|
|
|
updateTranslate();
|
|
|
});
|
|
|
};
|
|
|
var setTranslate = function(element, x) {
|
|
|
if (element) {
|
|
|
element.style.webkitTransform = 'translate(' + x + 'px,0)';
|
|
|
}
|
|
|
};
|
|
|
|
|
|
window.addEventListener($.EVENT_START, function(event) {
|
|
|
if (cell) {
|
|
|
toggleActive(false);
|
|
|
}
|
|
|
cell = a = false;
|
|
|
isMoved = isOpened = openedActions = false;
|
|
|
var target = event.target;
|
|
|
var isDisabled = false;
|
|
|
for (; target && target !== document; target = target.parentNode) {
|
|
|
if (target.classList) {
|
|
|
var classList = target.classList;
|
|
|
if ((target.tagName === 'INPUT' && target.type !== 'radio' && target.type !== 'checkbox') || target.tagName === 'BUTTON' || classList.contains(CLASS_TOGGLE) || classList.contains(CLASS_BTN) || classList.contains(CLASS_DISABLED)) {
|
|
|
isDisabled = true;
|
|
|
}
|
|
|
if (classList.contains(CLASS_COLLAPSE_CONTENT)) { //collapse content
|
|
|
break;
|
|
|
}
|
|
|
if (classList.contains(CLASS_TABLE_VIEW_CELL)) {
|
|
|
cell = target;
|
|
|
//TODO swipe to delete close
|
|
|
var selected = cell.parentNode.querySelector(SELECTOR_SELECTED);
|
|
|
if (!cell.parentNode.classList.contains(CLASS_RADIO_VIEW) && selected && selected !== cell) {
|
|
|
$.swipeoutClose(selected);
|
|
|
cell = isDisabled = false;
|
|
|
return;
|
|
|
}
|
|
|
if (!cell.parentNode.classList.contains(CLASS_GRID_VIEW)) {
|
|
|
var link = cell.querySelector('a');
|
|
|
if (link && link.parentNode === cell) { //li>a
|
|
|
a = link;
|
|
|
}
|
|
|
}
|
|
|
var handle = cell.querySelector(SELECTOR_SLIDER_HANDLE);
|
|
|
if (handle) {
|
|
|
toggleEvents(cell);
|
|
|
event.stopPropagation();
|
|
|
}
|
|
|
if (!isDisabled) {
|
|
|
if (handle) {
|
|
|
if (timer) {
|
|
|
timer.cancel();
|
|
|
}
|
|
|
timer = $.later(function() {
|
|
|
toggleActive(true);
|
|
|
}, 100);
|
|
|
} else {
|
|
|
toggleActive(true);
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
window.addEventListener($.EVENT_MOVE, function(event) {
|
|
|
toggleActive(false);
|
|
|
});
|
|
|
|
|
|
var handleEvent = {
|
|
|
handleEvent: function(event) {
|
|
|
switch (event.type) {
|
|
|
case 'drag':
|
|
|
this.drag(event);
|
|
|
break;
|
|
|
case 'dragend':
|
|
|
this.dragend(event);
|
|
|
break;
|
|
|
case 'flick':
|
|
|
this.flick(event);
|
|
|
break;
|
|
|
case 'swiperight':
|
|
|
this.swiperight(event);
|
|
|
break;
|
|
|
case 'swipeleft':
|
|
|
this.swipeleft(event);
|
|
|
break;
|
|
|
}
|
|
|
},
|
|
|
drag: function(event) {
|
|
|
if (!cell) {
|
|
|
return;
|
|
|
}
|
|
|
if (!isMoved) { //init
|
|
|
sliderHandle = sliderActionLeft = sliderActionRight = buttonsLeft = buttonsRight = sliderDirection = sliderRequestAnimationFrame = false;
|
|
|
sliderHandle = cell.querySelector(SELECTOR_SLIDER_HANDLE);
|
|
|
if (sliderHandle) {
|
|
|
sliderActionLeft = cell.querySelector(SELECTOR_SLIDER_LEFT);
|
|
|
sliderActionRight = cell.querySelector(SELECTOR_SLIDER_RIGHT);
|
|
|
if (sliderActionLeft) {
|
|
|
sliderActionLeftWidth = sliderActionLeft.offsetWidth;
|
|
|
buttonsLeft = sliderActionLeft.querySelectorAll(SELECTOR_BUTTON);
|
|
|
}
|
|
|
if (sliderActionRight) {
|
|
|
sliderActionRightWidth = sliderActionRight.offsetWidth;
|
|
|
buttonsRight = sliderActionRight.querySelectorAll(SELECTOR_BUTTON);
|
|
|
}
|
|
|
cell.classList.remove(CLASS_TRANSITIONING);
|
|
|
isOpened = cell.classList.contains(CLASS_SELECTED);
|
|
|
if (isOpened) {
|
|
|
openedActions = cell.querySelector(SELECTOR_SLIDER_LEFT + SELECTOR_SELECTED) ? 'left' : 'right';
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
var detail = event.detail;
|
|
|
var direction = detail.direction;
|
|
|
var angle = detail.angle;
|
|
|
if (direction === 'left' && (angle > 150 || angle < -150)) {
|
|
|
if (buttonsRight || (buttonsLeft && isOpened)) { //存在右侧按钮或存在左侧按钮且是已打开状态
|
|
|
isMoved = true;
|
|
|
}
|
|
|
} else if (direction === 'right' && (angle > -30 && angle < 30)) {
|
|
|
if (buttonsLeft || (buttonsRight && isOpened)) { //存在左侧按钮或存在右侧按钮且是已打开状态
|
|
|
isMoved = true;
|
|
|
}
|
|
|
}
|
|
|
if (isMoved) {
|
|
|
event.stopPropagation();
|
|
|
event.detail.gesture.preventDefault();
|
|
|
var translate = event.detail.deltaX;
|
|
|
if (isOpened) {
|
|
|
if (openedActions === 'right') {
|
|
|
translate = translate - sliderActionRightWidth;
|
|
|
} else {
|
|
|
translate = translate + sliderActionLeftWidth;
|
|
|
}
|
|
|
}
|
|
|
if ((translate > 0 && !buttonsLeft) || (translate < 0 && !buttonsRight)) {
|
|
|
if (!isOpened) {
|
|
|
return;
|
|
|
}
|
|
|
translate = 0;
|
|
|
}
|
|
|
if (translate < 0) {
|
|
|
sliderDirection = 'toLeft';
|
|
|
} else if (translate > 0) {
|
|
|
sliderDirection = 'toRight';
|
|
|
} else {
|
|
|
if (!sliderDirection) {
|
|
|
sliderDirection = 'toLeft';
|
|
|
}
|
|
|
}
|
|
|
if (!sliderRequestAnimationFrame) {
|
|
|
updateTranslate();
|
|
|
}
|
|
|
translateX = translate;
|
|
|
}
|
|
|
},
|
|
|
flick: function(event) {
|
|
|
if (isMoved) {
|
|
|
event.stopPropagation();
|
|
|
}
|
|
|
},
|
|
|
swipeleft: function(event) {
|
|
|
if (isMoved) {
|
|
|
event.stopPropagation();
|
|
|
}
|
|
|
},
|
|
|
swiperight: function(event) {
|
|
|
if (isMoved) {
|
|
|
event.stopPropagation();
|
|
|
}
|
|
|
},
|
|
|
dragend: function(event) {
|
|
|
if (!isMoved) {
|
|
|
return;
|
|
|
}
|
|
|
event.stopPropagation();
|
|
|
if (sliderRequestAnimationFrame) {
|
|
|
cancelAnimationFrame(sliderRequestAnimationFrame);
|
|
|
sliderRequestAnimationFrame = null;
|
|
|
}
|
|
|
var detail = event.detail;
|
|
|
isMoved = false;
|
|
|
var action = 'close';
|
|
|
var actionsWidth = sliderDirection === 'toLeft' ? sliderActionRightWidth : sliderActionLeftWidth;
|
|
|
var isToggle = detail.swipe || (Math.abs(translateX) > actionsWidth / 2);
|
|
|
if (isToggle) {
|
|
|
if (!isOpened) {
|
|
|
action = 'open';
|
|
|
} else if (detail.direction === 'left' && openedActions === 'right') {
|
|
|
action = 'open';
|
|
|
} else if (detail.direction === 'right' && openedActions === 'left') {
|
|
|
action = 'open';
|
|
|
}
|
|
|
|
|
|
}
|
|
|
cell.classList.add(CLASS_TRANSITIONING);
|
|
|
var buttons;
|
|
|
if (action === 'open') {
|
|
|
var newTranslate = sliderDirection === 'toLeft' ? -actionsWidth : actionsWidth;
|
|
|
setTranslate(sliderHandle, newTranslate);
|
|
|
buttons = sliderDirection === 'toLeft' ? buttonsRight : buttonsLeft;
|
|
|
if (typeof buttons !== 'undefined') {
|
|
|
var button = null;
|
|
|
for (var i = 0; i < buttons.length; i++) {
|
|
|
button = buttons[i];
|
|
|
setTranslate(button, newTranslate);
|
|
|
}
|
|
|
button.parentNode.classList.add(CLASS_SELECTED);
|
|
|
cell.classList.add(CLASS_SELECTED);
|
|
|
if (!isOpened) {
|
|
|
$.trigger(cell, sliderDirection === 'toLeft' ? 'slideleft' : 'slideright');
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
setTranslate(sliderHandle, 0);
|
|
|
sliderActionLeft && sliderActionLeft.classList.remove(CLASS_SELECTED);
|
|
|
sliderActionRight && sliderActionRight.classList.remove(CLASS_SELECTED);
|
|
|
cell.classList.remove(CLASS_SELECTED);
|
|
|
}
|
|
|
var buttonOffset;
|
|
|
if (buttonsLeft && buttonsLeft.length > 0 && buttonsLeft !== buttons) {
|
|
|
for (var i = 0, len = buttonsLeft.length; i < len; i++) {
|
|
|
var buttonLeft = buttonsLeft[i];
|
|
|
buttonOffset = buttonLeft._buttonOffset;
|
|
|
if (typeof buttonOffset === 'undefined') {
|
|
|
buttonLeft._buttonOffset = sliderActionLeftWidth - buttonLeft.offsetLeft - buttonLeft.offsetWidth;
|
|
|
}
|
|
|
setTranslate(buttonLeft, buttonOffset);
|
|
|
}
|
|
|
}
|
|
|
if (buttonsRight && buttonsRight.length > 0 && buttonsRight !== buttons) {
|
|
|
for (var i = 0, len = buttonsRight.length; i < len; i++) {
|
|
|
var buttonRight = buttonsRight[i];
|
|
|
buttonOffset = buttonRight._buttonOffset;
|
|
|
if (typeof buttonOffset === 'undefined') {
|
|
|
buttonRight._buttonOffset = buttonRight.offsetLeft;
|
|
|
}
|
|
|
setTranslate(buttonRight, -buttonOffset);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
function toggleEvents(element, isRemove) {
|
|
|
var method = !!isRemove ? 'removeEventListener' : 'addEventListener';
|
|
|
element[method]('drag', handleEvent);
|
|
|
element[method]('dragend', handleEvent);
|
|
|
element[method]('swiperight', handleEvent);
|
|
|
element[method]('swipeleft', handleEvent);
|
|
|
element[method]('flick', handleEvent);
|
|
|
};
|
|
|
/**
|
|
|
* 打开滑动菜单
|
|
|
* @param {Object} el
|
|
|
* @param {Object} direction
|
|
|
*/
|
|
|
$.swipeoutOpen = function(el, direction) {
|
|
|
if (!el) return;
|
|
|
var classList = el.classList;
|
|
|
if (classList.contains(CLASS_SELECTED)) return;
|
|
|
if (!direction) {
|
|
|
if (el.querySelector(SELECTOR_SLIDER_RIGHT)) {
|
|
|
direction = 'right';
|
|
|
} else {
|
|
|
direction = 'left';
|
|
|
}
|
|
|
}
|
|
|
var swipeoutAction = el.querySelector($.classSelector(".slider-" + direction));
|
|
|
if (!swipeoutAction) return;
|
|
|
swipeoutAction.classList.add(CLASS_SELECTED);
|
|
|
classList.add(CLASS_SELECTED);
|
|
|
classList.remove(CLASS_TRANSITIONING);
|
|
|
var buttons = swipeoutAction.querySelectorAll(SELECTOR_BUTTON);
|
|
|
var swipeoutWidth = swipeoutAction.offsetWidth;
|
|
|
var translate = (direction === 'right') ? -swipeoutWidth : swipeoutWidth;
|
|
|
var length = buttons.length;
|
|
|
var button;
|
|
|
for (var i = 0; i < length; i++) {
|
|
|
button = buttons[i];
|
|
|
if (direction === 'right') {
|
|
|
setTranslate(button, -button.offsetLeft);
|
|
|
} else {
|
|
|
setTranslate(button, (swipeoutWidth - button.offsetWidth - button.offsetLeft));
|
|
|
}
|
|
|
}
|
|
|
classList.add(CLASS_TRANSITIONING);
|
|
|
for (var i = 0; i < length; i++) {
|
|
|
setTranslate(buttons[i], translate);
|
|
|
}
|
|
|
setTranslate(el.querySelector(SELECTOR_SLIDER_HANDLE), translate);
|
|
|
};
|
|
|
/**
|
|
|
* 关闭滑动菜单
|
|
|
* @param {Object} el
|
|
|
*/
|
|
|
$.swipeoutClose = function(el) {
|
|
|
if (!el) return;
|
|
|
var classList = el.classList;
|
|
|
if (!classList.contains(CLASS_SELECTED)) return;
|
|
|
var direction = el.querySelector(SELECTOR_SLIDER_RIGHT + SELECTOR_SELECTED) ? 'right' : 'left';
|
|
|
var swipeoutAction = el.querySelector($.classSelector(".slider-" + direction));
|
|
|
if (!swipeoutAction) return;
|
|
|
swipeoutAction.classList.remove(CLASS_SELECTED);
|
|
|
classList.remove(CLASS_SELECTED);
|
|
|
classList.add(CLASS_TRANSITIONING);
|
|
|
var buttons = swipeoutAction.querySelectorAll(SELECTOR_BUTTON);
|
|
|
var swipeoutWidth = swipeoutAction.offsetWidth;
|
|
|
var length = buttons.length;
|
|
|
var button;
|
|
|
setTranslate(el.querySelector(SELECTOR_SLIDER_HANDLE), 0);
|
|
|
for (var i = 0; i < length; i++) {
|
|
|
button = buttons[i];
|
|
|
if (direction === 'right') {
|
|
|
setTranslate(button, (-button.offsetLeft));
|
|
|
} else {
|
|
|
setTranslate(button, (swipeoutWidth - button.offsetWidth - button.offsetLeft));
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
window.addEventListener($.EVENT_END, function(event) { //使用touchend来取消高亮,避免一次点击既不触发tap,doubletap,longtap的事件
|
|
|
if (!cell) {
|
|
|
return;
|
|
|
}
|
|
|
toggleActive(false);
|
|
|
sliderHandle && toggleEvents(cell, true);
|
|
|
});
|
|
|
window.addEventListener($.EVENT_CANCEL, function(event) { //使用touchcancel来取消高亮,避免一次点击既不触发tap,doubletap,longtap的事件
|
|
|
if (!cell) {
|
|
|
return;
|
|
|
}
|
|
|
toggleActive(false);
|
|
|
sliderHandle && toggleEvents(cell, true);
|
|
|
});
|
|
|
var radioOrCheckboxClick = function(event) {
|
|
|
var type = event.target && event.target.type || '';
|
|
|
if (type === 'radio' || type === 'checkbox') {
|
|
|
return;
|
|
|
}
|
|
|
var classList = cell.classList;
|
|
|
if (classList.contains('mui-radio')) {
|
|
|
var input = cell.querySelector('input[type=radio]');
|
|
|
if (input) {
|
|
|
// input.click();
|
|
|
if (!input.disabled && !input.readOnly) {
|
|
|
input.checked = !input.checked;
|
|
|
$.trigger(input, 'change');
|
|
|
}
|
|
|
}
|
|
|
} else if (classList.contains('mui-checkbox')) {
|
|
|
var input = cell.querySelector('input[type=checkbox]');
|
|
|
if (input) {
|
|
|
// input.click();
|
|
|
if (!input.disabled && !input.readOnly) {
|
|
|
input.checked = !input.checked;
|
|
|
$.trigger(input, 'change');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
//fixed hashchange(android)
|
|
|
window.addEventListener($.EVENT_CLICK, function(e) {
|
|
|
if (cell && cell.classList.contains('mui-collapse')) {
|
|
|
e.preventDefault();
|
|
|
}
|
|
|
});
|
|
|
window.addEventListener('doubletap', function(event) {
|
|
|
if (cell) {
|
|
|
radioOrCheckboxClick(event);
|
|
|
}
|
|
|
});
|
|
|
var preventDefaultException = /^(INPUT|TEXTAREA|BUTTON|SELECT)$/;
|
|
|
window.addEventListener('tap', function(event) {
|
|
|
if (!cell) {
|
|
|
return;
|
|
|
}
|
|
|
var isExpand = false;
|
|
|
var classList = cell.classList;
|
|
|
var ul = cell.parentNode;
|
|
|
if (ul && ul.classList.contains(CLASS_RADIO_VIEW)) {
|
|
|
if (classList.contains(CLASS_SELECTED)) {
|
|
|
return;
|
|
|
}
|
|
|
var selected = ul.querySelector('li' + SELECTOR_SELECTED);
|
|
|
if (selected) {
|
|
|
selected.classList.remove(CLASS_SELECTED);
|
|
|
}
|
|
|
classList.add(CLASS_SELECTED);
|
|
|
$.trigger(cell, 'selected', {
|
|
|
el: cell
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
if (classList.contains('mui-collapse') && !cell.parentNode.classList.contains('mui-unfold')) {
|
|
|
if (!preventDefaultException.test(event.target.tagName)) {
|
|
|
event.detail.gesture.preventDefault();
|
|
|
}
|
|
|
|
|
|
if (!classList.contains(CLASS_ACTIVE)) { //展开时,需要收缩其他同类
|
|
|
var collapse = cell.parentNode.querySelector('.mui-collapse.mui-active');
|
|
|
if (collapse) {
|
|
|
collapse.classList.remove(CLASS_ACTIVE);
|
|
|
}
|
|
|
isExpand = true;
|
|
|
}
|
|
|
classList.toggle(CLASS_ACTIVE);
|
|
|
if (isExpand) {
|
|
|
//触发展开事件
|
|
|
$.trigger(cell, 'expand');
|
|
|
|
|
|
//scroll
|
|
|
//暂不滚动
|
|
|
// var offsetTop = $.offset(cell).top;
|
|
|
// var scrollTop = document.body.scrollTop;
|
|
|
// var height = window.innerHeight;
|
|
|
// var offsetHeight = cell.offsetHeight;
|
|
|
// var cellHeight = (offsetTop - scrollTop + offsetHeight);
|
|
|
// if (offsetHeight > height) {
|
|
|
// $.scrollTo(offsetTop, 300);
|
|
|
// } else if (cellHeight > height) {
|
|
|
// $.scrollTo(cellHeight - height + scrollTop, 300);
|
|
|
// }
|
|
|
}
|
|
|
} else {
|
|
|
radioOrCheckboxClick(event);
|
|
|
}
|
|
|
});
|
|
|
})(mui, window, document);
|
|
|
(function($, window) {
|
|
|
/**
|
|
|
* 警告消息框
|
|
|
*/
|
|
|
$.alert = function(message, title, btnValue, callback) {
|
|
|
if ($.os.plus) {
|
|
|
if (typeof message === 'undefined') {
|
|
|
return;
|
|
|
} else {
|
|
|
if (typeof title === 'function') {
|
|
|
callback = title;
|
|
|
title = null;
|
|
|
btnValue = '确定';
|
|
|
} else if (typeof btnValue === 'function') {
|
|
|
callback = btnValue;
|
|
|
btnValue = null;
|
|
|
}
|
|
|
$.plusReady(function() {
|
|
|
plus.nativeUI.alert(message, callback, title, btnValue);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
//TODO H5版本
|
|
|
window.alert(message);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
})(mui, window);
|
|
|
(function($, window) {
|
|
|
/**
|
|
|
* 确认消息框
|
|
|
*/
|
|
|
$.confirm = function(message, title, btnArray, callback) {
|
|
|
if ($.os.plus) {
|
|
|
if (typeof message === 'undefined') {
|
|
|
return;
|
|
|
} else {
|
|
|
if (typeof title === 'function') {
|
|
|
callback = title;
|
|
|
title = null;
|
|
|
btnArray = null;
|
|
|
} else if (typeof btnArray === 'function') {
|
|
|
callback = btnArray;
|
|
|
btnArray = null;
|
|
|
}
|
|
|
$.plusReady(function() {
|
|
|
plus.nativeUI.confirm(message, callback, title, btnArray);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
//H5版本,0为确认,1为取消
|
|
|
if (window.confirm(message)) {
|
|
|
callback({
|
|
|
index: 0
|
|
|
});
|
|
|
} else {
|
|
|
callback({
|
|
|
index: 1
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
})(mui, window);
|
|
|
(function($, window) {
|
|
|
/**
|
|
|
* 输入对话框
|
|
|
*/
|
|
|
$.prompt = function(text, defaultText, title, btnArray, callback) {
|
|
|
if ($.os.plus) {
|
|
|
if (typeof message === 'undefined') {
|
|
|
return;
|
|
|
} else {
|
|
|
|
|
|
if (typeof defaultText === 'function') {
|
|
|
callback = defaultText;
|
|
|
defaultText = null;
|
|
|
title = null;
|
|
|
btnArray = null;
|
|
|
} else if (typeof title === 'function') {
|
|
|
callback = title;
|
|
|
title = null;
|
|
|
btnArray = null;
|
|
|
} else if (typeof btnArray === 'function') {
|
|
|
callback = btnArray;
|
|
|
btnArray = null;
|
|
|
}
|
|
|
$.plusReady(function() {
|
|
|
plus.nativeUI.prompt(text, callback, title, defaultText, btnArray);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
//H5版本(确认index为0,取消index为1)
|
|
|
var result = promptGener(text);
|
|
|
if (result) {
|
|
|
callback({
|
|
|
index: 0,
|
|
|
value: result
|
|
|
});
|
|
|
} else {
|
|
|
callback({
|
|
|
index: 1,
|
|
|
value: ''
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
})(mui, window);
|
|
|
(function($, window) {
|
|
|
var CLASS_ACTIVE = 'mui-active';
|
|
|
/**
|
|
|
* 自动消失提示框
|
|
|
*/
|
|
|
$.toast = function(message,options) {
|
|
|
var durations = {
|
|
|
'long': 3500,
|
|
|
'short': 2000
|
|
|
};
|
|
|
|
|
|
//计算显示时间
|
|
|
options = $.extend({
|
|
|
duration: 'short'
|
|
|
}, options || {});
|
|
|
|
|
|
|
|
|
if ($.os.plus && options.type !== 'div') {
|
|
|
//默认显示在底部;
|
|
|
$.plusReady(function() {
|
|
|
plus.nativeUI.toast(message, {
|
|
|
verticalAlign: 'bottom',
|
|
|
duration:options.duration
|
|
|
});
|
|
|
});
|
|
|
} else {
|
|
|
if (typeof options.duration === 'number') {
|
|
|
duration = options.duration>0 ? options.duration:durations['short'];
|
|
|
} else {
|
|
|
duration = durations[options.duration];
|
|
|
}
|
|
|
if (!duration) {
|
|
|
duration = durations['short'];
|
|
|
}
|
|
|
var toast = document.createElement('div');
|
|
|
toast.classList.add('mui-toast-container');
|
|
|
toast.innerHTML = '<div class="' + 'mui-toast-message' + '">' + message + '</div>';
|
|
|
toast.addEventListener('webkitTransitionEnd', function() {
|
|
|
if (!toast.classList.contains(CLASS_ACTIVE)) {
|
|
|
toast.parentNode.removeChild(toast);
|
|
|
toast = null;
|
|
|
}
|
|
|
});
|
|
|
//点击则自动消失
|
|
|
toast.addEventListener('click', function() {
|
|
|
toast.parentNode.removeChild(toast);
|
|
|
toast = null;
|
|
|
});
|
|
|
document.body.appendChild(toast);
|
|
|
toast.offsetHeight;
|
|
|
toast.classList.add(CLASS_ACTIVE);
|
|
|
setTimeout(function() {
|
|
|
toast && toast.classList.remove(CLASS_ACTIVE);
|
|
|
}, duration);
|
|
|
|
|
|
return {
|
|
|
isVisible: function() {return !!toast;}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
})(mui, window);
|
|
|
/**
|
|
|
* Popup(alert,confirm,prompt)
|
|
|
* @param {Object} $
|
|
|
* @param {Object} window
|
|
|
* @param {Object} document
|
|
|
*/
|
|
|
(function($, window, document) {
|
|
|
var CLASS_POPUP = 'mui-popup';
|
|
|
var CLASS_POPUP_BACKDROP = 'mui-popup-backdrop';
|
|
|
var CLASS_POPUP_IN = 'mui-popup-in';
|
|
|
var CLASS_POPUP_OUT = 'mui-popup-out';
|
|
|
var CLASS_POPUP_INNER = 'mui-popup-inner';
|
|
|
var CLASS_POPUP_TITLE = 'mui-popup-title';
|
|
|
var CLASS_POPUP_TEXT = 'mui-popup-text';
|
|
|
var CLASS_POPUP_INPUT = 'mui-popup-input';
|
|
|
var CLASS_POPUP_BUTTONS = 'mui-popup-buttons';
|
|
|
var CLASS_POPUP_BUTTON = 'mui-popup-button';
|
|
|
var CLASS_POPUP_BUTTON_BOLD = 'mui-popup-button-bold';
|
|
|
var CLASS_POPUP_BACKDROP = 'mui-popup-backdrop';
|
|
|
var CLASS_ACTIVE = 'mui-active';
|
|
|
|
|
|
var popupStack = [];
|
|
|
var backdrop = (function() {
|
|
|
var element = document.createElement('div');
|
|
|
element.classList.add(CLASS_POPUP_BACKDROP);
|
|
|
element.addEventListener($.EVENT_MOVE, $.preventDefault);
|
|
|
element.addEventListener('webkitTransitionEnd', function() {
|
|
|
if (!this.classList.contains(CLASS_ACTIVE)) {
|
|
|
element.parentNode && element.parentNode.removeChild(element);
|
|
|
}
|
|
|
});
|
|
|
return element;
|
|
|
}());
|
|
|
|
|
|
var createInput = function(placeholder) {
|
|
|
return '<div class="' + CLASS_POPUP_INPUT + '"><input type="text" autofocus placeholder="' + (placeholder || '') + '"/></div>';
|
|
|
};
|
|
|
var createInner = function(message, title, extra) {
|
|
|
return '<div class="' + CLASS_POPUP_INNER + '"><div class="' + CLASS_POPUP_TITLE + '">' + title + '</div><div class="' + CLASS_POPUP_TEXT + '">' + message.replace(/\r\n/g, "<br/>").replace(/\n/g, "<br/>") + '</div>' + (extra || '') + '</div>';
|
|
|
};
|
|
|
var createButtons = function(btnArray) {
|
|
|
var length = btnArray.length;
|
|
|
var btns = [];
|
|
|
for (var i = 0; i < length; i++) {
|
|
|
btns.push('<span class="' + CLASS_POPUP_BUTTON + (i === length - 1 ? (' ' + CLASS_POPUP_BUTTON_BOLD) : '') + '">' + btnArray[i] + '</span>');
|
|
|
}
|
|
|
return '<div class="' + CLASS_POPUP_BUTTONS + '">' + btns.join('') + '</div>';
|
|
|
};
|
|
|
|
|
|
var createPopup = function(html, callback) {
|
|
|
var popupElement = document.createElement('div');
|
|
|
popupElement.className = CLASS_POPUP;
|
|
|
popupElement.innerHTML = html;
|
|
|
var removePopupElement = function() {
|
|
|
popupElement.parentNode && popupElement.parentNode.removeChild(popupElement);
|
|
|
popupElement = null;
|
|
|
};
|
|
|
popupElement.addEventListener($.EVENT_MOVE, $.preventDefault);
|
|
|
popupElement.addEventListener('webkitTransitionEnd', function(e) {
|
|
|
if (popupElement && e.target === popupElement && popupElement.classList.contains(CLASS_POPUP_OUT)) {
|
|
|
removePopupElement();
|
|
|
}
|
|
|
});
|
|
|
popupElement.style.display = 'block';
|
|
|
document.body.appendChild(popupElement);
|
|
|
popupElement.offsetHeight;
|
|
|
popupElement.classList.add(CLASS_POPUP_IN);
|
|
|
|
|
|
if (!backdrop.classList.contains(CLASS_ACTIVE)) {
|
|
|
backdrop.style.display = 'block';
|
|
|
document.body.appendChild(backdrop);
|
|
|
backdrop.offsetHeight;
|
|
|
backdrop.classList.add(CLASS_ACTIVE);
|
|
|
}
|
|
|
var btns = $.qsa('.' + CLASS_POPUP_BUTTON, popupElement);
|
|
|
var input = popupElement.querySelector('.' + CLASS_POPUP_INPUT + ' input');
|
|
|
var popup = {
|
|
|
element: popupElement,
|
|
|
close: function(index, animate) {
|
|
|
if (popupElement) {
|
|
|
var result = callback && callback({
|
|
|
index: index || 0,
|
|
|
value: input && input.value || ''
|
|
|
});
|
|
|
if (result === false) { //返回false则不关闭当前popup
|
|
|
return;
|
|
|
}
|
|
|
if (animate !== false) {
|
|
|
popupElement.classList.remove(CLASS_POPUP_IN);
|
|
|
popupElement.classList.add(CLASS_POPUP_OUT);
|
|
|
} else {
|
|
|
removePopupElement();
|
|
|
}
|
|
|
popupStack.pop();
|
|
|
//如果还有其他popup,则不remove backdrop
|
|
|
if (popupStack.length) {
|
|
|
popupStack[popupStack.length - 1]['show'](animate);
|
|
|
} else {
|
|
|
backdrop.classList.remove(CLASS_ACTIVE);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
var handleEvent = function(e) {
|
|
|
popup.close(btns.indexOf(e.target));
|
|
|
};
|
|
|
$(popupElement).on('tap', '.' + CLASS_POPUP_BUTTON, handleEvent);
|
|
|
if (popupStack.length) {
|
|
|
popupStack[popupStack.length - 1]['hide']();
|
|
|
}
|
|
|
popupStack.push({
|
|
|
close: popup.close,
|
|
|
show: function(animate) {
|
|
|
popupElement.style.display = 'block';
|
|
|
popupElement.offsetHeight;
|
|
|
popupElement.classList.add(CLASS_POPUP_IN);
|
|
|
},
|
|
|
hide: function() {
|
|
|
popupElement.style.display = 'none';
|
|
|
popupElement.classList.remove(CLASS_POPUP_IN);
|
|
|
}
|
|
|
});
|
|
|
return popup;
|
|
|
};
|
|
|
var createAlert = function(message, title, btnValue, callback, type) {
|
|
|
if (typeof message === 'undefined') {
|
|
|
return;
|
|
|
} else {
|
|
|
if (typeof title === 'function') {
|
|
|
callback = title;
|
|
|
type = btnValue;
|
|
|
title = null;
|
|
|
btnValue = null;
|
|
|
} else if (typeof btnValue === 'function') {
|
|
|
type = callback;
|
|
|
callback = btnValue;
|
|
|
btnValue = null;
|
|
|
}
|
|
|
}
|
|
|
if (!$.os.plus || type === 'div') {
|
|
|
return createPopup(createInner(message, title || '提示') + createButtons([btnValue || '确定']), callback);
|
|
|
}
|
|
|
return plus.nativeUI.alert(message, callback, title || '提示', btnValue || '确定');
|
|
|
};
|
|
|
var createConfirm = function(message, title, btnArray, callback, type) {
|
|
|
if (typeof message === 'undefined') {
|
|
|
return;
|
|
|
} else {
|
|
|
if (typeof title === 'function') {
|
|
|
callback = title;
|
|
|
type = btnArray;
|
|
|
title = null;
|
|
|
btnArray = null;
|
|
|
} else if (typeof btnArray === 'function') {
|
|
|
type = callback;
|
|
|
callback = btnArray;
|
|
|
btnArray = null;
|
|
|
}
|
|
|
}
|
|
|
if (!$.os.plus || type === 'div') {
|
|
|
return createPopup(createInner(message, title || '提示') + createButtons(btnArray || ['取消', '确认']), callback);
|
|
|
}
|
|
|
return plus.nativeUI.confirm(message, callback, title, btnArray || ['取消', '确认']);
|
|
|
};
|
|
|
var createPrompt = function(message, placeholder, title, btnArray, callback, type) {
|
|
|
if (typeof message === 'undefined') {
|
|
|
return;
|
|
|
} else {
|
|
|
if (typeof placeholder === 'function') {
|
|
|
callback = placeholder;
|
|
|
type = title;
|
|
|
placeholder = null;
|
|
|
title = null;
|
|
|
btnArray = null;
|
|
|
} else if (typeof title === 'function') {
|
|
|
callback = title;
|
|
|
type = btnArray;
|
|
|
title = null;
|
|
|
btnArray = null;
|
|
|
} else if (typeof btnArray === 'function') {
|
|
|
type = callback;
|
|
|
callback = btnArray;
|
|
|
btnArray = null;
|
|
|
}
|
|
|
}
|
|
|
if (!$.os.plus || type === 'div') {
|
|
|
return createPopup(createInner(message, title || '提示', createInput(placeholder)) + createButtons(btnArray || ['取消', '确认']), callback);
|
|
|
}
|
|
|
return plus.nativeUI.prompt(message, callback, title || '提示', placeholder, btnArray || ['取消', '确认']);
|
|
|
};
|
|
|
var closePopup = function() {
|
|
|
if (popupStack.length) {
|
|
|
popupStack[popupStack.length - 1]['close']();
|
|
|
return true;
|
|
|
} else {
|
|
|
return false;
|
|
|
}
|
|
|
};
|
|
|
var closePopups = function() {
|
|
|
while (popupStack.length) {
|
|
|
popupStack[popupStack.length - 1]['close']();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
$.closePopup = closePopup;
|
|
|
$.closePopups = closePopups;
|
|
|
$.alert = createAlert;
|
|
|
$.confirm = createConfirm;
|
|
|
$.prompt = createPrompt;
|
|
|
})(mui, window, document);
|
|
|
(function($, document) {
|
|
|
var CLASS_PROGRESSBAR = 'mui-progressbar';
|
|
|
var CLASS_PROGRESSBAR_IN = 'mui-progressbar-in';
|
|
|
var CLASS_PROGRESSBAR_OUT = 'mui-progressbar-out';
|
|
|
var CLASS_PROGRESSBAR_INFINITE = 'mui-progressbar-infinite';
|
|
|
|
|
|
var SELECTOR_PROGRESSBAR = '.mui-progressbar';
|
|
|
|
|
|
var _findProgressbar = function(container) {
|
|
|
container = $(container || 'body');
|
|
|
if (container.length === 0) return;
|
|
|
container = container[0];
|
|
|
if (container.classList.contains(CLASS_PROGRESSBAR)) {
|
|
|
return container;
|
|
|
}
|
|
|
var progressbars = container.querySelectorAll(SELECTOR_PROGRESSBAR);
|
|
|
if (progressbars) {
|
|
|
for (var i = 0, len = progressbars.length; i < len; i++) {
|
|
|
var progressbar = progressbars[i];
|
|
|
if (progressbar.parentNode === container) {
|
|
|
return progressbar;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
/**
|
|
|
* 创建并显示进度条
|
|
|
* @param {Object} container 可选,默认body,支持selector,DOM Node,mui wrapper
|
|
|
* @param {Object} progress 可选,undefined表示循环,数字表示具体进度
|
|
|
* @param {Object} color 可选,指定颜色样式(目前暂未提供实际样式,可暂时不暴露此参数)
|
|
|
*/
|
|
|
var showProgressbar = function(container, progress, color) {
|
|
|
if (typeof container === 'number') {
|
|
|
color = progress;
|
|
|
progress = container;
|
|
|
container = 'body';
|
|
|
}
|
|
|
container = $(container || 'body');
|
|
|
if (container.length === 0) return;
|
|
|
container = container[0];
|
|
|
var progressbar;
|
|
|
if (container.classList.contains(CLASS_PROGRESSBAR)) {
|
|
|
progressbar = container;
|
|
|
} else {
|
|
|
var progressbars = container.querySelectorAll(SELECTOR_PROGRESSBAR + ':not(.' + CLASS_PROGRESSBAR_OUT + ')');
|
|
|
if (progressbars) {
|
|
|
for (var i = 0, len = progressbars.length; i < len; i++) {
|
|
|
var _progressbar = progressbars[i];
|
|
|
if (_progressbar.parentNode === container) {
|
|
|
progressbar = _progressbar;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (!progressbar) {
|
|
|
progressbar = document.createElement('span');
|
|
|
progressbar.className = CLASS_PROGRESSBAR + ' ' + CLASS_PROGRESSBAR_IN + (typeof progress !== 'undefined' ? '' : (' ' + CLASS_PROGRESSBAR_INFINITE)) + (color ? (' ' + CLASS_PROGRESSBAR + '-' + color) : '');
|
|
|
if (typeof progress !== 'undefined') {
|
|
|
progressbar.innerHTML = '<span></span>';
|
|
|
}
|
|
|
container.appendChild(progressbar);
|
|
|
} else {
|
|
|
progressbar.classList.add(CLASS_PROGRESSBAR_IN);
|
|
|
}
|
|
|
}
|
|
|
if (progress) setProgressbar(container, progress);
|
|
|
return progressbar;
|
|
|
};
|
|
|
/**
|
|
|
* 关闭进度条
|
|
|
* @param {Object} container 可选,默认body,支持selector,DOM Node,mui wrapper
|
|
|
*/
|
|
|
var hideProgressbar = function(container) {
|
|
|
var progressbar = _findProgressbar(container);
|
|
|
if (!progressbar) {
|
|
|
return;
|
|
|
}
|
|
|
var classList = progressbar.classList;
|
|
|
if (!classList.contains(CLASS_PROGRESSBAR_IN) || classList.contains(CLASS_PROGRESSBAR_OUT)) {
|
|
|
return;
|
|
|
}
|
|
|
classList.remove(CLASS_PROGRESSBAR_IN);
|
|
|
classList.add(CLASS_PROGRESSBAR_OUT);
|
|
|
progressbar.addEventListener('webkitAnimationEnd', function() {
|
|
|
progressbar.parentNode && progressbar.parentNode.removeChild(progressbar);
|
|
|
progressbar = null;
|
|
|
});
|
|
|
return;
|
|
|
};
|
|
|
/**
|
|
|
* 设置指定进度条进度
|
|
|
* @param {Object} container 可选,默认body,支持selector,DOM Node,mui wrapper
|
|
|
* @param {Object} progress 可选,默认0 取值范围[0-100]
|
|
|
* @param {Object} speed 进度条动画时间
|
|
|
*/
|
|
|
var setProgressbar = function(container, progress, speed) {
|
|
|
if (typeof container === 'number') {
|
|
|
speed = progress;
|
|
|
progress = container;
|
|
|
container = false;
|
|
|
}
|
|
|
var progressbar = _findProgressbar(container);
|
|
|
if (!progressbar || progressbar.classList.contains(CLASS_PROGRESSBAR_INFINITE)) {
|
|
|
return;
|
|
|
}
|
|
|
if (progress) progress = Math.min(Math.max(progress, 0), 100);
|
|
|
progressbar.offsetHeight;
|
|
|
var span = progressbar.querySelector('span');
|
|
|
if (span) {
|
|
|
var style = span.style;
|
|
|
style.webkitTransform = 'translate3d(' + (-100 + progress) + '%,0,0)';
|
|
|
if (typeof speed !== 'undefined') {
|
|
|
style.webkitTransitionDuration = speed + 'ms';
|
|
|
} else {
|
|
|
style.webkitTransitionDuration = '';
|
|
|
}
|
|
|
}
|
|
|
return progressbar;
|
|
|
};
|
|
|
$.fn.progressbar = function(options) {
|
|
|
var progressbarApis = [];
|
|
|
options = options || {};
|
|
|
this.each(function() {
|
|
|
var self = this;
|
|
|
var progressbarApi = self.mui_plugin_progressbar;
|
|
|
if (!progressbarApi) {
|
|
|
self.mui_plugin_progressbar = progressbarApi = {
|
|
|
options: options,
|
|
|
setOptions: function(options) {
|
|
|
this.options = options;
|
|
|
},
|
|
|
show: function() {
|
|
|
return showProgressbar(self, this.options.progress, this.options.color);
|
|
|
},
|
|
|
setProgress: function(progress) {
|
|
|
return setProgressbar(self, progress);
|
|
|
},
|
|
|
hide: function() {
|
|
|
return hideProgressbar(self);
|
|
|
}
|
|
|
};
|
|
|
} else if (options) {
|
|
|
progressbarApi.setOptions(options);
|
|
|
}
|
|
|
progressbarApis.push(progressbarApi);
|
|
|
});
|
|
|
return progressbarApis.length === 1 ? progressbarApis[0] : progressbarApis;
|
|
|
};
|
|
|
// $.setProgressbar = setProgressbar;
|
|
|
// $.showProgressbar = showProgressbar;
|
|
|
// $.hideProgressbar = hideProgressbar;
|
|
|
})(mui, document);
|
|
|
/**
|
|
|
* Input(TODO resize)
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @param {type} document
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window, document) {
|
|
|
var CLASS_ICON = 'mui-icon';
|
|
|
var CLASS_ICON_CLEAR = 'mui-icon-clear';
|
|
|
var CLASS_ICON_SPEECH = 'mui-icon-speech';
|
|
|
var CLASS_ICON_SEARCH = 'mui-icon-search';
|
|
|
var CLASS_ICON_PASSWORD = 'mui-icon-eye';
|
|
|
var CLASS_INPUT_ROW = 'mui-input-row';
|
|
|
var CLASS_PLACEHOLDER = 'mui-placeholder';
|
|
|
var CLASS_TOOLTIP = 'mui-tooltip';
|
|
|
var CLASS_HIDDEN = 'mui-hidden';
|
|
|
var CLASS_FOCUSIN = 'mui-focusin';
|
|
|
var SELECTOR_ICON_CLOSE = '.' + CLASS_ICON_CLEAR;
|
|
|
var SELECTOR_ICON_SPEECH = '.' + CLASS_ICON_SPEECH;
|
|
|
var SELECTOR_ICON_PASSWORD = '.' + CLASS_ICON_PASSWORD;
|
|
|
var SELECTOR_PLACEHOLDER = '.' + CLASS_PLACEHOLDER;
|
|
|
var SELECTOR_TOOLTIP = '.' + CLASS_TOOLTIP;
|
|
|
|
|
|
var findRow = function(target) {
|
|
|
for (; target && target !== document; target = target.parentNode) {
|
|
|
if (target.classList && target.classList.contains(CLASS_INPUT_ROW)) {
|
|
|
return target;
|
|
|
}
|
|
|
}
|
|
|
return null;
|
|
|
};
|
|
|
var Input = function(element, options) {
|
|
|
this.element = element;
|
|
|
this.options = options || {
|
|
|
actions: 'clear'
|
|
|
};
|
|
|
if (~this.options.actions.indexOf('slider')) { //slider
|
|
|
this.sliderActionClass = CLASS_TOOLTIP + ' ' + CLASS_HIDDEN;
|
|
|
this.sliderActionSelector = SELECTOR_TOOLTIP;
|
|
|
} else { //clear,speech,search
|
|
|
if (~this.options.actions.indexOf('clear')) {
|
|
|
this.clearActionClass = CLASS_ICON + ' ' + CLASS_ICON_CLEAR + ' ' + CLASS_HIDDEN;
|
|
|
this.clearActionSelector = SELECTOR_ICON_CLOSE;
|
|
|
}
|
|
|
if (~this.options.actions.indexOf('speech')) { //only for 5+
|
|
|
this.speechActionClass = CLASS_ICON + ' ' + CLASS_ICON_SPEECH;
|
|
|
this.speechActionSelector = SELECTOR_ICON_SPEECH;
|
|
|
}
|
|
|
if (~this.options.actions.indexOf('search')) {
|
|
|
this.searchActionClass = CLASS_PLACEHOLDER;
|
|
|
this.searchActionSelector = SELECTOR_PLACEHOLDER;
|
|
|
}
|
|
|
if (~this.options.actions.indexOf('password')) {
|
|
|
this.passwordActionClass = CLASS_ICON + ' ' + CLASS_ICON_PASSWORD;
|
|
|
this.passwordActionSelector = SELECTOR_ICON_PASSWORD;
|
|
|
}
|
|
|
}
|
|
|
this.init();
|
|
|
};
|
|
|
Input.prototype.init = function() {
|
|
|
this.initAction();
|
|
|
this.initElementEvent();
|
|
|
};
|
|
|
Input.prototype.initAction = function() {
|
|
|
var self = this;
|
|
|
|
|
|
var row = self.element.parentNode;
|
|
|
if (row) {
|
|
|
if (self.sliderActionClass) {
|
|
|
self.sliderAction = self.createAction(row, self.sliderActionClass, self.sliderActionSelector);
|
|
|
} else {
|
|
|
if (self.searchActionClass) {
|
|
|
self.searchAction = self.createAction(row, self.searchActionClass, self.searchActionSelector);
|
|
|
self.searchAction.addEventListener('tap', function(e) {
|
|
|
$.focus(self.element);
|
|
|
e.stopPropagation();
|
|
|
});
|
|
|
}
|
|
|
if (self.speechActionClass) {
|
|
|
self.speechAction = self.createAction(row, self.speechActionClass, self.speechActionSelector);
|
|
|
self.speechAction.addEventListener('click', $.stopPropagation);
|
|
|
self.speechAction.addEventListener('tap', function(event) {
|
|
|
self.speechActionClick(event);
|
|
|
});
|
|
|
}
|
|
|
if (self.clearActionClass) {
|
|
|
self.clearAction = self.createAction(row, self.clearActionClass, self.clearActionSelector);
|
|
|
self.clearAction.addEventListener('tap', function(event) {
|
|
|
self.clearActionClick(event);
|
|
|
});
|
|
|
}
|
|
|
if (self.passwordActionClass) {
|
|
|
self.passwordAction = self.createAction(row, self.passwordActionClass, self.passwordActionSelector);
|
|
|
self.passwordAction.addEventListener('tap', function(event) {
|
|
|
self.passwordActionClick(event);
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
Input.prototype.createAction = function(row, actionClass, actionSelector) {
|
|
|
var action = row.querySelector(actionSelector);
|
|
|
if (!action) {
|
|
|
var action = document.createElement('span');
|
|
|
action.className = actionClass;
|
|
|
if (actionClass === this.searchActionClass) {
|
|
|
action.innerHTML = '<span class="' + CLASS_ICON + ' ' + CLASS_ICON_SEARCH + '"></span><span>' + this.element.getAttribute('placeholder') + '</span>';
|
|
|
this.element.setAttribute('placeholder', '');
|
|
|
if (this.element.value.trim()) {
|
|
|
row.classList.add('mui-active');
|
|
|
}
|
|
|
}
|
|
|
row.insertBefore(action, this.element.nextSibling);
|
|
|
}
|
|
|
return action;
|
|
|
};
|
|
|
Input.prototype.initElementEvent = function() {
|
|
|
var element = this.element;
|
|
|
|
|
|
if (this.sliderActionClass) {
|
|
|
var tooltip = this.sliderAction;
|
|
|
var timer = null;
|
|
|
var showTip = function() { //每次重新计算是因为控件可能被隐藏,初始化时计算是不正确的
|
|
|
tooltip.classList.remove(CLASS_HIDDEN);
|
|
|
var offsetLeft = element.offsetLeft;
|
|
|
var width = element.offsetWidth - 28;
|
|
|
var tooltipWidth = tooltip.offsetWidth;
|
|
|
var distince = Math.abs(element.max - element.min);
|
|
|
var scaleWidth = (width / distince) * Math.abs(element.value - element.min);
|
|
|
tooltip.style.left = (14 + offsetLeft + scaleWidth - tooltipWidth / 2) + 'px';
|
|
|
tooltip.innerText = element.value;
|
|
|
if (timer) {
|
|
|
clearTimeout(timer);
|
|
|
}
|
|
|
timer = setTimeout(function() {
|
|
|
tooltip.classList.add(CLASS_HIDDEN);
|
|
|
}, 1000);
|
|
|
};
|
|
|
element.addEventListener('input', showTip);
|
|
|
element.addEventListener('tap', showTip);
|
|
|
element.addEventListener($.EVENT_MOVE, function(e) {
|
|
|
e.stopPropagation();
|
|
|
});
|
|
|
} else {
|
|
|
if (this.clearActionClass) {
|
|
|
var action = this.clearAction;
|
|
|
if (!action) {
|
|
|
return;
|
|
|
}
|
|
|
$.each(['keyup', 'change', 'input', 'focus', 'cut', 'paste'], function(index, type) {
|
|
|
(function(type) {
|
|
|
element.addEventListener(type, function() {
|
|
|
action.classList[element.value.trim() ? 'remove' : 'add'](CLASS_HIDDEN);
|
|
|
});
|
|
|
})(type);
|
|
|
});
|
|
|
element.addEventListener('blur', function() {
|
|
|
action.classList.add(CLASS_HIDDEN);
|
|
|
});
|
|
|
}
|
|
|
if (this.searchActionClass) {
|
|
|
element.addEventListener('focus', function() {
|
|
|
element.parentNode.classList.add('mui-active');
|
|
|
});
|
|
|
element.addEventListener('blur', function() {
|
|
|
if (!element.value.trim()) {
|
|
|
element.parentNode.classList.remove('mui-active');
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
Input.prototype.setPlaceholder = function(text) {
|
|
|
if (this.searchActionClass) {
|
|
|
var placeholder = this.element.parentNode.querySelector(SELECTOR_PLACEHOLDER);
|
|
|
placeholder && (placeholder.getElementsByTagName('span')[1].innerText = text);
|
|
|
} else {
|
|
|
this.element.setAttribute('placeholder', text);
|
|
|
}
|
|
|
};
|
|
|
Input.prototype.passwordActionClick = function(event) {
|
|
|
if (this.element.type === 'text') {
|
|
|
this.element.type = 'password';
|
|
|
} else {
|
|
|
this.element.type = 'text';
|
|
|
}
|
|
|
this.passwordAction.classList.toggle('mui-active');
|
|
|
event.preventDefault();
|
|
|
};
|
|
|
Input.prototype.clearActionClick = function(event) {
|
|
|
var self = this;
|
|
|
self.element.value = '';
|
|
|
$.focus(self.element);
|
|
|
self.clearAction.classList.add(CLASS_HIDDEN);
|
|
|
event.preventDefault();
|
|
|
};
|
|
|
Input.prototype.speechActionClick = function(event) {
|
|
|
if (window.plus) {
|
|
|
var self = this;
|
|
|
var oldValue = self.element.value;
|
|
|
self.element.value = '';
|
|
|
document.body.classList.add(CLASS_FOCUSIN);
|
|
|
plus.speech.startRecognize({
|
|
|
engine: 'iFly'
|
|
|
}, function(s) {
|
|
|
self.element.value += s;
|
|
|
$.focus(self.element);
|
|
|
plus.speech.stopRecognize();
|
|
|
$.trigger(self.element, 'recognized', {
|
|
|
value: self.element.value
|
|
|
});
|
|
|
if (oldValue !== self.element.value) {
|
|
|
$.trigger(self.element, 'change');
|
|
|
$.trigger(self.element, 'input');
|
|
|
}
|
|
|
// document.body.classList.remove(CLASS_FOCUSIN);
|
|
|
}, function(e) {
|
|
|
document.body.classList.remove(CLASS_FOCUSIN);
|
|
|
});
|
|
|
} else {
|
|
|
alert('only for 5+');
|
|
|
}
|
|
|
event.preventDefault();
|
|
|
};
|
|
|
$.fn.input = function(options) {
|
|
|
var inputApis = [];
|
|
|
this.each(function() {
|
|
|
var inputApi = null;
|
|
|
var actions = [];
|
|
|
var row = findRow(this.parentNode);
|
|
|
if (this.type === 'range' && row.classList.contains('mui-input-range')) {
|
|
|
actions.push('slider');
|
|
|
} else {
|
|
|
var classList = this.classList;
|
|
|
if (classList.contains('mui-input-clear')) {
|
|
|
actions.push('clear');
|
|
|
}
|
|
|
if (!($.os.android && $.os.stream) && classList.contains('mui-input-speech')) {
|
|
|
actions.push('speech');
|
|
|
}
|
|
|
if (classList.contains('mui-input-password')) {
|
|
|
actions.push('password');
|
|
|
}
|
|
|
if (this.type === 'search' && row.classList.contains('mui-search')) {
|
|
|
actions.push('search');
|
|
|
}
|
|
|
}
|
|
|
var id = this.getAttribute('data-input-' + actions[0]);
|
|
|
if (!id) {
|
|
|
id = ++$.uuid;
|
|
|
inputApi = $.data[id] = new Input(this, {
|
|
|
actions: actions.join(',')
|
|
|
});
|
|
|
for (var i = 0, len = actions.length; i < len; i++) {
|
|
|
this.setAttribute('data-input-' + actions[i], id);
|
|
|
}
|
|
|
} else {
|
|
|
inputApi = $.data[id];
|
|
|
}
|
|
|
inputApis.push(inputApi);
|
|
|
});
|
|
|
return inputApis.length === 1 ? inputApis[0] : inputApis;
|
|
|
};
|
|
|
$.ready(function() {
|
|
|
$('.mui-input-row input').input();
|
|
|
});
|
|
|
})(mui, window, document);
|
|
|
(function($, window) {
|
|
|
var CLASS_ACTIVE = 'mui-active';
|
|
|
var rgbaRegex = /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d*(?:\.\d+)?)\)$/;
|
|
|
var getColor = function(colorStr) {
|
|
|
var matches = colorStr.match(rgbaRegex);
|
|
|
if (matches && matches.length === 5) {
|
|
|
return [
|
|
|
matches[1],
|
|
|
matches[2],
|
|
|
matches[3],
|
|
|
matches[4]
|
|
|
];
|
|
|
}
|
|
|
return [];
|
|
|
};
|
|
|
var Transparent = function(element, options) {
|
|
|
this.element = element;
|
|
|
this.options = $.extend({
|
|
|
top: 0, //距离顶部高度(到达该高度即触发)
|
|
|
offset: 150, //滚动透明距离
|
|
|
duration: 16, //过渡时间
|
|
|
scrollby: window//监听滚动距离容器
|
|
|
}, options || {});
|
|
|
|
|
|
this.scrollByElem = this.options.scrollby || window;
|
|
|
if (!this.scrollByElem) {
|
|
|
throw new Error("监听滚动的元素不存在");
|
|
|
}
|
|
|
this.isNativeScroll = false;
|
|
|
if (this.scrollByElem === window) {
|
|
|
this.isNativeScroll = true;
|
|
|
} else if (!~this.scrollByElem.className.indexOf('mui-scroll-wrapper')) {
|
|
|
this.isNativeScroll = true;
|
|
|
}
|
|
|
|
|
|
this._style = this.element.style;
|
|
|
this._bgColor = this._style.backgroundColor;
|
|
|
var color = getColor(mui.getStyles(this.element, 'backgroundColor'));
|
|
|
if (color.length) {
|
|
|
this._R = color[0];
|
|
|
this._G = color[1];
|
|
|
this._B = color[2];
|
|
|
this._A = parseFloat(color[3]);
|
|
|
this.lastOpacity = this._A;
|
|
|
this._bufferFn = $.buffer(this.handleScroll, this.options.duration, this);
|
|
|
this.initEvent();
|
|
|
} else {
|
|
|
throw new Error("元素背景颜色必须为RGBA");
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Transparent.prototype.initEvent = function() {
|
|
|
this.scrollByElem.addEventListener('scroll', this._bufferFn);
|
|
|
if (this.isNativeScroll) { //原生scroll
|
|
|
this.scrollByElem.addEventListener($.EVENT_MOVE, this._bufferFn);
|
|
|
}
|
|
|
}
|
|
|
Transparent.prototype.handleScroll = function(e) {
|
|
|
var y = window.scrollY;
|
|
|
if (!this.isNativeScroll && e && e.detail) {
|
|
|
y = -e.detail.y;
|
|
|
}
|
|
|
var opacity = (y - this.options.top) / this.options.offset + this._A;
|
|
|
opacity = Math.min(Math.max(this._A, opacity), 1);
|
|
|
this._style.backgroundColor = 'rgba(' + this._R + ',' + this._G + ',' + this._B + ',' + opacity + ')';
|
|
|
if (opacity > this._A) {
|
|
|
this.element.classList.add(CLASS_ACTIVE);
|
|
|
} else {
|
|
|
this.element.classList.remove(CLASS_ACTIVE);
|
|
|
}
|
|
|
if (this.lastOpacity !== opacity) {
|
|
|
$.trigger(this.element, 'alpha', {
|
|
|
alpha: opacity
|
|
|
});
|
|
|
this.lastOpacity = opacity;
|
|
|
}
|
|
|
};
|
|
|
Transparent.prototype.destory = function() {
|
|
|
this.scrollByElem.removeEventListener('scroll', this._bufferFn);
|
|
|
this.scrollByElem.removeEventListener($.EVENT_MOVE, this._bufferFn);
|
|
|
this.element.style.backgroundColor = this._bgColor;
|
|
|
this.element.mui_plugin_transparent = null;
|
|
|
};
|
|
|
$.fn.transparent = function(options) {
|
|
|
options = options || {};
|
|
|
var transparentApis = [];
|
|
|
this.each(function() {
|
|
|
var transparentApi = this.mui_plugin_transparent;
|
|
|
if (!transparentApi) {
|
|
|
var top = this.getAttribute('data-top');
|
|
|
var offset = this.getAttribute('data-offset');
|
|
|
var duration = this.getAttribute('data-duration');
|
|
|
var scrollby = this.getAttribute('data-scrollby');
|
|
|
if (top !== null && typeof options.top === 'undefined') {
|
|
|
options.top = top;
|
|
|
}
|
|
|
if (offset !== null && typeof options.offset === 'undefined') {
|
|
|
options.offset = offset;
|
|
|
}
|
|
|
if (duration !== null && typeof options.duration === 'undefined') {
|
|
|
options.duration = duration;
|
|
|
}
|
|
|
if (scrollby !== null && typeof options.scrollby === 'undefined') {
|
|
|
options.scrollby = document.querySelector(scrollby) || window;
|
|
|
}
|
|
|
transparentApi = this.mui_plugin_transparent = new Transparent(this, options);
|
|
|
}
|
|
|
transparentApis.push(transparentApi);
|
|
|
});
|
|
|
return transparentApis.length === 1 ? transparentApis[0] : transparentApis;
|
|
|
};
|
|
|
$.ready(function() {
|
|
|
$('.mui-bar-transparent').transparent();
|
|
|
});
|
|
|
})(mui, window);
|
|
|
/**
|
|
|
* 数字输入框
|
|
|
* varstion 1.0.1
|
|
|
* by Houfeng
|
|
|
* Houfeng@DCloud.io
|
|
|
*/
|
|
|
|
|
|
(function($) {
|
|
|
|
|
|
var touchSupport = ('ontouchstart' in document);
|
|
|
var tapEventName = touchSupport ? 'tap' : 'click';
|
|
|
var changeEventName = 'change';
|
|
|
var holderClassName = 'mui-numbox';
|
|
|
var plusClassSelector = '.mui-btn-numbox-plus,.mui-numbox-btn-plus';
|
|
|
var minusClassSelector = '.mui-btn-numbox-minus,.mui-numbox-btn-minus';
|
|
|
var inputClassSelector = '.mui-input-numbox,.mui-numbox-input';
|
|
|
|
|
|
var Numbox = $.Numbox = $.Class.extend({
|
|
|
/**
|
|
|
* 构造函数
|
|
|
**/
|
|
|
init: function(holder, options) {
|
|
|
var self = this;
|
|
|
if (!holder) {
|
|
|
throw "构造 numbox 时缺少容器元素";
|
|
|
}
|
|
|
self.holder = holder;
|
|
|
options = options || {};
|
|
|
options.step = parseInt(options.step || 1);
|
|
|
self.options = options;
|
|
|
self.input = $.qsa(inputClassSelector, self.holder)[0];
|
|
|
self.plus = $.qsa(plusClassSelector, self.holder)[0];
|
|
|
self.minus = $.qsa(minusClassSelector, self.holder)[0];
|
|
|
self.checkValue();
|
|
|
self.initEvent();
|
|
|
},
|
|
|
/**
|
|
|
* 初始化事件绑定
|
|
|
**/
|
|
|
initEvent: function() {
|
|
|
var self = this;
|
|
|
self.plus.addEventListener(tapEventName, function(event) {
|
|
|
var val = parseInt(self.input.value) + self.options.step;
|
|
|
self.input.value = val.toString();
|
|
|
$.trigger(self.input, changeEventName, null);
|
|
|
});
|
|
|
self.minus.addEventListener(tapEventName, function(event) {
|
|
|
var val = parseInt(self.input.value) - self.options.step;
|
|
|
self.input.value = val.toString();
|
|
|
$.trigger(self.input, changeEventName, null);
|
|
|
});
|
|
|
self.input.addEventListener(changeEventName, function(event) {
|
|
|
self.checkValue();
|
|
|
var val = parseInt(self.input.value);
|
|
|
//触发顶层容器
|
|
|
$.trigger(self.holder, changeEventName, {
|
|
|
value: val
|
|
|
});
|
|
|
});
|
|
|
},
|
|
|
/**
|
|
|
* 获取当前值
|
|
|
**/
|
|
|
getValue: function() {
|
|
|
var self = this;
|
|
|
return parseInt(self.input.value);
|
|
|
},
|
|
|
/**
|
|
|
* 验证当前值是法合法
|
|
|
**/
|
|
|
checkValue: function() {
|
|
|
var self = this;
|
|
|
var val = self.input.value;
|
|
|
if (val == null || val == '' || isNaN(val)) {
|
|
|
self.input.value = self.options.min || 0;
|
|
|
self.minus.disabled = self.options.min != null;
|
|
|
} else {
|
|
|
var val = parseInt(val);
|
|
|
if (self.options.max != null && !isNaN(self.options.max) && val >= parseInt(self.options.max)) {
|
|
|
val = self.options.max;
|
|
|
self.plus.disabled = true;
|
|
|
} else {
|
|
|
self.plus.disabled = false;
|
|
|
}
|
|
|
if (self.options.min != null && !isNaN(self.options.min) && val <= parseInt(self.options.min)) {
|
|
|
val = self.options.min;
|
|
|
self.minus.disabled = true;
|
|
|
} else {
|
|
|
self.minus.disabled = false;
|
|
|
}
|
|
|
self.input.value = val;
|
|
|
}
|
|
|
},
|
|
|
/**
|
|
|
* 更新选项
|
|
|
**/
|
|
|
setOption: function(name, value) {
|
|
|
var self = this;
|
|
|
self.options[name] = value;
|
|
|
},
|
|
|
/**
|
|
|
* 动态设置新值
|
|
|
**/
|
|
|
setValue: function(value) {
|
|
|
this.input.value = value;
|
|
|
this.checkValue();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
$.fn.numbox = function(options) {
|
|
|
var instanceArray = [];
|
|
|
//遍历选择的元素
|
|
|
this.each(function(i, element) {
|
|
|
if (element.numbox) {
|
|
|
return;
|
|
|
}
|
|
|
if (options) {
|
|
|
element.numbox = new Numbox(element, options);
|
|
|
} else {
|
|
|
var optionsText = element.getAttribute('data-numbox-options');
|
|
|
var options = optionsText ? JSON.parse(optionsText) : {};
|
|
|
options.step = element.getAttribute('data-numbox-step') || options.step;
|
|
|
options.min = element.getAttribute('data-numbox-min') || options.min;
|
|
|
options.max = element.getAttribute('data-numbox-max') || options.max;
|
|
|
element.numbox = new Numbox(element, options);
|
|
|
}
|
|
|
});
|
|
|
return this[0] ? this[0].numbox : null;
|
|
|
}
|
|
|
|
|
|
//自动处理 class='mui-locker' 的 dom
|
|
|
$.ready(function() {
|
|
|
$('.' + holderClassName).numbox();
|
|
|
});
|
|
|
|
|
|
}(mui));
|
|
|
/**
|
|
|
* Button
|
|
|
* @param {type} $
|
|
|
* @param {type} window
|
|
|
* @param {type} document
|
|
|
* @returns {undefined}
|
|
|
*/
|
|
|
(function($, window, document) {
|
|
|
var CLASS_ICON = 'mui-icon';
|
|
|
var CLASS_DISABLED = 'mui-disabled';
|
|
|
|
|
|
var STATE_RESET = 'reset';
|
|
|
var STATE_LOADING = 'loading';
|
|
|
|
|
|
var defaultOptions = {
|
|
|
loadingText: 'Loading...', //文案
|
|
|
loadingIcon: 'mui-spinner' + ' ' + 'mui-spinner-white', //图标,可为空
|
|
|
loadingIconPosition: 'left' //图标所处位置,仅支持left|right
|
|
|
};
|
|
|
|
|
|
var Button = function(element, options) {
|
|
|
this.element = element;
|
|
|
this.options = $.extend({}, defaultOptions, options);
|
|
|
if (!this.options.loadingText) {
|
|
|
this.options.loadingText = defaultOptions.loadingText;
|
|
|
}
|
|
|
if (this.options.loadingIcon === null) {
|
|
|
this.options.loadingIcon = 'mui-spinner';
|
|
|
if ($.getStyles(this.element, 'color') === 'rgb(255, 255, 255)') {
|
|
|
this.options.loadingIcon += ' ' + 'mui-spinner-white';
|
|
|
}
|
|
|
}
|
|
|
this.isInput = this.element.tagName === 'INPUT';
|
|
|
this.resetHTML = this.isInput ? this.element.value : this.element.innerHTML;
|
|
|
this.state = '';
|
|
|
};
|
|
|
Button.prototype.loading = function() {
|
|
|
this.setState(STATE_LOADING);
|
|
|
};
|
|
|
Button.prototype.reset = function() {
|
|
|
this.setState(STATE_RESET);
|
|
|
};
|
|
|
Button.prototype.setState = function(state) {
|
|
|
if (this.state === state) {
|
|
|
return false;
|
|
|
}
|
|
|
this.state = state;
|
|
|
if (state === STATE_RESET) {
|
|
|
this.element.disabled = false;
|
|
|
this.element.classList.remove(CLASS_DISABLED);
|
|
|
this.setHtml(this.resetHTML);
|
|
|
} else if (state === STATE_LOADING) {
|
|
|
this.element.disabled = true;
|
|
|
this.element.classList.add(CLASS_DISABLED);
|
|
|
var html = this.isInput ? this.options.loadingText : ('<span>' + this.options.loadingText + '</span>');
|
|
|
if (this.options.loadingIcon && !this.isInput) {
|
|
|
if (this.options.loadingIconPosition === 'right') {
|
|
|
html += ' <span class="' + this.options.loadingIcon + '"></span>';
|
|
|
} else {
|
|
|
html = '<span class="' + this.options.loadingIcon + '"></span> ' + html;
|
|
|
}
|
|
|
}
|
|
|
this.setHtml(html);
|
|
|
}
|
|
|
};
|
|
|
Button.prototype.setHtml = function(html) {
|
|
|
if (this.isInput) {
|
|
|
this.element.value = html;
|
|
|
} else {
|
|
|
this.element.innerHTML = html;
|
|
|
}
|
|
|
}
|
|
|
$.fn.button = function(state) {
|
|
|
var buttonApis = [];
|
|
|
this.each(function() {
|
|
|
var buttonApi = this.mui_plugin_button;
|
|
|
if (!buttonApi) {
|
|
|
var loadingText = this.getAttribute('data-loading-text');
|
|
|
var loadingIcon = this.getAttribute('data-loading-icon');
|
|
|
var loadingIconPosition = this.getAttribute('data-loading-icon-position');
|
|
|
this.mui_plugin_button = buttonApi = new Button(this, {
|
|
|
loadingText: loadingText,
|
|
|
loadingIcon: loadingIcon,
|
|
|
loadingIconPosition: loadingIconPosition
|
|
|
});
|
|
|
}
|
|
|
if (state === STATE_LOADING || state === STATE_RESET) {
|
|
|
buttonApi.setState(state);
|
|
|
}
|
|
|
buttonApis.push(buttonApi);
|
|
|
});
|
|
|
return buttonApis.length === 1 ? buttonApis[0] : buttonApis;
|
|
|
};
|
|
|
})(mui, window, document); |