1092 lines
36 KiB
JavaScript
1092 lines
36 KiB
JavaScript
var noop = function() {};
|
|
|
|
function SwipeReader(options) {
|
|
if (!options) {
|
|
options = {};
|
|
}
|
|
this.$wrapper = $(options.wrapperSelector);
|
|
this.$scroller = function() {
|
|
return this.$wrapper.find(options.scrollerSelector);
|
|
}.bind(this);
|
|
this.$pager = $(options.pagerSelector);
|
|
this.onCenterClick = options.onCenterClick || noop;
|
|
this.onSwipePrev = options.onSwipePrev || noop;
|
|
this.onSwipeNext = options.onSwipeNext || noop;
|
|
this.onWillSwipeNext = options.onWillSwipeNext || noop;
|
|
this.gap = options.gap || 16;
|
|
this.pager = {
|
|
cur: 1,
|
|
max: 1
|
|
};
|
|
this.enabled = false;
|
|
this.isPreloading = false;
|
|
this.initEvents();
|
|
this.initPager();
|
|
}
|
|
|
|
SwipeReader.prototype = {
|
|
initEvents: function() {
|
|
var self = this;
|
|
var $wrapper = self.$wrapper;
|
|
var $scroller = self.$scroller;
|
|
var isMoving = false;
|
|
var firstTouch;
|
|
var touch = {};
|
|
var startLeft = 0;
|
|
$wrapper.on({
|
|
touchstart: function(event) {
|
|
if (!self.enabled) {
|
|
return;
|
|
}
|
|
var target = event.target || {};
|
|
if (/^(?:a|input|label|i|use|svg)$/i.test(target.tagName) || $(target).parents("a").length) {
|
|
return;
|
|
}
|
|
isMoving = true;
|
|
firstTouch = event.touches[0] || event;
|
|
touch.x1 = firstTouch.pageX;
|
|
touch.y1 = firstTouch.pageY;
|
|
startLeft = $scroller().data("left") || 0;
|
|
},
|
|
touchmove: function(event) {
|
|
if (!isMoving) {
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
firstTouch = event.touches[0] || event;
|
|
touch.x2 = firstTouch.pageX;
|
|
touch.y2 = firstTouch.pageY;
|
|
var scrollLeft = startLeft - (touch.x2 - touch.x1);
|
|
$scroller().css({
|
|
"-webkit-transform": "translateX(" + -scrollLeft + "px)",
|
|
transform: "translateX(" + -scrollLeft + "px)"
|
|
});
|
|
},
|
|
touchend: function() {
|
|
if (!isMoving) {
|
|
return;
|
|
}
|
|
isMoving = false;
|
|
var distanceX = touch.x2 - touch.x1;
|
|
var distanceMin = self.gap;
|
|
if (!touch.x2 || Math.abs(distanceX) < distanceMin) {
|
|
var winWidth = window.innerWidth;
|
|
var range = [ winWidth / 3, winWidth * 2 / 3 ];
|
|
if (touch.x1 <= range[0]) {
|
|
self.turnLeft();
|
|
} else if (touch.x1 >= range[1]) {
|
|
self.turnRight();
|
|
} else {
|
|
self.scrollTo(startLeft);
|
|
self.onCenterClick();
|
|
}
|
|
} else if (distanceX > distanceMin) {
|
|
self.turnLeft();
|
|
} else if (distanceX < distanceMin) {
|
|
self.turnRight();
|
|
} else {
|
|
self.scrollTo(startLeft);
|
|
}
|
|
firstTouch = null;
|
|
touch = {};
|
|
startLeft = 0;
|
|
}
|
|
});
|
|
},
|
|
initPager: function() {
|
|
this.resetPager();
|
|
this.refreshPager();
|
|
},
|
|
resetPager: function() {
|
|
var elScroller = this.$scroller()[0];
|
|
var pager = this.pager;
|
|
var gap = this.gap;
|
|
pager.cur = 1;
|
|
pager.max = Math.round((elScroller.scrollWidth + gap) / (elScroller.clientWidth + gap));
|
|
},
|
|
refreshPager: function() {
|
|
var pager = this.pager;
|
|
this.$pager.html([ pager.cur, pager.max ].join("/"));
|
|
},
|
|
scrollTo: function(x) {
|
|
var $scroller = this.$scroller();
|
|
var left = $scroller.data("left") || 0;
|
|
var step = function() {
|
|
left += (x - left) * .5;
|
|
if (Math.abs(x - left) < 1) {
|
|
$scroller.data("left", x).css({
|
|
"-webkit-transform": "translateX(" + -x + "px)",
|
|
transform: "translateX(" + -x + "px)"
|
|
});
|
|
} else {
|
|
$scroller.css({
|
|
"-webkit-transform": "translateX(" + -left + "px)",
|
|
transform: "translateX(" + -left + "px)"
|
|
});
|
|
if (window.requestAnimationFrame) {
|
|
requestAnimationFrame(step);
|
|
} else {
|
|
setTimeout(step, 17);
|
|
}
|
|
}
|
|
};
|
|
step();
|
|
},
|
|
turnTo: function(current) {
|
|
var pager = this.pager;
|
|
var gap = this.gap;
|
|
var width = this.$scroller().width();
|
|
pager.cur = current;
|
|
this.scrollTo((current - 1) * (width + gap));
|
|
this.refreshPager();
|
|
},
|
|
turnLeft: function() {
|
|
var self = this;
|
|
var pager = self.pager;
|
|
var current = pager.cur - 1;
|
|
if (current < 1) {
|
|
pager.cur = 1;
|
|
self.enabled = false;
|
|
self.onSwipePrev(function() {
|
|
var $scroller = self.$scroller();
|
|
var maxLeft = $scroller[0].scrollWidth - $scroller.width();
|
|
self.enabled = true;
|
|
self.$scroller().data("left", maxLeft).css({
|
|
"-webkit-transform": "translateX(" + -maxLeft + "px)",
|
|
transform: "translateX(" + -maxLeft + "px)"
|
|
});
|
|
self.initPager();
|
|
pager.cur = pager.max;
|
|
self.refreshPager();
|
|
}, function() {
|
|
self.enabled = true;
|
|
});
|
|
} else {
|
|
this.turnTo(current);
|
|
}
|
|
},
|
|
turnRight: function() {
|
|
var self = this;
|
|
var pager = self.pager;
|
|
var current = pager.cur + 1;
|
|
if (current > pager.max) {
|
|
pager.cur = 1;
|
|
self.enabled = false;
|
|
self.onSwipeNext(function() {
|
|
self.enabled = true;
|
|
self.$scroller().css({
|
|
"-webkit-transform": "",
|
|
transform: ""
|
|
});
|
|
self.initPager();
|
|
}, function() {
|
|
self.enabled = true;
|
|
});
|
|
} else {
|
|
self.turnTo(current);
|
|
if (current > pager.max - 3 && !self.isPreloading) {
|
|
self.isPreloading = true;
|
|
self.onWillSwipeNext(function() {
|
|
self.isPreloading = false;
|
|
}, function() {
|
|
self.isPreloading = false;
|
|
});
|
|
}
|
|
}
|
|
},
|
|
enable: function() {
|
|
this.enabled = true;
|
|
this.refresh();
|
|
},
|
|
disable: function() {
|
|
this.enabled = false;
|
|
this.$scroller().css({
|
|
"-webkit-transform": "",
|
|
transform: ""
|
|
});
|
|
},
|
|
refresh: function() {
|
|
this.initPager();
|
|
},
|
|
restart: function() {
|
|
this.$scroller().css({
|
|
"-webkit-transform": "",
|
|
transform: ""
|
|
});
|
|
this.initPager();
|
|
}
|
|
};
|
|
|
|
function scaleStepable(value, arrValueStep, arrScaleStep) {
|
|
if (arrValueStep.length !== arrScaleStep.length) {
|
|
return value;
|
|
}
|
|
var scaleedValue = value;
|
|
var valueStepIndex = arrValueStep.length;
|
|
while (valueStepIndex--) {
|
|
if (value > arrValueStep[valueStepIndex]) {
|
|
scaleedValue = (value - arrValueStep[valueStepIndex]) * arrScaleStep[valueStepIndex];
|
|
for (var i = valueStepIndex; i > 0; i--) {
|
|
scaleedValue += (arrValueStep[i] - arrValueStep[i - 1]) * arrScaleStep[i - 1];
|
|
}
|
|
scaleedValue += arrValueStep[0] * 1;
|
|
break;
|
|
}
|
|
}
|
|
return scaleedValue;
|
|
}
|
|
|
|
function ScrollReader(options) {
|
|
if (!options) {
|
|
options = {};
|
|
}
|
|
this.$wrapper = $(options.wrapperSelector);
|
|
this.$scroller = $(options.scrollerSelector || window);
|
|
this.$prev = $(options.prevSelector);
|
|
this.$next = $(options.nextSelector);
|
|
this.$nextTrigger = $(options.nextTriggerSelector);
|
|
this.$mark = $(options.markSelector);
|
|
this.onPrevClick = options.onPrevClick || noop;
|
|
this.onCenterClick = options.onCenterClick || noop;
|
|
this.onNextClick = options.onNextClick || noop;
|
|
this.onScroll = options.onScroll || noop;
|
|
this.onScrollPrev = options.onScrollPrev || noop;
|
|
this.onScrollNext = options.onScrollNext || noop;
|
|
this.onWillScrollNext = options.onWillScrollNext || noop;
|
|
this.triggerMinHeight = options.triggerMinHeight || 58;
|
|
this.enabled = false;
|
|
this.isPreloading = false;
|
|
this.initEvents();
|
|
}
|
|
|
|
ScrollReader.prototype = {
|
|
initEvents: function() {
|
|
var self = this;
|
|
var $wrapper = self.$wrapper;
|
|
var $scroller = self.$scroller;
|
|
var $prev = self.$prev;
|
|
var $next = self.$next;
|
|
var $nextTrigger = self.$nextTrigger;
|
|
var isMoving = false;
|
|
var firstTouch;
|
|
var touch = {};
|
|
var pull = {};
|
|
var jump;
|
|
$wrapper.on({
|
|
touchstart: function(event) {
|
|
if (!self.enabled) {
|
|
return;
|
|
}
|
|
var target = event.target || {};
|
|
if (/^(?:a|input|label|i|use|svg)$/i.test(target.tagName) || $(target).parents("a").length) {
|
|
return;
|
|
}
|
|
isMoving = true;
|
|
firstTouch = event.touches[0] || event;
|
|
touch.x1 = firstTouch.pageX;
|
|
touch.y1 = firstTouch.pageY;
|
|
},
|
|
touchmove: function(event) {
|
|
if (!isMoving) {
|
|
return;
|
|
}
|
|
firstTouch = event.touches[0] || event;
|
|
touch.x2 = firstTouch.pageX;
|
|
touch.y2 = firstTouch.pageY;
|
|
var dy = touch.y2 - touch.y1;
|
|
var scrollTop = $scroller.scrollTop();
|
|
var maxScrollTop = $wrapper.offset().top + $wrapper.height() - $scroller.height();
|
|
if (scrollTop <= 0 && dy > 0) {
|
|
event.preventDefault();
|
|
if (pull.type !== "down") {
|
|
pull.type = "down";
|
|
pull.y1 = touch.y2;
|
|
}
|
|
pull.y2 = touch.y2;
|
|
pull.dy = pull.y2 - pull.y1;
|
|
var limitDownHeight = 52;
|
|
var downOffsetTop = Math.abs(parseInt($prev.css("margin-top"), 10));
|
|
if (pull.dy - limitDownHeight > 0) {
|
|
jump = -1;
|
|
$prev.css({
|
|
"border-bottom-width": scaleStepable(pull.dy - limitDownHeight, [ 20, 40, 60, 80, 100 ], [ .5, .4, .3, .2, .1 ]),
|
|
height: limitDownHeight,
|
|
transition: "none"
|
|
});
|
|
} else {
|
|
jump = 0;
|
|
$prev.css({
|
|
"border-bottom-width": Math.max(downOffsetTop - pull.dy, 0),
|
|
height: pull.dy,
|
|
transition: "none"
|
|
});
|
|
}
|
|
} else if (scrollTop >= maxScrollTop && dy < 0) {
|
|
event.preventDefault();
|
|
if (pull.type !== "up") {
|
|
pull.type = "up";
|
|
pull.y1 = touch.y2;
|
|
}
|
|
pull.y2 = touch.y2;
|
|
pull.dy = pull.y1 - pull.y2;
|
|
var limitUpHeight = 48;
|
|
if (pull.dy > 0) {
|
|
if (pull.dy > limitUpHeight) {
|
|
jump = 1;
|
|
} else {
|
|
jump = 0;
|
|
}
|
|
$next.prev().css({
|
|
position: "relative",
|
|
top: -scaleStepable(pull.dy, [ 20, 40, 60, 80, 100 ], [ .5, .4, .3, .2, .1 ])
|
|
});
|
|
} else {
|
|
jump = 0;
|
|
$next.prev().css({
|
|
position: "relative",
|
|
top: 0
|
|
});
|
|
}
|
|
} else {
|
|
self.checkWillScrollNext();
|
|
}
|
|
},
|
|
touchend: function(e) {
|
|
if (!isMoving) {
|
|
return;
|
|
}
|
|
isMoving = false;
|
|
var restore = function() {
|
|
$prev.css({
|
|
"border-bottom-width": "",
|
|
height: "",
|
|
transition: ""
|
|
});
|
|
$next.prev().css({
|
|
position: "",
|
|
top: "",
|
|
"-webkit-transition": "",
|
|
transition: ""
|
|
});
|
|
};
|
|
if (!touch.y2) {
|
|
self.handlerClick(touch.x1, touch.y1, e);
|
|
} else if (jump === -1) {
|
|
$prev.css({
|
|
"border-bottom-width": 0,
|
|
transition: ""
|
|
});
|
|
self.enabled = false;
|
|
self.onScrollPrev(function() {
|
|
restore();
|
|
var maxScrollTop = $wrapper.offset().top + $wrapper.height() - $scroller.height();
|
|
$scroller.scrollTop(maxScrollTop - 58 - 48);
|
|
self.enabled = true;
|
|
}, function() {
|
|
restore();
|
|
self.enabled = true;
|
|
});
|
|
} else if (jump === 1) {
|
|
$next.prev().css({
|
|
position: "relative",
|
|
top: 0,
|
|
"-webkit-transition": "top .25s",
|
|
transition: "top .25s"
|
|
});
|
|
self.enabled = false;
|
|
self.onScrollNext(function() {
|
|
restore();
|
|
self.enabled = true;
|
|
}, function() {
|
|
restore();
|
|
self.enabled = true;
|
|
});
|
|
} else if (pull.type) {
|
|
restore();
|
|
}
|
|
firstTouch = null;
|
|
touch = {};
|
|
pull = {};
|
|
jump = null;
|
|
}
|
|
});
|
|
$scroller.on("scroll", function() {
|
|
self.onScroll($scroller.scrollTop());
|
|
});
|
|
$nextTrigger.on("click", function() {
|
|
layer_login=layer.open({type: 2,content: '加载中'});
|
|
self.enabled = false;
|
|
self.onScrollNext(function() {
|
|
layer.close(layer_login);
|
|
self.enabled = true;
|
|
}, function() {
|
|
layer.close(layer_login);
|
|
self.enabled = true;
|
|
});
|
|
});
|
|
},
|
|
enable: function() {
|
|
this.enabled = true;
|
|
this.refresh();
|
|
},
|
|
disable: function() {
|
|
this.enabled = false;
|
|
this.$scroller.scrollTop(0);
|
|
},
|
|
refresh: function() {},
|
|
restart: function() {
|
|
this.$scroller.scrollTop(0);
|
|
},
|
|
handlerClick: function(x, y, e) {
|
|
var self = this;
|
|
var $wrapper = self.$wrapper;
|
|
var $scroller = self.$scroller;
|
|
var height = $scroller.height();
|
|
var scrollTop = $scroller.scrollTop();
|
|
var range = [ scrollTop + height / 3, scrollTop + height * 2 / 3 ];
|
|
var oneScreenContentHeight = height - 60;
|
|
if (y <= range[0]) {
|
|
self.adjusthMark(Math.max(scrollTop + 44, 0));
|
|
self.onPrevClick(e);
|
|
self.scrollTo(Math.max(scrollTop - oneScreenContentHeight, 0));
|
|
} else if (y >= range[1]) {
|
|
var maxScrollTop = $wrapper.offset().top + $wrapper.height() - $scroller.height();
|
|
self.adjusthMark(Math.min(scrollTop + height, maxScrollTop));
|
|
self.onNextClick(e);
|
|
self.scrollTo(Math.min(scrollTop + oneScreenContentHeight, maxScrollTop));
|
|
self.checkWillScrollNext();
|
|
} else {
|
|
self.onCenterClick();
|
|
}
|
|
},
|
|
checkWillScrollNext: function() {
|
|
var self = this;
|
|
var $wrapper = self.$wrapper;
|
|
var $scroller = self.$scroller;
|
|
var scrollTop = $scroller.scrollTop();
|
|
var maxScrollTop = $wrapper.offset().top + $wrapper.height() - $scroller.height();
|
|
if (scrollTop >= Math.min(maxScrollTop * .8, maxScrollTop - 200) && !self.isPreloading) {
|
|
self.isPreloading = true;
|
|
self.onWillScrollNext(function() {
|
|
self.isPreloading = false;
|
|
}, function() {
|
|
self.isPreloading = false;
|
|
});
|
|
}
|
|
},
|
|
scrollTo: function(y, callback) {
|
|
var $scroller = this.$scroller;
|
|
var scrollTop = $scroller.scrollTop();
|
|
if (y < 0) {
|
|
y = 0;
|
|
}
|
|
var step = function() {
|
|
scrollTop += (y - scrollTop) * .2;
|
|
if (Math.abs(y - scrollTop) < 1) {
|
|
$scroller.scrollTop(y);
|
|
if ($.isFunction(callback)) {
|
|
callback();
|
|
}
|
|
} else {
|
|
$scroller.scrollTop(scrollTop);
|
|
if (window.requestAnimationFrame) {
|
|
requestAnimationFrame(step);
|
|
} else {
|
|
setTimeout(step, 17);
|
|
}
|
|
}
|
|
};
|
|
step();
|
|
},
|
|
adjusthMark: function(y) {
|
|
var self = this;
|
|
var $wapper = self.$wrapper;
|
|
var $mark = self.$mark;
|
|
if (!$mark.data("init")) {
|
|
$mark.data("init", true);
|
|
$wapper.on("touchstart", function() {
|
|
if (!self.enabled) {
|
|
return;
|
|
}
|
|
clearTimeout($mark.timer);
|
|
$mark.css("opacity", 0);
|
|
});
|
|
}
|
|
$mark.css({
|
|
opacity: 1,
|
|
top: y
|
|
});
|
|
$mark.timer = setTimeout(function() {
|
|
$mark.css("opacity", 0);
|
|
}, 1500);
|
|
}
|
|
};
|
|
|
|
|
|
var ACTIVE = "active", ENABLED = "enabled";
|
|
var Toggle = function(selector, options) {
|
|
var self = this;
|
|
if (!selector) {
|
|
return self;
|
|
}
|
|
if ($.isFunction(options)) {
|
|
options = {
|
|
callback: options
|
|
};
|
|
}
|
|
var defaults = {
|
|
mode: "visible",
|
|
container: $("body"),
|
|
callback: function() {}
|
|
};
|
|
var params = $.extend({}, defaults, options || {});
|
|
self.callback = params.callback;
|
|
self.mode = params.mode;
|
|
if (!selector.size && $.isArray(selector)) {
|
|
selector = selector.join();
|
|
}
|
|
if (typeof selector == "string") {
|
|
params.container.on("click", selector, function(event) {
|
|
self.toggle($(this), event);
|
|
});
|
|
} else if (selector.length) {
|
|
selector.on("click", function(event) {
|
|
self.toggle($(this), event);
|
|
});
|
|
}
|
|
self.aria(selector);
|
|
};
|
|
Toggle.prototype.aria = function(selector) {
|
|
var self = this;
|
|
if (self.mode == "visible" && typeof selector == "string") {
|
|
$(selector).each(function() {
|
|
var trigger = $(this);
|
|
trigger.attr({
|
|
role: "menuitem",
|
|
"aria-expanded": trigger.hasClass(ACTIVE)
|
|
});
|
|
});
|
|
}
|
|
};
|
|
Toggle.prototype.toggle = function(trigger, event) {
|
|
var self = this;
|
|
var target = trigger;
|
|
var isActive;
|
|
if (self.mode == "visible") {
|
|
target = $("#" + trigger.attr("data-rel"));
|
|
isActive = trigger.hasClass(ACTIVE);
|
|
if (isActive) {
|
|
trigger.removeClass(ACTIVE).attr("aria-expanded", "false");
|
|
target.removeClass(ACTIVE);
|
|
} else {
|
|
trigger.addClass(ACTIVE).attr("aria-expanded", "true");
|
|
target.addClass(ACTIVE);
|
|
}
|
|
} else if (self.mode == "more") {
|
|
isActive = typeof trigger.attr("open") == "string";
|
|
if (isActive) {
|
|
trigger.removeAttr("open");
|
|
} else {
|
|
trigger.attr("open", "");
|
|
}
|
|
}
|
|
self.callback.call(trigger, trigger, target, isActive, event);
|
|
};
|
|
|
|
|
|
function isLocalStorageSupported() {
|
|
var testKey = "test";
|
|
try {
|
|
localStorage.setItem(testKey, testKey);
|
|
localStorage.removeItem(testKey);
|
|
return true;
|
|
} catch (ex) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
var isSupported = isLocalStorageSupported();
|
|
|
|
var Storage = {
|
|
get : function(key) {
|
|
if (!isSupported) {
|
|
return null;
|
|
}
|
|
try {
|
|
return JSON.parse(localStorage.getItem(key));
|
|
} catch (ex) {
|
|
return null;
|
|
}
|
|
},
|
|
set : function(key, value) {
|
|
if (!isSupported) {
|
|
return null;
|
|
}
|
|
try {
|
|
return localStorage.setItem(key, JSON.stringify(value));
|
|
} catch (ex) {
|
|
return null;
|
|
}
|
|
},
|
|
remove : function(key) {
|
|
if (!isSupported) {
|
|
return null;
|
|
}
|
|
return localStorage.removeItem(key);
|
|
},
|
|
clear : function() {
|
|
if (!isSupported) {
|
|
return null;
|
|
}
|
|
return localStorage.clear();
|
|
}
|
|
};
|
|
|
|
|
|
(function ($) {
|
|
"use strict";
|
|
var $ = window.Zepto;
|
|
var ACTIVE = "active";
|
|
var Aside;
|
|
$.fn.aside = function(options) {
|
|
if (!this.$aside) {
|
|
this.$aside = new Aside(this, options);
|
|
}
|
|
};
|
|
Aside = function(el, options) {
|
|
var defaults = {
|
|
scrollable: ".scrollable",
|
|
onInit: function() {},
|
|
onShow: function() {},
|
|
onHide: function() {},
|
|
onScroll: function() {}
|
|
};
|
|
var elTrigger = $(el);
|
|
var elBody = $(document.body);
|
|
if (elTrigger.length === 0) return;
|
|
var params = $.extend({}, defaults, options);
|
|
var idAside = el.data("rel");
|
|
var elAside = $("#" + idAside);
|
|
var isActive = function() {
|
|
return location.hash.replace("#&", "") === idAside;
|
|
};
|
|
var self = this;
|
|
self.el = {
|
|
trigger: elTrigger,
|
|
aside: elAside,
|
|
overlay: elAside.find(".aside-overlay"),
|
|
content: elAside.find(".aside-content")
|
|
};
|
|
self.callback = {
|
|
init: params.onInit,
|
|
show: params.onShow,
|
|
hide: params.onHide,
|
|
scroll: params.onScroll
|
|
};
|
|
self.title = elTrigger.attr("title");
|
|
elTrigger.attr({
|
|
role: "button",
|
|
"aria-haspopup": "true"
|
|
});
|
|
elTrigger.on("click", function(event) {
|
|
event.preventDefault();
|
|
self.show(this.href);
|
|
});
|
|
elAside.prependTo(elBody);
|
|
self.el.overlay.on("click", function() {
|
|
self.hide();
|
|
}).on("touchmove", function(event) {
|
|
event.preventDefault();
|
|
}).attr({
|
|
role: "button"
|
|
});
|
|
self.scrollable(params.scrollable);
|
|
self.swipeOut(params.scrollable);
|
|
if (isActive()) {
|
|
self.show();
|
|
}
|
|
window.addEventListener("popstate", function() {
|
|
if (isActive()) {
|
|
self.show();
|
|
} else {
|
|
self.hide(true);
|
|
}
|
|
});
|
|
};
|
|
Aside.prototype.show = function(hash) {
|
|
var self = this;
|
|
var el = self.el, callback = self.callback;
|
|
var elTrigger = el.trigger;
|
|
var elAside = el.aside;
|
|
if (elAside.hasClass(ACTIVE)) {
|
|
return;
|
|
}
|
|
elAside.addClass(ACTIVE);
|
|
el.overlay.attr("title", "点击关闭浮层");
|
|
elTrigger.attr("title", "浮层已显示");
|
|
if (!elTrigger.data("init")) {
|
|
elTrigger.data("init", true);
|
|
callback.init.call(self);
|
|
}
|
|
$("html").addClass("noscroll");
|
|
callback.show.call(self);
|
|
if (history.pushState && hash) {
|
|
history.pushState(null, null, hash);
|
|
}
|
|
};
|
|
Aside.prototype.hide = function(isFromPopState) {
|
|
var self = this;
|
|
var el = self.el, callback = self.callback;
|
|
var elTrigger = el.trigger;
|
|
var elAside = el.aside;
|
|
$("html").removeClass("noscroll");
|
|
if (!elAside.hasClass(ACTIVE)) {
|
|
return;
|
|
}
|
|
elAside.removeClass(ACTIVE);
|
|
el.overlay.attr("title", "浮层已关闭");
|
|
elTrigger.attr("title", self.title);
|
|
callback.hide.call(self);
|
|
if (history.pushState && !isFromPopState) {
|
|
var href = location.href.split("#")[0];
|
|
history.go(-1);
|
|
setTimeout(function() {
|
|
history.replaceState(null, null, href);
|
|
}, 0);
|
|
}
|
|
};
|
|
Aside.prototype.scrollable = function(selectorScrollable) {
|
|
var self = this;
|
|
var elAside = self.el.aside;
|
|
if (!selectorScrollable || elAside.data("isBindScroll")) {
|
|
return self;
|
|
}
|
|
var isSBBrowser = /mx\d.*mqqbrowser/i.test(navigator.userAgent);
|
|
var data = {
|
|
posY: 0,
|
|
maxscroll: 0
|
|
};
|
|
elAside.on("touchstart", selectorScrollable, function(event) {
|
|
var events = event.touches[0] || event;
|
|
data.elScroll = $(this);
|
|
data.posY = events.pageY;
|
|
data.scrollY = data.elScroll.scrollTop();
|
|
data.maxscroll = this.scrollHeight - this.clientHeight;
|
|
});
|
|
elAside.on("touchmove", function(event) {
|
|
if (data.maxscroll <= 0 || isSBBrowser) {
|
|
event.preventDefault();
|
|
}
|
|
var elScroll = data.elScroll;
|
|
var scrollTop = elScroll.scrollTop();
|
|
var events = event.touches[0] || event;
|
|
var distanceY = events.pageY - data.posY;
|
|
if (isSBBrowser) {
|
|
elScroll.scrollTop(data.scrollY - distanceY);
|
|
elScroll.trigger("scroll");
|
|
return;
|
|
}
|
|
if (distanceY > 0 && scrollTop == 0) {
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
if (distanceY < 0 && scrollTop + 1 >= data.maxscroll) {
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
self.callback.scroll.call(self, elScroll);
|
|
});
|
|
elAside.data("isBindScroll", true);
|
|
};
|
|
Aside.prototype.swipeOut = function(selectorScrollable) {
|
|
var self = this;
|
|
var elAside = self.el.aside;
|
|
var elContent = self.el.content;
|
|
var data = {};
|
|
elContent.on("touchstart", function(event) {
|
|
var events = event.touches[0] || event;
|
|
data.posX = events.pageX;
|
|
data.distanceX = 0;
|
|
if (data.transition) {
|
|
return;
|
|
}
|
|
elContent.css({
|
|
"-webkit-transition": "none",
|
|
transition: "none"
|
|
});
|
|
var target = event.target, elTarget = $(target);
|
|
var elScroll = elTarget.parents(selectorScrollable);
|
|
if (elTarget.is(selectorScrollable)) {
|
|
elScroll = elTarget;
|
|
}
|
|
if (elScroll.length && elScroll[0].scrollHeight > elScroll[0].clientHeight) {
|
|
data.moving = false;
|
|
return;
|
|
}
|
|
data.moving = true;
|
|
});
|
|
elAside.on("touchmove", function(event) {
|
|
var events = event.touches[0] || event;
|
|
var distanceX = events.pageX - data.posX;
|
|
data.distanceX = distanceX;
|
|
if (distanceX < 0) {
|
|
distanceX = 0;
|
|
}
|
|
if (!data.moving) {
|
|
return;
|
|
}
|
|
elContent.css({
|
|
"-webkit-transform": "translateX(" + distanceX + "px)",
|
|
transform: "translateX(" + distanceX + "px)"
|
|
});
|
|
event.preventDefault();
|
|
});
|
|
elAside.on("touchend", function() {
|
|
elContent.css({
|
|
"-webkit-transition": "",
|
|
transition: ""
|
|
});
|
|
if (!data.moving) {
|
|
return;
|
|
}
|
|
data.transition = true;
|
|
if (data.distanceX > 100) {
|
|
self.hide();
|
|
elContent.css({
|
|
"-webkit-transform": "translateX(100%)",
|
|
transform: "translateX(100%)"
|
|
});
|
|
} else {
|
|
elContent.css({
|
|
"-webkit-transform": "translateX(0)",
|
|
transform: "translateX(0)"
|
|
});
|
|
}
|
|
setTimeout(function() {
|
|
elContent.css({
|
|
"-webkit-transform": "",
|
|
transform: ""
|
|
});
|
|
delete data.transition;
|
|
}, 151);
|
|
data.moving = false;
|
|
});
|
|
return self;
|
|
};
|
|
return Aside;
|
|
})(Zepto);
|
|
|
|
var CL = "range", rangePrefix = CL + "-";
|
|
$.fn.range = function(options) {
|
|
return $(this).each(function() {
|
|
if (this.$range) {
|
|
this.$range = new Range($(this), options);
|
|
}
|
|
});
|
|
};
|
|
var Range = function(el, options) {
|
|
var self = this;
|
|
var defaults = {
|
|
container: $("body"),
|
|
shadow: false,
|
|
buttons: [ "", "" ],
|
|
onChangeEnd: function() {},
|
|
tips: function(value) {
|
|
return value;
|
|
}
|
|
};
|
|
var params = $.extend({}, defaults, options || {});
|
|
var min = el.attr("min") || 0, max = el.attr("max") || 100, step = el.attr("step") || 1;
|
|
var container = $("<div></div>").attr("class", el.attr("class")).addClass(CL);
|
|
var track = $("<div></div>").addClass(rangePrefix + "track");
|
|
var thumb = $("<a></a>").addClass(rangePrefix + "thumb").attr({
|
|
role: "slider",
|
|
"aria-valuenow": el.val(),
|
|
"aria-valuemax": max,
|
|
"aria-valuemin": min
|
|
});
|
|
var shadow = $();
|
|
if (params.shadow == true) {
|
|
shadow = $("<a></a>").addClass(rangePrefix + "shadow").attr("title", "之前位置");
|
|
}
|
|
el.before(container);
|
|
if (container.width() == 0) {
|
|
container.width(el.width());
|
|
}
|
|
track.append(thumb);
|
|
container.append(track).prepend(shadow);
|
|
container.on("click", function(event) {
|
|
var target = event && event.target;
|
|
if (!target) {
|
|
return;
|
|
}
|
|
if (shadow.length && target == shadow[0]) {
|
|
var value = $(target).attr("data-value"), valueEl = el.val();
|
|
if (value && valueEl != value) {
|
|
self.value(value);
|
|
params.onChangeEnd.call(el, self);
|
|
}
|
|
} else if (target != thumb[0]) {
|
|
var distance = event.clientX - (thumb.offset().left - $(window).scrollLeft()) - thumb.width() / 2;
|
|
self.value(el.val() * 1 + (max - min) * distance / $(this).width());
|
|
params.onChangeEnd.call(el, self);
|
|
}
|
|
});
|
|
var posThumb = {
|
|
distance: 0
|
|
};
|
|
thumb.on("touchstart", function(event) {
|
|
var events = event.touches[0] || event;
|
|
posThumb.x = events.pageX;
|
|
posThumb.value = el.val() * 1;
|
|
posThumb.distance = 0;
|
|
var tips = posThumb.value;
|
|
if ($.isFunction(params.tips)) {
|
|
tips = params.tips.call(el, posThumb.value);
|
|
}
|
|
thumb.attr("data-tips", tips).attr("aria-valuenow", tips).addClass("active");
|
|
});
|
|
params.container.on({
|
|
touchmove: function(event) {
|
|
var events = event.touches[0] || event;
|
|
if (typeof posThumb.x == "number") {
|
|
var distance = events.pageX - posThumb.x;
|
|
posThumb.distance = distance;
|
|
self.value(posThumb.value + (max - min) * distance / container.width());
|
|
var tips = el.val();
|
|
if ($.isFunction(params.tips)) {
|
|
tips = params.tips.call(el, tips);
|
|
}
|
|
thumb.attr("data-tips", tips).attr("aria-valuenow", tips);
|
|
event.preventDefault();
|
|
}
|
|
},
|
|
touchend: function() {
|
|
if (Math.abs(posThumb.distance) > 0) {
|
|
params.onChangeEnd.call(el, self);
|
|
}
|
|
posThumb.x = null;
|
|
posThumb.value = null;
|
|
thumb.removeClass("active");
|
|
posThumb.distance = 0;
|
|
}
|
|
});
|
|
if ($.isArray(params.buttons)) {
|
|
params.buttons.forEach(function(button, index) {
|
|
if (!button) {
|
|
return;
|
|
}
|
|
if (typeof button == "string") {
|
|
button = $(button);
|
|
}
|
|
if (button.length) {
|
|
button.on("click", function() {
|
|
var indexBtn = +$(this).data("index");
|
|
var max = el.attr("max");
|
|
var min = el.attr("min") || "1";
|
|
var step = el.attr("step") || "1";
|
|
var value = el.val(), newValue = value;
|
|
if (indexBtn == 0) {
|
|
newValue = value - step;
|
|
if (newValue < min) {
|
|
newValue = min;
|
|
}
|
|
} else if (indexBtn == 1) {
|
|
newValue = value * 1 + step * 1;
|
|
if (newValue > max) {
|
|
newValue = max;
|
|
}
|
|
}
|
|
if (newValue !== value) {
|
|
self.value(newValue);
|
|
params.onChangeEnd.call(el, self);
|
|
}
|
|
}).data("index", index);
|
|
button.attr("role", "button");
|
|
}
|
|
});
|
|
}
|
|
this.num = {
|
|
min: +min,
|
|
max: +max,
|
|
step: +step
|
|
};
|
|
this.el = {
|
|
input: el,
|
|
container: container,
|
|
track: track,
|
|
thumb: thumb,
|
|
shadow: shadow
|
|
};
|
|
this.callback = {
|
|
changeEnd: params.onChangeEnd.bind(el, self)
|
|
};
|
|
this.obj = {};
|
|
this.value();
|
|
this.shadow();
|
|
return this;
|
|
};
|
|
Range.prototype.value = function(value) {
|
|
var input = this.el.input, oldvalue = input.val();
|
|
var max = this.num.max, min = this.num.min, step = this.num.step;
|
|
if (!value) {
|
|
oldvalue = value;
|
|
value = $.trim(input.val());
|
|
}
|
|
if (value > max || max - value < step / 2) {
|
|
value = max;
|
|
} else if (value == "" || value < min || value - min < step / 2) {
|
|
value = min;
|
|
} else {
|
|
value = min + Math.round((value - min) / step) * step;
|
|
}
|
|
input.val(value);
|
|
this.position();
|
|
if (value != oldvalue) {
|
|
input.trigger("change");
|
|
}
|
|
return this;
|
|
};
|
|
Range.prototype.position = function() {
|
|
var input = this.el.input, value = input.val();
|
|
var max = this.num.max, min = this.num.min, step = this.num.step;
|
|
this.el.track.css("borderLeftWidth", this.el.container.width() * (value - min) / (max - min));
|
|
return this;
|
|
};
|
|
Range.prototype.shadow = function() {
|
|
var el = this.el;
|
|
var track = el.track, shadow = el.shadow;
|
|
if (shadow.length) {
|
|
shadow.css("left", track.css("borderLeftWidth")).attr("data-value", el.input.val());
|
|
}
|
|
return this;
|
|
};
|
|
|
|
function debounce(func, wait) {
|
|
var context;
|
|
var args;
|
|
var result;
|
|
var previous;
|
|
var timer;
|
|
var later = function() {
|
|
var diff = Date.now() - previous;
|
|
if (diff < wait && diff > 0) {
|
|
timer = setTimeout(later, wait - diff);
|
|
} else {
|
|
timer = null;
|
|
result = func.apply(context, args);
|
|
if (!timer) {
|
|
context = args = null;
|
|
}
|
|
}
|
|
};
|
|
return function() {
|
|
context = this;
|
|
args = arguments;
|
|
previous = Date.now();
|
|
if (!timer) {
|
|
timer = setTimeout(later, wait);
|
|
}
|
|
return result;
|
|
};
|
|
}; |