xm-select/docs/fathom/fathom.min.js
maplemei d54aa08565 v1.0.0.0727
1. 新增单选模式, {radio: true|false}
2. 新增重复选模式, {repeat: true|false}
3. 新增配置, 可以控制是否自动关闭下拉框, {clickClose: true|false}
4. 新增on方法, 可以监听已选择数据, data: {arr, item, selected}
2019-07-27 16:26:05 +08:00

316 lines
10 KiB
JavaScript
Executable File

(function($, window, undefined) {
var Fathom = function(container, options) {
this.container = container;
this.options = options;
return this.init()
},
$window = $(window),
$document = $(document);
Fathom.prototype = {
defaults: {
portable: undefined,
portableTagName: "div",
portableClass: "fathom-container",
displayMode: "single",
slideTagName: "div",
slideClass: "slide",
activeClass: "activeslide",
inactiveClass: "inactiveslide",
margin: 100,
onScrollInterval: 300,
scrollLength: 600,
easing: "swing",
timeline: undefined,
video: undefined,
onActivateSlide: undefined,
onDeactivateSlide: undefined
},
init: function() {
this.config = $.extend({}, this.defaults, this.options);
this.$container = $(this.container);
this.$slides = this.$container.find(this.config.slideTagName + (this.config.slideClass ? "." + this.config.slideClass :
""));
this.$firstSlide = this.$slides.filter(":first");
this.$lastSlide = this.$slides.filter(":last");
this.$activeSlide = this.activateSlide(this.$firstSlide);
return this._detectPortable()._setStyles()._setClasses()._setMargins()._setupEvents()._setupTimeline()._setupVideo()
._setupScrollHandler()
},
nextSlide: function() {
return this.scrollToSlide(this.$activeSlide.next())
},
prevSlide: function() {
return this.scrollToSlide(this.$activeSlide.prev())
},
scrollToSlide: function($elem) {
var self = this,
$scrollingElement = this.config.portable ? this.$portableContainer : $("html,body"),
$container = this.config.portable ? this.$portableContainer : $window,
portableScrollLeft = this.config.portable ? this.$portableContainer.scrollLeft() : 0;
if ($elem.length !== 1) {
return $elem
}
this.isAutoScrolling = true;
$scrollingElement.stop().animate({
scrollLeft: $elem.position().left + portableScrollLeft - ($container.width() - $elem.innerWidth()) / 2
}, self.config.scrollLength, self.config.easing, function() {
self.isAutoScrolling = false
});
return this.activateSlide($elem)
},
activateSlide: function($elem) {
var elem = $elem.get(0),
activeSlide;
if (this.$activeSlide !== undefined) {
activeSlide = this.$activeSlide.get(0);
if (activeSlide === elem) {
return $elem
}
this.$activeSlide.removeClass(this.config.activeClass).addClass(this.config.inactiveClass).trigger(
"deactivateslide.fathom");
if (typeof this.config.onDeactivateSlide === "function") {
this.config.onDeactivateSlide.call(activeSlide)
}
}
$elem.removeClass(this.config.inactiveClass).addClass(this.config.activeClass);
this.$activeSlide = $elem;
$elem.trigger("activateslide.fathom");
if (typeof this.config.onActivateSlide === "function") {
this.config.onActivateSlide.call(elem)
}
return $elem
},
setTime: function(t) {
var times = this._timeline || [];
for (var i = 0; i < times.length; i++) {
if (times[i].time <= t && times[i + 1].time > t) {
if (this.$activeSlide[0] !== times[i].slide[0]) {
this.scrollToSlide(times[i].slide)
}
break
}
}
},
_detectPortable: function() {
if (this.config.portable === undefined) {
if (this.$container.parent().is("body")) {
this.config.portable = false
} else {
this.config.portable = true
}
}
return this
},
_setupEvents: function() {
var self = this;
this.$container.delegate(this.config.slideTagName + "." + this.config.inactiveClass, "click", function(event) {
event.preventDefault();
self.scrollToSlide($(this))
});
$document.keydown(function(event) {
var key = event.which;
if (key === 39 || key === 32) {
event.preventDefault();
self.nextSlide()
} else if (key === 37) {
event.preventDefault();
self.prevSlide()
}
});
$window.resize(function() {
self._setMargins()
});
return this
},
_setStyles: function() {
this.$container.css("white-space", "nowrap");
this.$slides.css({
"white-space": "normal",
display: "inline-block",
"vertical-align": "top"
});
if (this.config.portable) {
this.$portableContainer = $("<" + this.config.portableTagName + ' class="' + this.config.portableClass + '" />');
this.$container.before(this.$portableContainer).appendTo(this.$portableContainer)
}
return this
},
_setClasses: function() {
this.$slides.addClass(this.config.inactiveClass);
this.$activeSlide.removeClass(this.config.inactiveClass).addClass(this.config.activeClass);
return this
},
_setMargins: function() {
var displayMode = this.config.displayMode,
$container = this.config.portable ? this.$portableContainer : $window,
containerWidth = $container.width(),
verticalSpacing = Math.ceil(($container.height() - this.$firstSlide.innerHeight()) / 2),
firstSlideSpacing = Math.ceil((containerWidth - this.$firstSlide.innerWidth()) / 2),
lastSlideSpacing = Math.ceil((containerWidth - this.$lastSlide.innerWidth()) / 2),
peekabooWidth = Math.ceil(containerWidth / 25);
this.$container.css("margin-top", verticalSpacing);
if (displayMode === "single") {
this.$slides.css("margin-right", firstSlideSpacing)
} else if (displayMode === "multi") {
this.$slides.css("margin-right", this.config.margin)
}
this.$firstSlide.css("margin-left", firstSlideSpacing);
this.$lastSlide.css("margin-right", lastSlideSpacing);
if (this.config.portable) {
var slidesWidth = parseInt(this.$container.css("padding-left")) + parseInt(this.$container.css("padding-right"));
this.$slides.each(function() {
slidesWidth += $(this).outerWidth(true)
});
this.$container.width(slidesWidth)
}
return this
},
_setupTimeline: function() {
var slides = this.$slides;
function parseTime(point) {
for (var m = (point.time || point).toString().match(/(((\d+):)?(\d+):)?(\d+)/), a = 0, i = 3; i <= 5; i++) {
a = a * 60 + parseInt(m[i] || 0)
}
return a
}
var currentSlide = -1;
function parseSlide(point) {
if (point.slide == null) {
currentSlide++
} else if ($.type(point.slide) === "number") {
currentSlide = point.slide
} else {
for (var match = slides.filter(point.slide)[0], i = 0; i < slides.length; i++) {
if (slides[i] === match) {
currentSlide = i;
break
}
}
}
return slides.eq(currentSlide)
}
if (!this.config.timeline) return this;
this._timeline = [];
for (var t = this.config.timeline, i = 0; i < t.length; i++) {
this._timeline.push({
time: parseTime(t[i]),
slide: parseSlide(t[i])
})
}
this._timeline.push({
time: 99999,
slide: t[0].slide
});
return this
},
_setupVideo: function() {
if (!this.config.video) {
this._setupDefaultTimeSource()
} else if (this.config.video.source === "vimeo") {
this._setupVimeoVideo(this.config.video)
} else {
throw "unknown video source, not supported"
}
return this
},
_setupDefaultTimeSource: function() {
var self = this,
t0 = (new Date).getTime();
setInterval(function() {
var t1 = (new Date).getTime();
self.setTime((t1 - t0) / 1e3)
}, 250)
},
_setupVimeoVideo: function(vid) {
var self = this,
vid = this.config.video,
downgrade = false;
if (window.location.protocol === "file:") {
"console" in window && console.log(
"vimeo video player api does not work with local files. Downgrading video support\nsee http://vimeo.com/api/docs/player-js"
);
downgrade = true
}
function loadFrame() {
var id = "p" + vid.id;
var frameSrc = '<iframe id="' + id + '" width="' + (vid.width || 360) + '" height="' + (vid.height || 203) +
'" frameborder="0" src="http://player.vimeo.com/video/' + vid.id + "?api=1&player_id=" + id + '">';
return $(frameSrc).appendTo(vid.parent || "body")[0]
}
if (downgrade) {
$(loadFrame()).bind("load", function() {
self._setupDefaultTimeSource()
})
} else {
$.getScript("http://a.vimeocdn.com/js/froogaloop2.min.js?", function() {
$f(loadFrame()).addEvent("ready", function(player_id) {
var vimeo = $f(player_id),
timer = false;
vimeo.addEvent("play", function(data) {
if (timer === false) {
timer = setInterval(function() {
vimeo.api("getCurrentTime", function(value, player_id) {
self.setTime(value)
})
}, 250)
}
});
vimeo.addEvent("pause", function(data) {
clearInterval(timer);
timer = false
});
vid.autoplay && vimeo.api("play")
})
})
}
},
_setupScrollHandler: function() {
var self = this,
slideSelector = self.config.slideTagName + (self.config.slideClass ? "." + self.config.slideClass : ""),
$scrollContainer = this.config.portable ? this.$portableContainer : $window,
isIOS = navigator.userAgent.match(/like Mac OS X/i) === null ? false : true,
$elem;
self.scrolling = false;
setInterval(function() {
if (self.scrolling && (self.isAutoScrolling === false || self.isAutoScrolling === undefined)) {
self.scrolling = false;
if ($scrollContainer.scrollLeft() === 0) {
self.activateSlide(self.$firstSlide)
} else {
var offsetX = self.config.portable ? $scrollContainer.position().left : 0,
offsetY = self.config.portable ? $scrollContainer.position().top : 0,
midpoint = {
x: offsetX + $scrollContainer.width() / 2 + (isIOS ? $window.scrollLeft() : 0),
y: offsetY + $scrollContainer.height() / 2 + (isIOS ? $window.scrollTop() : 0)
};
$elem = $(document.elementFromPoint(midpoint.x, midpoint.y));
if ($elem.is(slideSelector)) {
self.activateSlide($elem)
} else {
$elem = $elem.parents(slideSelector + ":first").each(function() {
self.activateSlide($(this))
})
}
}
}
}, self.config.onScrollInterval);
$scrollContainer.scroll(function() {
self.scrolling = true
});
return this
}
};
$.fn.fathom = function(options) {
new Fathom(this, options);
return this
};
Fathom.defaults = Fathom.prototype.defaults;
Fathom.setDefaults = function(options) {
$.extend(Fathom.defaults, options)
};
window.Fathom = Fathom
})(jQuery, window);