2019-06-24 19:53:10 +02:00

797 lines
23 KiB
CoffeeScript
Executable File

# SlidesJS 3.0.4
# Documentation and examples http://slidesjs.com
# Support forum http://groups.google.com/group/slidesjs
# Created by Nathan Searles http://nathansearles.com
# Version: 3.0.4
# Updated: June 26th, 2013
# SlidesJS is an open source project, contribute at GitHub:
# https://github.com/nathansearles/Slides
# (c) 2013 by Nathan Searles
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
(($, window, document) ->
pluginName = "slidesjs"
defaults =
width: 940
# Set the default width of the slideshow.
height: 528
# Set the default height of the slideshow.
start: 1
# Set the first slide in the slideshow.
navigation:
# Next and previous button settings.
active: true
# [boolean] Create next and previous buttons.
# You can set to false and use your own next/prev buttons.
# User defined next/prev buttons must have the following:
# previous: class="slidesjs-previous slidesjs-navigation"
# next: class="slidesjs-next slidesjs-navigation"
effect: "slide"
# [string] Can be either "slide" or "fade".
pagination:
# Pagination settings
active: true
# [boolean] Create pagination items.
# You cannot use your own pagination.
effect: "slide"
# [string] Can be either "slide" or "fade".
play:
# Play and stop button setting.
active: false
# [boolean] Create the play and stop buttons.
# You cannot use your own pagination.
effect: "slide"
# [string] Can be either "slide" or "fade".
interval: 5000
# [number] Time spent on each slide in milliseconds.
auto: false
# [boolean] Start playing the slideshow on load
swap: true
# [boolean] show/hide stop and play buttons
pauseOnHover: false
# [boolean] pause a playing slideshow on hover
restartDelay: 2500
# [number] restart delay on an inactive slideshow
effect:
slide:
# Slide effect settings.
speed: 500
# [number] Speed in milliseconds of the slide animation.
fade:
speed: 300
# [number] Speed in milliseconds of the fade animation.
crossfade: true
# [boolean] Cross-fade the transition
callback:
loaded: () ->
# [function] Called when slides is loaded
start: () ->
# [function] Called when animation has started
complete: () ->
# [function] Called when animation is complete
class Plugin
constructor: (@element, options) ->
@options = $.extend true, {}, defaults, options
@_defaults = defaults
@_name = pluginName
@init()
Plugin::init = ->
$element = $(@element)
@data = $.data this
# Set data
$.data this, "animating", false
$.data this, "total", $element.children().not(".slidesjs-navigation", $element).length
$.data this, "current", @options.start - 1
$.data this, "vendorPrefix", @_getVendorPrefix()
# Detect touch device
if typeof TouchEvent != "undefined"
$.data this, "touch", true
# Set slide speed to half for touch
@options.effect.slide.speed = this.options.effect.slide.speed / 2
# Hide overflow
$element.css overflow: "hidden"
# Create container
$element.slidesContainer = $element.children().not(".slidesjs-navigation", $element).wrapAll("<div class='slidesjs-container'>", $element).parent().css
overflow: "hidden"
position: "relative"
# Create control div
$(".slidesjs-container", $element)
.wrapInner("<div class='slidesjs-control'>", $element)
.children()
# Setup control div
$(".slidesjs-control", $element)
.css
position: "relative"
left: 0
# Setup slides
$(".slidesjs-control", $element)
.children()
.addClass("slidesjs-slide")
.css
position: "absolute"
top: 0
left: 0
width: "100%"
zIndex: 0
display: "none"
webkitBackfaceVisibility: "hidden"
# Assign an index to each slide
$.each( $(".slidesjs-control", $element).children(), (i) ->
$slide = $(this)
$slide.attr("slidesjs-index", i)
)
if @data.touch
# Bind touch events, if supported
$(".slidesjs-control", $element).on("touchstart", (e) =>
@_touchstart(e)
)
$(".slidesjs-control", $element).on("touchmove", (e) =>
@_touchmove(e)
)
$(".slidesjs-control", $element).on("touchend", (e) =>
@_touchend(e)
)
# Fades in slideshow, your slideshow ID must be display:none in your CSS
$element.fadeIn 0
# Update sets width/height of slideshow
@update()
# If touch device setup next slides
@_setuptouch() if @data.touch
# Fade in start slide
$(".slidesjs-control", $element)
.children(":eq(" + @data.current + ")")
.eq(0)
.fadeIn 0, ->
$(this).css zIndex: 10
if @options.navigation.active
# Create next/prev buttons
prevButton = $("<a>"
class: "slidesjs-previous slidesjs-navigation"
href: "#"
title: "Previous"
text: "Previous"
).appendTo($element)
nextButton = $("<a>"
class: "slidesjs-next slidesjs-navigation"
href: "#"
title: "Next"
text: "Next"
).appendTo($element)
# bind click events
$(".slidesjs-next", $element).click (e) =>
e.preventDefault()
@stop(true)
@next(@options.navigation.effect)
$(".slidesjs-previous", $element).click (e) =>
e.preventDefault()
@stop(true)
@previous(@options.navigation.effect)
if @options.play.active
playButton = $("<a>",
class: "slidesjs-play slidesjs-navigation"
href: "#"
title: "Play"
text: "Play"
).appendTo($element)
stopButton = $("<a>",
class: "slidesjs-stop slidesjs-navigation"
href: "#"
title: "Stop"
text: "Stop"
).appendTo($element)
playButton.click (e) =>
e.preventDefault()
@play(true)
stopButton.click (e) =>
e.preventDefault()
@stop(true)
if @options.play.swap
stopButton.css
display: "none"
if @options.pagination.active
# Create unordered list pagination
pagination = $("<ul>"
class: "slidesjs-pagination"
).appendTo($element)
# Create a list item and anchor for each slide
$.each(new Array(@data.total), (i) =>
paginationItem = $("<li>"
class: "slidesjs-pagination-item"
).appendTo(pagination)
paginationLink = $("<a>"
href: "#"
"data-slidesjs-item": i
html: i + 1
).appendTo(paginationItem)
# bind click events
paginationLink.click (e) =>
e.preventDefault()
# Stop play
@stop(true)
# Goto to selected slide
@goto( ($(e.currentTarget).attr("data-slidesjs-item") * 1) + 1 )
)
# Bind update on browser resize
$(window).bind("resize", () =>
@update()
)
# Set start pagination item to active
@_setActive()
# Auto play slideshow
if @options.play.auto
@play()
# Slides has loaded
@options.callback.loaded(@options.start)
# @_setActive()
# Sets the active slide in the pagination
Plugin::_setActive = (number) ->
$element = $(@element)
@data = $.data this
# Get the current slide index
current = if number > -1 then number else @data.current
# Set active slide in pagination
$(".active", $element).removeClass "active"
$(".slidesjs-pagination li:eq(" + current + ") a", $element).addClass "active"
# @update()
# Update the slideshow size on browser resize
Plugin::update = ->
$element = $(@element)
@data = $.data this
# Hide all slides expect current
$(".slidesjs-control", $element).children(":not(:eq(" + @data.current + "))").css
display: "none"
left: 0
zIndex: 0
# Get the new width and height
width = $element.width()
height = (@options.height / @options.width) * width
# Store new width and height
@options.width = width
@options.height = height
# Set new width and height
$(".slidesjs-control, .slidesjs-container", $element).css
width: width
height: height
# @next()
# Next mechanics
Plugin::next = (effect) ->
$element = $(@element)
@data = $.data this
# Set the direction
$.data this, "direction", "next"
# Slides or fade effect
if effect is undefined then effect = @options.navigation.effect
if effect is "fade" then @_fade() else @_slide()
# @previous()
# Previous mechanics
Plugin::previous = (effect) ->
$element = $(@element)
@data = $.data this
# Set the direction
$.data this, "direction", "previous"
# Slides or fade effect
if effect is undefined then effect = @options.navigation.effect
if effect is "fade" then @_fade() else @_slide()
# @goto()
# Pagination mechanics
Plugin::goto = (number) ->
$element = $(@element)
@data = $.data this
# Set effect to default if not defined
if effect is undefined then effect = @options.pagination.effect
# Error correction if slide doesn't exists
if number > @data.total
number = @data.total
else if number < 1
number = 1
if typeof number is "number"
if effect is "fade" then @_fade(number) else @_slide(number)
else if typeof number is "string"
if number is "first"
if effect is "fade" then @_fade(0) else @_slide(0)
else if number is "last"
if effect is "fade" then @_fade(@data.total) else @_slide(@data.total)
# @_setuptouch()
# Setup slideshow for touch
Plugin::_setuptouch = () ->
$element = $(@element)
@data = $.data this
# Define slides control
slidesControl = $(".slidesjs-control", $element)
# Get next/prev slides around current slide
next = @data.current + 1
previous = @data.current - 1
# Create the loop
previous = @data.total - 1 if previous < 0
next = 0 if next > @data.total - 1
# By default next/prev slides are hidden, show them when on touch device
slidesControl.children(":eq(" + next + ")").css
display: "block"
left: @options.width
slidesControl.children(":eq(" + previous + ")").css
display: "block"
left: -@options.width
# @_touchstart()
# Start touch
Plugin::_touchstart = (e) ->
$element = $(@element)
@data = $.data this
touches = e.originalEvent.touches[0]
# Setup the next and previous slides for swiping
@_setuptouch()
# Start touch timer
$.data this, "touchtimer", Number(new Date())
# Set touch position
$.data this, "touchstartx", touches.pageX
$.data this, "touchstarty", touches.pageY
# Stop event from bubbling up
e.stopPropagation()
# @_touchend()
# Animates the slideshow when touch is complete
Plugin::_touchend = (e) ->
$element = $(@element)
@data = $.data this
touches = e.originalEvent.touches[0]
# Define slides control
slidesControl = $(".slidesjs-control", $element)
# Slide has been dragged to the right, goto previous slide
if slidesControl.position().left > @options.width * 0.5 || slidesControl.position().left > @options.width * 0.1 && (Number(new Date()) - @data.touchtimer < 250)
$.data this, "direction", "previous"
@_slide()
# Slide has been dragged to the left, goto next slide
else if slidesControl.position().left < -(@options.width * 0.5) || slidesControl.position().left < -(@options.width * 0.1) && (Number(new Date()) - @data.touchtimer < 250)
$.data this, "direction", "next"
@_slide()
else
# Slide has not been dragged far enough, animate back to 0 and reset
# Get the browser's vendor prefix
prefix = @data.vendorPrefix
# Create CSS3 styles based on vendor prefix
transform = prefix + "Transform"
duration = prefix + "TransitionDuration"
timing = prefix + "TransitionTimingFunction"
# Set CSS3 styles
slidesControl[0].style[transform] = "translateX(0px)"
slidesControl[0].style[duration] = @options.effect.slide.speed * 0.85 + "ms"
# Rest slideshow
slidesControl.on "transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd", =>
# Get the browser's vendor prefix
prefix = @data.vendorPrefix
# Create CSS3 styles based on vendor prefix
transform = prefix + "Transform"
duration = prefix + "TransitionDuration"
timing = prefix + "TransitionTimingFunction"
# Set CSS3 styles
slidesControl[0].style[transform] = ""
slidesControl[0].style[duration] = ""
slidesControl[0].style[timing] = ""
# Stop event from bubbling up
e.stopPropagation()
# @_touchmove()
# Moves the slide on touch
Plugin::_touchmove = (e) ->
$element = $(@element)
@data = $.data this
touches = e.originalEvent.touches[0]
# Get the browser's vendor prefix
prefix = @data.vendorPrefix
# Define slides control
slidesControl = $(".slidesjs-control", $element)
# Create CSS3 styles based on vendor prefix
transform = prefix + "Transform"
# Check if user is trying to scroll vertically
$.data this, "scrolling", Math.abs(touches.pageX - @data.touchstartx) < Math.abs(touches.pageY - @data.touchstarty)
# Set CSS3 styles
if !@data.animating && !@data.scrolling
# Prevent default scrolling
e.preventDefault()
@_setuptouch()
slidesControl[0].style[transform] = "translateX(" + (touches.pageX - @data.touchstartx) + "px)"
# Stop event from bubbling up
e.stopPropagation()
# @play()
# Play the slideshow
Plugin::play = (next) ->
$element = $(@element)
@data = $.data this
# Check if the slideshow is already playing
if not @data.playInterval
# If next is true goto next slide
if next
currentSlide = @data.current
@data.direction = "next"
if @options.play.effect is "fade" then @_fade() else @_slide()
# Set and store interval
$.data this, "playInterval", setInterval ( =>
currentSlide = @data.current
@data.direction = "next"
if @options.play.effect is "fade" then @_fade() else @_slide()
), @options.play.interval
# Define slides container
slidesContainer = $(".slidesjs-container", $element)
if @options.play.pauseOnHover
# Prevent event build up
slidesContainer.unbind()
# Stop/pause slideshow on mouse enter
slidesContainer.bind "mouseenter", =>
clearTimeout @data.restartDelay
$.data this, "restartDelay", null
@stop()
# Play slideshow on mouse leave
slidesContainer.bind "mouseleave", =>
if @options.play.restartDelay
$.data this, "restartDelay", setTimeout ( =>
@play(true)
), @options.play.restartDelay
else
@play()
$.data this, "playing", true
# Add "slidesjs-playing" class to "slidesjs-play" button
$(".slidesjs-play", $element).addClass("slidesjs-playing")
if @options.play.swap
$(".slidesjs-play", $element).hide()
$(".slidesjs-stop", $element).show()
# @stop()
# Stops a playing slideshow
Plugin::stop = (clicked) ->
$element = $(@element)
@data = $.data this
# Clear play interval
clearInterval @data.playInterval
if @options.play.pauseOnHover && clicked
# Prevent event build up
$(".slidesjs-container", $element).unbind()
# Reset slideshow
$.data this, "playInterval", null
$.data this, "playing", false
$(".slidesjs-play", $element).removeClass("slidesjs-playing")
if @options.play.swap
$(".slidesjs-stop", $element).hide()
$(".slidesjs-play", $element).show()
# @_slide()
# CSS3 and JavaScript slide animations
Plugin::_slide = (number) ->
$element = $(@element)
@data = $.data this
if not @data.animating and number isnt @data.current + 1
# Set animating to true
$.data this, "animating", true
# Get current slide
currentSlide = @data.current
if number > -1
number = number - 1
value = if number > currentSlide then 1 else -1
direction = if number > currentSlide then -@options.width else @options.width
next = number
else
value = if @data.direction is "next" then 1 else -1
direction = if @data.direction is "next" then -@options.width else @options.width
next = currentSlide + value
# Loop from first to last slide
next = @data.total - 1 if next is -1
# Loop from last to first slide
next = 0 if next is @data.total
# Set next slide pagination item to active
@_setActive(next)
# Define slides control
slidesControl = $(".slidesjs-control", $element)
# When changing from touch to pagination reset touch slide setup
if number > -1
# Hide all slides expect current
slidesControl.children(":not(:eq(" + currentSlide + "))").css
display: "none"
left: 0
zIndex: 0
# Setup the next slide
slidesControl.children(":eq(" + next + ")").css
display: "block"
left: value * @options.width
zIndex: 10
# Start the slide animation
@options.callback.start(currentSlide + 1)
if @data.vendorPrefix
# If supported use CSS3 for the animation
# Get the browser's vendor prefix
prefix = @data.vendorPrefix
# Create CSS3 styles based on vendor prefix
transform = prefix + "Transform"
duration = prefix + "TransitionDuration"
timing = prefix + "TransitionTimingFunction"
# Set CSS3 styles
slidesControl[0].style[transform] = "translateX(" + direction + "px)"
slidesControl[0].style[duration] = @options.effect.slide.speed + "ms"
slidesControl.on "transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd", =>
# Clear styles
slidesControl[0].style[transform] = ""
slidesControl[0].style[duration] = ""
# Reset slideshow
slidesControl.children(":eq(" + next + ")").css left: 0
slidesControl.children(":eq(" + currentSlide + ")").css
display: "none"
left: 0
zIndex: 0
# Set the new slide to the current
$.data this, "current", next
# # Set animating to false
$.data this, "animating", false
# Unbind transition callback to prevent build up
slidesControl.unbind("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd")
# Hide all slides expect current
slidesControl.children(":not(:eq(" + next + "))").css
display: "none"
left: 0
zIndex: 0
# If touch device setup next slides
@_setuptouch() if @data.touch
# End of the animation, call complete callback
@options.callback.complete(next + 1)
else
# If CSS3 isn't support use JavaScript for the animation
slidesControl.stop().animate
left: direction
, @options.effect.slide.speed, (=>
slidesControl.css left: 0
slidesControl.children(":eq(" + next + ")").css left: 0
slidesControl.children(":eq(" + currentSlide + ")").css
display: "none"
left: 0
zIndex: 0
# Set the new slide to the current
$.data this, "current", next
# Set animating to false
$.data this, "animating", false
# End of the animation, call complete callback
@options.callback.complete(next + 1)
)
# @_fade()
# Fading and cross fading
Plugin::_fade = (number) ->
$element = $(@element)
@data = $.data this
# Check if not currently animating and the selected slide is not the current slide
if not @data.animating and number isnt @data.current + 1
# Set animating to true
$.data this, "animating", true
# Get current slide
currentSlide = @data.current
if number
# Specific slide has been called
number = number - 1
value = if number > currentSlide then 1 else -1
next = number
else
# Next/prev slide has been called
value = if @data.direction is "next" then 1 else -1
next = currentSlide + value
# Loop from first to last slide
next = @data.total - 1 if next is -1
# Loop from last to first slide
next = 0 if next is @data.total
# Set next slide pagination item to active
@_setActive next
# Define slides control
slidesControl = $(".slidesjs-control", $element)
# Setup the next slide
slidesControl.children(":eq(" + next + ")").css
display: "none"
left: 0
zIndex: 10
# Start of the animation, call the start callback
@options.callback.start(currentSlide + 1)
if @options.effect.fade.crossfade
# Fade out current slide to next slide
slidesControl.children(":eq(" + @data.current + ")")
.stop()
.fadeOut @options.effect.fade.speed
# Fade in to next slide
slidesControl.children(":eq(" + next + ")")
.stop()
.fadeIn @options.effect.fade.speed, (=>
# Reset slides
slidesControl.children(":eq(" + next + ")").css zIndex: 0
# Set animating to false
$.data this, "animating", false
# Set the new slide to the current
$.data this, "current", next
# End of the animation, call complete callback
@options.callback.complete(next + 1)
)
else
# Fade to next slide
slidesControl.children(":eq(" + currentSlide + ")")
.stop()
.fadeOut @options.effect.fade.speed, (=>
# Reset slides
slidesControl.children(":eq(" + next + ")")
.stop()
.fadeIn @options.effect.fade.speed, (=>
# Reset slides
slidesControl.children(":eq(" + next + ")").css zIndex: 10
)
# Set animating to false
$.data this, "animating", false
# Set the new slide to the current
$.data this, "current", next
# End of the animation, call complete callback
@options.callback.complete(next + 1)
)
# @_getVendorPrefix()
# Check if the browser supports CSS3 Transitions
Plugin::_getVendorPrefix = () ->
body = document.body or document.documentElement
style = body.style
transition = "transition"
vendor = ["Moz", "Webkit", "Khtml", "O", "ms"]
transition = transition.charAt(0).toUpperCase() + transition.substr(1)
i = 0
while i < vendor.length
return vendor[i] if typeof style[vendor[i] + transition] is "string"
i++
false
# Plugin constructor
$.fn[pluginName] = (options) ->
@each ->
if !$.data(@, "plugin_#{pluginName}")
$.data(@, "plugin_#{pluginName}", new Plugin(@, options))
)(jQuery, window, document)