Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F56337349
sly.js
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
75 KB
Referenced Files
None
Subscribers
None
sly.js
View Options
;(
function
(
$
,
w
,
undefined
)
{
'use strict'
;
var
pluginName
=
'sly'
;
var
className
=
'Sly'
;
var
namespace
=
pluginName
;
// Local WindowAnimationTiming interface
var
cAF
=
w
.
cancelAnimationFrame
||
w
.
cancelRequestAnimationFrame
;
var
rAF
=
w
.
requestAnimationFrame
;
// Support indicators
var
transform
,
gpuAcceleration
;
// Other global values
var
$doc
=
$
(
document
);
var
dragInitEvents
=
'touchstart.'
+
namespace
+
' mousedown.'
+
namespace
;
var
dragMouseEvents
=
'mousemove.'
+
namespace
+
' mouseup.'
+
namespace
;
var
dragTouchEvents
=
'touchmove.'
+
namespace
+
' touchend.'
+
namespace
;
var
wheelEvent
=
(
document
.
implementation
.
hasFeature
(
'Event.wheel'
,
'3.0'
)
?
'wheel.'
:
'mousewheel.'
)
+
namespace
;
var
clickEvent
=
'click.'
+
namespace
;
var
mouseDownEvent
=
'mousedown.'
+
namespace
;
var
tmpArray
=
[];
var
time
;
// Math shorthands
var
abs
=
Math
.
abs
;
var
sqrt
=
Math
.
sqrt
;
var
pow
=
Math
.
pow
;
var
round
=
Math
.
round
;
var
max
=
Math
.
max
;
var
min
=
Math
.
min
;
// Keep track of last fired global wheel event
var
lastGlobalWheel
=
0
;
$doc
.
on
(
wheelEvent
,
function
(
event
)
{
var
sly
=
event
.
originalEvent
[
namespace
];
var
time
=
+
new
Date
();
// Update last global wheel time, but only when event didn't originate
// in Sly frame, or the origin was less than scrollHijack time ago
if
(
!
sly
||
sly
.
options
.
scrollHijack
<
time
-
lastGlobalWheel
)
lastGlobalWheel
=
time
;
});
/**
* Sly.
*
* @class
*
* @param {Element} frame DOM element of sly container.
* @param {Object} options Object with options.
* @param {Object} callbackMap Callbacks map.
*/
function
Sly
(
frame
,
options
,
callbackMap
)
{
if
(
!
(
this
instanceof
Sly
))
return
new
Sly
(
frame
,
options
,
callbackMap
);
// Extend options
var
o
=
$
.
extend
({},
Sly
.
defaults
,
options
);
// Private variables
var
self
=
this
;
var
parallax
=
isNumber
(
frame
);
// Frame
var
$frame
=
$
(
frame
);
var
$slidee
=
o
.
slidee
?
$
(
o
.
slidee
).
eq
(
0
)
:
$frame
.
children
().
eq
(
0
);
var
frameSize
=
0
;
var
slideeSize
=
0
;
var
pos
=
{
start
:
0
,
center
:
0
,
end
:
0
,
cur
:
0
,
dest
:
0
};
// Scrollbar
var
$sb
=
$
(
o
.
scrollBar
).
eq
(
0
);
var
$handle
=
$sb
.
children
().
eq
(
0
);
var
sbSize
=
0
;
var
handleSize
=
0
;
var
hPos
=
{
start
:
0
,
end
:
0
,
cur
:
0
};
// Pagesbar
var
$pb
=
$
(
o
.
pagesBar
);
var
$pages
=
0
;
var
pages
=
[];
// Items
var
$items
=
0
;
var
items
=
[];
var
rel
=
{
firstItem
:
0
,
lastItem
:
0
,
centerItem
:
0
,
activeItem
:
null
,
activePage
:
0
};
// Styles
var
frameStyles
=
new
StyleRestorer
(
$frame
[
0
]);
var
slideeStyles
=
new
StyleRestorer
(
$slidee
[
0
]);
var
sbStyles
=
new
StyleRestorer
(
$sb
[
0
]);
var
handleStyles
=
new
StyleRestorer
(
$handle
[
0
]);
// Navigation type booleans
var
basicNav
=
o
.
itemNav
===
'basic'
;
var
forceCenteredNav
=
o
.
itemNav
===
'forceCentered'
;
var
centeredNav
=
o
.
itemNav
===
'centered'
||
forceCenteredNav
;
var
itemNav
=
!
parallax
&&
(
basicNav
||
centeredNav
||
forceCenteredNav
);
// Miscellaneous
var
$scrollSource
=
o
.
scrollSource
?
$
(
o
.
scrollSource
)
:
$frame
;
var
$dragSource
=
o
.
dragSource
?
$
(
o
.
dragSource
)
:
$frame
;
var
$forwardButton
=
$
(
o
.
forward
);
var
$backwardButton
=
$
(
o
.
backward
);
var
$prevButton
=
$
(
o
.
prev
);
var
$nextButton
=
$
(
o
.
next
);
var
$prevPageButton
=
$
(
o
.
prevPage
);
var
$nextPageButton
=
$
(
o
.
nextPage
);
var
callbacks
=
{};
var
last
=
{};
var
animation
=
{};
var
move
=
{};
var
dragging
=
{
released
:
1
};
var
scrolling
=
{
last
:
0
,
delta
:
0
,
resetTime
:
200
};
var
renderID
=
0
;
var
historyID
=
0
;
var
cycleID
=
0
;
var
continuousID
=
0
;
var
i
,
l
;
// Normalizing frame
if
(
!
parallax
)
{
frame
=
$frame
[
0
];
}
// Expose properties
self
.
initialized
=
0
;
self
.
frame
=
frame
;
self
.
slidee
=
$slidee
[
0
];
self
.
pos
=
pos
;
self
.
rel
=
rel
;
self
.
items
=
items
;
self
.
pages
=
pages
;
self
.
isPaused
=
0
;
self
.
options
=
o
;
self
.
dragging
=
dragging
;
/**
* Loading function.
*
* Populate arrays, set sizes, bind events, ...
*
* @param {Boolean} [isInit] Whether load is called from within self.init().
* @return {Void}
*/
function
load
(
isInit
)
{
// Local variables
var
lastItemsCount
=
0
;
var
lastPagesCount
=
pages
.
length
;
// Save old position
pos
.
old
=
$
.
extend
({},
pos
);
// Reset global variables
frameSize
=
parallax
?
0
:
$frame
[
o
.
horizontal
?
'width'
:
'height'
]();
sbSize
=
$sb
[
o
.
horizontal
?
'width'
:
'height'
]();
slideeSize
=
parallax
?
frame
:
$slidee
[
o
.
horizontal
?
'outerWidth'
:
'outerHeight'
]();
pages
.
length
=
0
;
// Set position limits & relatives
pos
.
start
=
0
;
pos
.
end
=
max
(
slideeSize
-
frameSize
,
0
);
// Sizes & offsets for item based navigations
if
(
itemNav
)
{
// Save the number of current items
lastItemsCount
=
items
.
length
;
// Reset itemNav related variables
$items
=
$slidee
.
children
(
o
.
itemSelector
);
items
.
length
=
0
;
// Needed variables
var
paddingStart
=
getPx
(
$slidee
,
o
.
horizontal
?
'paddingLeft'
:
'paddingTop'
);
var
paddingEnd
=
getPx
(
$slidee
,
o
.
horizontal
?
'paddingRight'
:
'paddingBottom'
);
var
borderBox
=
$
(
$items
).
css
(
'boxSizing'
)
===
'border-box'
;
var
areFloated
=
$items
.
css
(
'float'
)
!==
'none'
;
var
ignoredMargin
=
0
;
var
lastItemIndex
=
$items
.
length
-
1
;
var
lastItem
;
// Reset slideeSize
slideeSize
=
0
;
// Iterate through items
$items
.
each
(
function
(
i
,
element
)
{
// Item
var
$item
=
$
(
element
);
var
rect
=
element
.
getBoundingClientRect
();
var
itemSize
=
(
o
.
horizontal
?
rect
.
width
||
rect
.
right
-
rect
.
left
:
rect
.
height
||
rect
.
bottom
-
rect
.
top
);
var
itemMarginStart
=
getPx
(
$item
,
o
.
horizontal
?
'marginLeft'
:
'marginTop'
);
var
itemMarginEnd
=
getPx
(
$item
,
o
.
horizontal
?
'marginRight'
:
'marginBottom'
);
var
itemSizeFull
=
itemSize
+
itemMarginStart
+
itemMarginEnd
;
var
singleSpaced
=
!
itemMarginStart
||
!
itemMarginEnd
;
var
item
=
{};
item
.
el
=
element
;
item
.
size
=
singleSpaced
?
itemSize
:
itemSizeFull
;
item
.
half
=
item
.
size
/
2
;
item
.
start
=
slideeSize
+
(
singleSpaced
?
itemMarginStart
:
0
);
item
.
center
=
item
.
start
-
round
(
frameSize
/
2
-
item
.
size
/
2
);
item
.
end
=
item
.
start
-
frameSize
+
item
.
size
;
// Account for slidee padding
if
(
!
i
)
{
slideeSize
+=
paddingStart
;
}
// Increment slidee size for size of the active element
slideeSize
+=
itemSizeFull
;
// Try to account for vertical margin collapsing in vertical mode
// It's not bulletproof, but should work in 99% of cases
if
(
!
o
.
horizontal
&&
!
areFloated
)
{
// Subtract smaller margin, but only when top margin is not 0, and this is not the first element
if
(
itemMarginEnd
&&
itemMarginStart
&&
i
>
0
)
{
slideeSize
-=
min
(
itemMarginStart
,
itemMarginEnd
);
}
}
// Things to be done on last item
if
(
i
===
lastItemIndex
)
{
item
.
end
+=
paddingEnd
;
slideeSize
+=
paddingEnd
;
ignoredMargin
=
singleSpaced
?
itemMarginEnd
:
0
;
}
// Add item object to items array
items
.
push
(
item
);
lastItem
=
item
;
});
// Resize SLIDEE to fit all items
$slidee
[
0
].
style
[
o
.
horizontal
?
'width'
:
'height'
]
=
(
borderBox
?
slideeSize
:
slideeSize
-
paddingStart
-
paddingEnd
)
+
'px'
;
// Adjust internal SLIDEE size for last margin
slideeSize
-=
ignoredMargin
;
// Set limits
if
(
items
.
length
)
{
pos
.
start
=
items
[
0
][
forceCenteredNav
?
'center'
:
'start'
];
pos
.
end
=
forceCenteredNav
?
lastItem
.
center
:
frameSize
<
slideeSize
?
lastItem
.
end
:
pos
.
start
;
}
else
{
pos
.
start
=
pos
.
end
=
0
;
}
}
// Calculate SLIDEE center position
pos
.
center
=
round
(
pos
.
end
/
2
+
pos
.
start
/
2
);
// Update relative positions
updateRelatives
();
// Scrollbar
if
(
$handle
.
length
&&
sbSize
>
0
)
{
// Stretch scrollbar handle to represent the visible area
if
(
o
.
dynamicHandle
)
{
handleSize
=
pos
.
start
===
pos
.
end
?
sbSize
:
round
(
sbSize
*
frameSize
/
slideeSize
);
handleSize
=
within
(
handleSize
,
o
.
minHandleSize
,
sbSize
);
$handle
[
0
].
style
[
o
.
horizontal
?
'width'
:
'height'
]
=
handleSize
+
'px'
;
}
else
{
handleSize
=
$handle
[
o
.
horizontal
?
'outerWidth'
:
'outerHeight'
]();
}
hPos
.
end
=
sbSize
-
handleSize
;
if
(
!
renderID
)
{
syncScrollbar
();
}
}
// Pages
if
(
!
parallax
&&
frameSize
>
0
)
{
var
tempPagePos
=
pos
.
start
;
var
pagesHtml
=
''
;
// Populate pages array
if
(
itemNav
)
{
$
.
each
(
items
,
function
(
i
,
item
)
{
if
(
forceCenteredNav
)
{
pages
.
push
(
item
.
center
);
}
else
if
(
item
.
start
+
item
.
size
>
tempPagePos
&&
tempPagePos
<=
pos
.
end
)
{
tempPagePos
=
item
.
start
;
pages
.
push
(
tempPagePos
);
tempPagePos
+=
frameSize
;
if
(
tempPagePos
>
pos
.
end
&&
tempPagePos
<
pos
.
end
+
frameSize
)
{
pages
.
push
(
pos
.
end
);
}
}
});
}
else
{
while
(
tempPagePos
-
frameSize
<
pos
.
end
)
{
pages
.
push
(
tempPagePos
);
tempPagePos
+=
frameSize
;
}
}
// Pages bar
if
(
$pb
[
0
]
&&
lastPagesCount
!==
pages
.
length
)
{
for
(
var
i
=
0
;
i
<
pages
.
length
;
i
++
)
{
pagesHtml
+=
o
.
pageBuilder
.
call
(
self
,
i
);
}
$pages
=
$pb
.
html
(
pagesHtml
).
children
();
$pages
.
eq
(
rel
.
activePage
).
addClass
(
o
.
activeClass
);
}
}
// Extend relative variables object with some useful info
rel
.
slideeSize
=
slideeSize
;
rel
.
frameSize
=
frameSize
;
rel
.
sbSize
=
sbSize
;
rel
.
handleSize
=
handleSize
;
// Activate requested position
if
(
itemNav
)
{
if
(
isInit
&&
o
.
startAt
!=
null
)
{
activate
(
o
.
startAt
);
self
[
centeredNav
?
'toCenter'
:
'toStart'
](
o
.
startAt
);
}
// Fix possible overflowing
var
activeItem
=
items
[
rel
.
activeItem
];
slideTo
(
centeredNav
&&
activeItem
?
activeItem
.
center
:
within
(
pos
.
dest
,
pos
.
start
,
pos
.
end
));
}
else
{
if
(
isInit
)
{
if
(
o
.
startAt
!=
null
)
slideTo
(
o
.
startAt
,
1
);
}
else
{
// Fix possible overflowing
slideTo
(
within
(
pos
.
dest
,
pos
.
start
,
pos
.
end
));
}
}
// Trigger load event
trigger
(
'load'
);
}
self
.
reload
=
function
()
{
load
();
};
/**
* Animate to a position.
*
* @param {Int} newPos New position.
* @param {Bool} immediate Reposition immediately without an animation.
* @param {Bool} dontAlign Do not align items, use the raw position passed in first argument.
*
* @return {Void}
*/
function
slideTo
(
newPos
,
immediate
,
dontAlign
)
{
// Align items
if
(
itemNav
&&
dragging
.
released
&&
!
dontAlign
)
{
var
tempRel
=
getRelatives
(
newPos
);
var
isNotBordering
=
newPos
>
pos
.
start
&&
newPos
<
pos
.
end
;
if
(
centeredNav
)
{
if
(
isNotBordering
)
{
newPos
=
items
[
tempRel
.
centerItem
].
center
;
}
if
(
forceCenteredNav
&&
o
.
activateMiddle
)
{
activate
(
tempRel
.
centerItem
);
}
}
else
if
(
isNotBordering
)
{
newPos
=
items
[
tempRel
.
firstItem
].
start
;
}
}
// Handle overflowing position limits
if
(
dragging
.
init
&&
dragging
.
slidee
&&
o
.
elasticBounds
)
{
if
(
newPos
>
pos
.
end
)
{
newPos
=
pos
.
end
+
(
newPos
-
pos
.
end
)
/
6
;
}
else
if
(
newPos
<
pos
.
start
)
{
newPos
=
pos
.
start
+
(
newPos
-
pos
.
start
)
/
6
;
}
}
else
{
newPos
=
within
(
newPos
,
pos
.
start
,
pos
.
end
);
}
// Update the animation object
animation
.
start
=
+
new
Date
();
animation
.
time
=
0
;
animation
.
from
=
pos
.
cur
;
animation
.
to
=
newPos
;
animation
.
delta
=
newPos
-
pos
.
cur
;
animation
.
tweesing
=
dragging
.
tweese
||
dragging
.
init
&&
!
dragging
.
slidee
;
animation
.
immediate
=
!
animation
.
tweesing
&&
(
immediate
||
dragging
.
init
&&
dragging
.
slidee
||
!
o
.
speed
);
// Reset dragging tweesing request
dragging
.
tweese
=
0
;
// Start animation rendering
if
(
newPos
!==
pos
.
dest
)
{
pos
.
dest
=
newPos
;
trigger
(
'change'
);
if
(
!
renderID
)
{
render
();
}
}
// Reset next cycle timeout
resetCycle
();
// Synchronize states
updateRelatives
();
updateButtonsState
();
syncPagesbar
();
}
/**
* Render animation frame.
*
* @return {Void}
*/
function
render
()
{
if
(
!
self
.
initialized
)
{
return
;
}
// If first render call, wait for next animationFrame
if
(
!
renderID
)
{
renderID
=
rAF
(
render
);
if
(
dragging
.
released
)
{
trigger
(
'moveStart'
);
}
return
;
}
// If immediate repositioning is requested, don't animate.
if
(
animation
.
immediate
)
{
pos
.
cur
=
animation
.
to
;
}
// Use tweesing for animations without known end point
else
if
(
animation
.
tweesing
)
{
animation
.
tweeseDelta
=
animation
.
to
-
pos
.
cur
;
// Fuck Zeno's paradox
if
(
abs
(
animation
.
tweeseDelta
)
<
0.1
)
{
pos
.
cur
=
animation
.
to
;
}
else
{
pos
.
cur
+=
animation
.
tweeseDelta
*
(
dragging
.
released
?
o
.
swingSpeed
:
o
.
syncSpeed
);
}
}
// Use tweening for basic animations with known end point
else
{
animation
.
time
=
min
(
+
new
Date
()
-
animation
.
start
,
o
.
speed
);
pos
.
cur
=
animation
.
from
+
animation
.
delta
*
$
.
easing
[
o
.
easing
](
animation
.
time
/
o
.
speed
,
animation
.
time
,
0
,
1
,
o
.
speed
);
}
// If there is nothing more to render break the rendering loop, otherwise request new animation frame.
if
(
animation
.
to
===
pos
.
cur
)
{
pos
.
cur
=
animation
.
to
;
dragging
.
tweese
=
renderID
=
0
;
}
else
{
renderID
=
rAF
(
render
);
}
trigger
(
'move'
);
// Update SLIDEE position
if
(
!
parallax
)
{
if
(
transform
)
{
$slidee
[
0
].
style
[
transform
]
=
gpuAcceleration
+
(
o
.
horizontal
?
'translateX'
:
'translateY'
)
+
'('
+
(
-
pos
.
cur
)
+
'px)'
;
}
else
{
$slidee
[
0
].
style
[
o
.
horizontal
?
'left'
:
'top'
]
=
-
round
(
pos
.
cur
)
+
'px'
;
}
}
// When animation reached the end, and dragging is not active, trigger moveEnd
if
(
!
renderID
&&
dragging
.
released
)
{
trigger
(
'moveEnd'
);
}
syncScrollbar
();
}
/**
* Synchronizes scrollbar with the SLIDEE.
*
* @return {Void}
*/
function
syncScrollbar
()
{
if
(
$handle
.
length
)
{
hPos
.
cur
=
pos
.
start
===
pos
.
end
?
0
:
(((
dragging
.
init
&&
!
dragging
.
slidee
)
?
pos
.
dest
:
pos
.
cur
)
-
pos
.
start
)
/
(
pos
.
end
-
pos
.
start
)
*
hPos
.
end
;
hPos
.
cur
=
within
(
round
(
hPos
.
cur
),
hPos
.
start
,
hPos
.
end
);
if
(
last
.
hPos
!==
hPos
.
cur
)
{
last
.
hPos
=
hPos
.
cur
;
if
(
transform
)
{
$handle
[
0
].
style
[
transform
]
=
gpuAcceleration
+
(
o
.
horizontal
?
'translateX'
:
'translateY'
)
+
'('
+
hPos
.
cur
+
'px)'
;
}
else
{
$handle
[
0
].
style
[
o
.
horizontal
?
'left'
:
'top'
]
=
hPos
.
cur
+
'px'
;
}
}
}
}
/**
* Synchronizes pagesbar with SLIDEE.
*
* @return {Void}
*/
function
syncPagesbar
()
{
if
(
$pages
[
0
]
&&
last
.
page
!==
rel
.
activePage
)
{
last
.
page
=
rel
.
activePage
;
$pages
.
removeClass
(
o
.
activeClass
).
eq
(
rel
.
activePage
).
addClass
(
o
.
activeClass
);
trigger
(
'activePage'
,
last
.
page
);
}
}
/**
* Returns the position object.
*
* @param {Mixed} item
*
* @return {Object}
*/
self
.
getPos
=
function
(
item
)
{
if
(
itemNav
)
{
var
index
=
getIndex
(
item
);
return
index
!==
-
1
?
items
[
index
]
:
false
;
}
else
{
var
$item
=
$slidee
.
find
(
item
).
eq
(
0
);
if
(
$item
[
0
])
{
var
offset
=
o
.
horizontal
?
$item
.
offset
().
left
-
$slidee
.
offset
().
left
:
$item
.
offset
().
top
-
$slidee
.
offset
().
top
;
var
size
=
$item
[
o
.
horizontal
?
'outerWidth'
:
'outerHeight'
]();
return
{
start
:
offset
,
center
:
offset
-
frameSize
/
2
+
size
/
2
,
end
:
offset
-
frameSize
+
size
,
size
:
size
};
}
else
{
return
false
;
}
}
};
/**
* Continuous move in a specified direction.
*
* @param {Bool} forward True for forward movement, otherwise it'll go backwards.
* @param {Int} speed Movement speed in pixels per frame. Overrides options.moveBy value.
*
* @return {Void}
*/
self
.
moveBy
=
function
(
speed
)
{
move
.
speed
=
speed
;
// If already initiated, or there is nowhere to move, abort
if
(
dragging
.
init
||
!
move
.
speed
||
pos
.
cur
===
(
move
.
speed
>
0
?
pos
.
end
:
pos
.
start
))
{
return
;
}
// Initiate move object
move
.
lastTime
=
+
new
Date
();
move
.
startPos
=
pos
.
cur
;
// Set dragging as initiated
continuousInit
(
'button'
);
dragging
.
init
=
1
;
// Start movement
trigger
(
'moveStart'
);
cAF
(
continuousID
);
moveLoop
();
};
/**
* Continuous movement loop.
*
* @return {Void}
*/
function
moveLoop
()
{
// If there is nowhere to move anymore, stop
if
(
!
move
.
speed
||
pos
.
cur
===
(
move
.
speed
>
0
?
pos
.
end
:
pos
.
start
))
{
self
.
stop
();
}
// Request new move loop if it hasn't been stopped
continuousID
=
dragging
.
init
?
rAF
(
moveLoop
)
:
0
;
// Update move object
move
.
now
=
+
new
Date
();
move
.
pos
=
pos
.
cur
+
(
move
.
now
-
move
.
lastTime
)
/
1000
*
move
.
speed
;
// Slide
slideTo
(
dragging
.
init
?
move
.
pos
:
round
(
move
.
pos
));
// Normally, this is triggered in render(), but if there
// is nothing to render, we have to do it manually here.
if
(
!
dragging
.
init
&&
pos
.
cur
===
pos
.
dest
)
{
trigger
(
'moveEnd'
);
}
// Update times for future iteration
move
.
lastTime
=
move
.
now
;
}
/**
* Stops continuous movement.
*
* @return {Void}
*/
self
.
stop
=
function
()
{
if
(
dragging
.
source
===
'button'
)
{
dragging
.
init
=
0
;
dragging
.
released
=
1
;
}
};
/**
* Activate previous item.
*
* @return {Void}
*/
self
.
prev
=
function
()
{
self
.
activate
(
rel
.
activeItem
==
null
?
0
:
rel
.
activeItem
-
1
);
};
/**
* Activate next item.
*
* @return {Void}
*/
self
.
next
=
function
()
{
self
.
activate
(
rel
.
activeItem
==
null
?
0
:
rel
.
activeItem
+
1
);
};
/**
* Activate previous page.
*
* @return {Void}
*/
self
.
prevPage
=
function
()
{
self
.
activatePage
(
rel
.
activePage
-
1
);
};
/**
* Activate next page.
*
* @return {Void}
*/
self
.
nextPage
=
function
()
{
self
.
activatePage
(
rel
.
activePage
+
1
);
};
/**
* Slide SLIDEE by amount of pixels.
*
* @param {Int} delta Pixels/Items. Positive means forward, negative means backward.
* @param {Bool} immediate Reposition immediately without an animation.
*
* @return {Void}
*/
self
.
slideBy
=
function
(
delta
,
immediate
)
{
if
(
!
delta
)
{
return
;
}
if
(
itemNav
)
{
self
[
centeredNav
?
'toCenter'
:
'toStart'
](
within
((
centeredNav
?
rel
.
centerItem
:
rel
.
firstItem
)
+
o
.
scrollBy
*
delta
,
0
,
items
.
length
)
);
}
else
{
slideTo
(
pos
.
dest
+
delta
,
immediate
);
}
};
/**
* Animate SLIDEE to a specific position.
*
* @param {Int} pos New position.
* @param {Bool} immediate Reposition immediately without an animation.
*
* @return {Void}
*/
self
.
slideTo
=
function
(
pos
,
immediate
)
{
slideTo
(
pos
,
immediate
);
};
/**
* Core method for handling `toLocation` methods.
*
* @param {String} location
* @param {Mixed} item
* @param {Bool} immediate
*
* @return {Void}
*/
function
to
(
location
,
item
,
immediate
)
{
// Optional arguments logic
if
(
type
(
item
)
===
'boolean'
)
{
immediate
=
item
;
item
=
undefined
;
}
if
(
item
===
undefined
)
{
slideTo
(
pos
[
location
],
immediate
);
}
else
{
// You can't align items to sides of the frame
// when centered navigation type is enabled
if
(
centeredNav
&&
location
!==
'center'
)
{
return
;
}
var
itemPos
=
self
.
getPos
(
item
);
if
(
itemPos
)
{
slideTo
(
itemPos
[
location
],
immediate
,
!
centeredNav
);
}
}
}
/**
* Animate element or the whole SLIDEE to the start of the frame.
*
* @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
* @param {Bool} immediate Reposition immediately without an animation.
*
* @return {Void}
*/
self
.
toStart
=
function
(
item
,
immediate
)
{
to
(
'start'
,
item
,
immediate
);
};
/**
* Animate element or the whole SLIDEE to the end of the frame.
*
* @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
* @param {Bool} immediate Reposition immediately without an animation.
*
* @return {Void}
*/
self
.
toEnd
=
function
(
item
,
immediate
)
{
to
(
'end'
,
item
,
immediate
);
};
/**
* Animate element or the whole SLIDEE to the center of the frame.
*
* @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
* @param {Bool} immediate Reposition immediately without an animation.
*
* @return {Void}
*/
self
.
toCenter
=
function
(
item
,
immediate
)
{
to
(
'center'
,
item
,
immediate
);
};
/**
* Get the index of an item in SLIDEE.
*
* @param {Mixed} item Item DOM element.
*
* @return {Int} Item index, or -1 if not found.
*/
function
getIndex
(
item
)
{
return
item
!=
null
?
isNumber
(
item
)
?
item
>=
0
&&
item
<
items
.
length
?
item
:
-
1
:
$items
.
index
(
item
)
:
-
1
;
}
// Expose getIndex without lowering the compressibility of it,
// as it is used quite often throughout Sly.
self
.
getIndex
=
getIndex
;
/**
* Get index of an item in SLIDEE based on a variety of input types.
*
* @param {Mixed} item DOM element, positive or negative integer.
*
* @return {Int} Item index, or -1 if not found.
*/
function
getRelativeIndex
(
item
)
{
return
getIndex
(
isNumber
(
item
)
&&
item
<
0
?
item
+
items
.
length
:
item
);
}
/**
* Activates an item.
*
* @param {Mixed} item Item DOM element, or index starting at 0.
*
* @return {Mixed} Activated item index or false on fail.
*/
function
activate
(
item
,
force
)
{
var
index
=
getIndex
(
item
);
if
(
!
itemNav
||
index
<
0
)
{
return
false
;
}
// Update classes, last active index, and trigger active event only when there
// has been a change. Otherwise just return the current active index.
if
(
last
.
active
!==
index
||
force
)
{
// Update classes
$items
.
eq
(
rel
.
activeItem
).
removeClass
(
o
.
activeClass
);
$items
.
eq
(
index
).
addClass
(
o
.
activeClass
);
last
.
active
=
rel
.
activeItem
=
index
;
updateButtonsState
();
trigger
(
'active'
,
index
);
}
return
index
;
}
/**
* Activates an item and helps with further navigation when o.smart is enabled.
*
* @param {Mixed} item Item DOM element, or index starting at 0.
* @param {Bool} immediate Whether to reposition immediately in smart navigation.
*
* @return {Void}
*/
self
.
activate
=
function
(
item
,
immediate
)
{
var
index
=
activate
(
item
);
// Smart navigation
if
(
o
.
smart
&&
index
!==
false
)
{
// When centeredNav is enabled, center the element.
// Otherwise, determine where to position the element based on its current position.
// If the element is currently on the far end side of the frame, assume that user is
// moving forward and animate it to the start of the visible frame, and vice versa.
if
(
centeredNav
)
{
self
.
toCenter
(
index
,
immediate
);
}
else
if
(
index
>=
rel
.
lastItem
)
{
self
.
toStart
(
index
,
immediate
);
}
else
if
(
index
<=
rel
.
firstItem
)
{
self
.
toEnd
(
index
,
immediate
);
}
else
{
resetCycle
();
}
}
};
/**
* Activates a page.
*
* @param {Int} index Page index, starting from 0.
* @param {Bool} immediate Whether to reposition immediately without animation.
*
* @return {Void}
*/
self
.
activatePage
=
function
(
index
,
immediate
)
{
if
(
isNumber
(
index
))
{
slideTo
(
pages
[
within
(
index
,
0
,
pages
.
length
-
1
)],
immediate
);
}
};
/**
* Return relative positions of items based on their visibility within FRAME.
*
* @param {Int} slideePos Position of SLIDEE.
*
* @return {Void}
*/
function
getRelatives
(
slideePos
)
{
slideePos
=
within
(
isNumber
(
slideePos
)
?
slideePos
:
pos
.
dest
,
pos
.
start
,
pos
.
end
);
var
relatives
=
{};
var
centerOffset
=
forceCenteredNav
?
0
:
frameSize
/
2
;
// Determine active page
if
(
!
parallax
)
{
for
(
var
p
=
0
,
pl
=
pages
.
length
;
p
<
pl
;
p
++
)
{
if
(
slideePos
>=
pos
.
end
||
p
===
pages
.
length
-
1
)
{
relatives
.
activePage
=
pages
.
length
-
1
;
break
;
}
if
(
slideePos
<=
pages
[
p
]
+
centerOffset
)
{
relatives
.
activePage
=
p
;
break
;
}
}
}
// Relative item indexes
if
(
itemNav
)
{
var
first
=
false
;
var
last
=
false
;
var
center
=
false
;
// From start
for
(
var
i
=
0
,
il
=
items
.
length
;
i
<
il
;
i
++
)
{
// First item
if
(
first
===
false
&&
slideePos
<=
items
[
i
].
start
+
items
[
i
].
half
)
{
first
=
i
;
}
// Center item
if
(
center
===
false
&&
slideePos
<=
items
[
i
].
center
+
items
[
i
].
half
)
{
center
=
i
;
}
// Last item
if
(
i
===
il
-
1
||
slideePos
<=
items
[
i
].
end
+
items
[
i
].
half
)
{
last
=
i
;
break
;
}
}
// Safe assignment, just to be sure the false won't be returned
relatives
.
firstItem
=
isNumber
(
first
)
?
first
:
0
;
relatives
.
centerItem
=
isNumber
(
center
)
?
center
:
relatives
.
firstItem
;
relatives
.
lastItem
=
isNumber
(
last
)
?
last
:
relatives
.
centerItem
;
}
return
relatives
;
}
/**
* Update object with relative positions.
*
* @param {Int} newPos
*
* @return {Void}
*/
function
updateRelatives
(
newPos
)
{
$
.
extend
(
rel
,
getRelatives
(
newPos
));
}
/**
* Disable navigation buttons when needed.
*
* Adds disabledClass, and when the button is <button> or <input>, activates :disabled state.
*
* @return {Void}
*/
function
updateButtonsState
()
{
var
isStart
=
pos
.
dest
<=
pos
.
start
;
var
isEnd
=
pos
.
dest
>=
pos
.
end
;
var
slideePosState
=
(
isStart
?
1
:
0
)
|
(
isEnd
?
2
:
0
);
// Update paging buttons only if there has been a change in SLIDEE position
if
(
last
.
slideePosState
!==
slideePosState
)
{
last
.
slideePosState
=
slideePosState
;
if
(
$prevPageButton
.
is
(
'button,input'
))
{
$prevPageButton
.
prop
(
'disabled'
,
isStart
);
}
if
(
$nextPageButton
.
is
(
'button,input'
))
{
$nextPageButton
.
prop
(
'disabled'
,
isEnd
);
}
$prevPageButton
.
add
(
$backwardButton
)[
isStart
?
'addClass'
:
'removeClass'
](
o
.
disabledClass
);
$nextPageButton
.
add
(
$forwardButton
)[
isEnd
?
'addClass'
:
'removeClass'
](
o
.
disabledClass
);
}
// Forward & Backward buttons need a separate state caching because we cannot "property disable"
// them while they are being used, as disabled buttons stop emitting mouse events.
if
(
last
.
fwdbwdState
!==
slideePosState
&&
dragging
.
released
)
{
last
.
fwdbwdState
=
slideePosState
;
if
(
$backwardButton
.
is
(
'button,input'
))
{
$backwardButton
.
prop
(
'disabled'
,
isStart
);
}
if
(
$forwardButton
.
is
(
'button,input'
))
{
$forwardButton
.
prop
(
'disabled'
,
isEnd
);
}
}
// Item navigation
if
(
itemNav
&&
rel
.
activeItem
!=
null
)
{
var
isFirst
=
rel
.
activeItem
===
0
;
var
isLast
=
rel
.
activeItem
>=
items
.
length
-
1
;
var
itemsButtonState
=
(
isFirst
?
1
:
0
)
|
(
isLast
?
2
:
0
);
if
(
last
.
itemsButtonState
!==
itemsButtonState
)
{
last
.
itemsButtonState
=
itemsButtonState
;
if
(
$prevButton
.
is
(
'button,input'
))
{
$prevButton
.
prop
(
'disabled'
,
isFirst
);
}
if
(
$nextButton
.
is
(
'button,input'
))
{
$nextButton
.
prop
(
'disabled'
,
isLast
);
}
$prevButton
[
isFirst
?
'addClass'
:
'removeClass'
](
o
.
disabledClass
);
$nextButton
[
isLast
?
'addClass'
:
'removeClass'
](
o
.
disabledClass
);
}
}
}
/**
* Resume cycling.
*
* @param {Int} priority Resume pause with priority lower or equal than this. Used internally for pauseOnHover.
*
* @return {Void}
*/
self
.
resume
=
function
(
priority
)
{
if
(
!
o
.
cycleBy
||
!
o
.
cycleInterval
||
o
.
cycleBy
===
'items'
&&
(
!
items
[
0
]
||
rel
.
activeItem
==
null
)
||
priority
<
self
.
isPaused
)
{
return
;
}
self
.
isPaused
=
0
;
if
(
cycleID
)
{
cycleID
=
clearTimeout
(
cycleID
);
}
else
{
trigger
(
'resume'
);
}
cycleID
=
setTimeout
(
function
()
{
trigger
(
'cycle'
);
switch
(
o
.
cycleBy
)
{
case
'items'
:
self
.
activate
(
rel
.
activeItem
>=
items
.
length
-
1
?
0
:
rel
.
activeItem
+
1
);
break
;
case
'pages'
:
self
.
activatePage
(
rel
.
activePage
>=
pages
.
length
-
1
?
0
:
rel
.
activePage
+
1
);
break
;
}
},
o
.
cycleInterval
);
};
/**
* Pause cycling.
*
* @param {Int} priority Pause priority. 100 is default. Used internally for pauseOnHover.
*
* @return {Void}
*/
self
.
pause
=
function
(
priority
)
{
if
(
priority
<
self
.
isPaused
)
{
return
;
}
self
.
isPaused
=
priority
||
100
;
if
(
cycleID
)
{
cycleID
=
clearTimeout
(
cycleID
);
trigger
(
'pause'
);
}
};
/**
* Toggle cycling.
*
* @return {Void}
*/
self
.
toggle
=
function
()
{
self
[
cycleID
?
'pause'
:
'resume'
]();
};
/**
* Updates a signle or multiple option values.
*
* @param {Mixed} name Name of the option that should be updated, or object that will extend the options.
* @param {Mixed} value New option value.
*
* @return {Void}
*/
self
.
set
=
function
(
name
,
value
)
{
if
(
$
.
isPlainObject
(
name
))
{
$
.
extend
(
o
,
name
);
}
else
if
(
o
.
hasOwnProperty
(
name
))
{
o
[
name
]
=
value
;
}
};
/**
* Add one or multiple items to the SLIDEE end, or a specified position index.
*
* @param {Mixed} element Node element, or HTML string.
* @param {Int} index Index of a new item position. By default item is appended at the end.
*
* @return {Void}
*/
self
.
add
=
function
(
element
,
index
)
{
var
$element
=
$
(
element
);
if
(
itemNav
)
{
// Insert the element(s)
if
(
index
==
null
||
!
items
[
0
]
||
index
>=
items
.
length
)
{
$element
.
appendTo
(
$slidee
);
}
else
if
(
items
.
length
)
{
$element
.
insertBefore
(
items
[
index
].
el
);
}
// Adjust the activeItem index
if
(
rel
.
activeItem
!=
null
&&
index
<=
rel
.
activeItem
)
{
last
.
active
=
rel
.
activeItem
+=
$element
.
length
;
}
}
else
{
$slidee
.
append
(
$element
);
}
// Reload
load
();
};
/**
* Remove an item from SLIDEE.
*
* @param {Mixed} element Item index, or DOM element.
* @param {Int} index Index of a new item position. By default item is appended at the end.
*
* @return {Void}
*/
self
.
remove
=
function
(
element
)
{
if
(
itemNav
)
{
var
index
=
getRelativeIndex
(
element
);
if
(
index
>
-
1
)
{
// Remove the element
$items
.
eq
(
index
).
remove
();
// If the current item is being removed, activate new one after reload
var
reactivate
=
index
===
rel
.
activeItem
;
// Adjust the activeItem index
if
(
rel
.
activeItem
!=
null
&&
index
<
rel
.
activeItem
)
{
last
.
active
=
--
rel
.
activeItem
;
}
// Reload
load
();
// Activate new item at the removed position
if
(
reactivate
)
{
last
.
active
=
null
;
self
.
activate
(
rel
.
activeItem
);
}
}
}
else
{
$
(
element
).
remove
();
load
();
}
};
/**
* Helps re-arranging items.
*
* @param {Mixed} item Item DOM element, or index starting at 0. Use negative numbers to select items from the end.
* @param {Mixed} position Item insertion anchor. Accepts same input types as item argument.
* @param {Bool} after Insert after instead of before the anchor.
*
* @return {Void}
*/
function
moveItem
(
item
,
position
,
after
)
{
item
=
getRelativeIndex
(
item
);
position
=
getRelativeIndex
(
position
);
// Move only if there is an actual change requested
if
(
item
>
-
1
&&
position
>
-
1
&&
item
!==
position
&&
(
!
after
||
position
!==
item
-
1
)
&&
(
after
||
position
!==
item
+
1
))
{
$items
.
eq
(
item
)[
after
?
'insertAfter'
:
'insertBefore'
](
items
[
position
].
el
);
var
shiftStart
=
item
<
position
?
item
:
(
after
?
position
:
position
-
1
);
var
shiftEnd
=
item
>
position
?
item
:
(
after
?
position
+
1
:
position
);
var
shiftsUp
=
item
>
position
;
// Update activeItem index
if
(
rel
.
activeItem
!=
null
)
{
if
(
item
===
rel
.
activeItem
)
{
last
.
active
=
rel
.
activeItem
=
after
?
(
shiftsUp
?
position
+
1
:
position
)
:
(
shiftsUp
?
position
:
position
-
1
);
}
else
if
(
rel
.
activeItem
>
shiftStart
&&
rel
.
activeItem
<
shiftEnd
)
{
last
.
active
=
rel
.
activeItem
+=
shiftsUp
?
1
:
-
1
;
}
}
// Reload
load
();
}
}
/**
* Move item after the target anchor.
*
* @param {Mixed} item Item to be moved. Can be DOM element or item index.
* @param {Mixed} position Target position anchor. Can be DOM element or item index.
*
* @return {Void}
*/
self
.
moveAfter
=
function
(
item
,
position
)
{
moveItem
(
item
,
position
,
1
);
};
/**
* Move item before the target anchor.
*
* @param {Mixed} item Item to be moved. Can be DOM element or item index.
* @param {Mixed} position Target position anchor. Can be DOM element or item index.
*
* @return {Void}
*/
self
.
moveBefore
=
function
(
item
,
position
)
{
moveItem
(
item
,
position
);
};
/**
* Registers callbacks.
*
* @param {Mixed} name Event name, or callbacks map.
* @param {Mixed} fn Callback, or an array of callback functions.
*
* @return {Void}
*/
self
.
on
=
function
(
name
,
fn
)
{
// Callbacks map
if
(
type
(
name
)
===
'object'
)
{
for
(
var
key
in
name
)
{
if
(
name
.
hasOwnProperty
(
key
))
{
self
.
on
(
key
,
name
[
key
]);
}
}
// Callback
}
else
if
(
type
(
fn
)
===
'function'
)
{
var
names
=
name
.
split
(
' '
);
for
(
var
n
=
0
,
nl
=
names
.
length
;
n
<
nl
;
n
++
)
{
callbacks
[
names
[
n
]]
=
callbacks
[
names
[
n
]]
||
[];
if
(
callbackIndex
(
names
[
n
],
fn
)
===
-
1
)
{
callbacks
[
names
[
n
]].
push
(
fn
);
}
}
// Callbacks array
}
else
if
(
type
(
fn
)
===
'array'
)
{
for
(
var
f
=
0
,
fl
=
fn
.
length
;
f
<
fl
;
f
++
)
{
self
.
on
(
name
,
fn
[
f
]);
}
}
};
/**
* Registers callbacks to be executed only once.
*
* @param {Mixed} name Event name, or callbacks map.
* @param {Mixed} fn Callback, or an array of callback functions.
*
* @return {Void}
*/
self
.
one
=
function
(
name
,
fn
)
{
function
proxy
()
{
fn
.
apply
(
self
,
arguments
);
self
.
off
(
name
,
proxy
);
}
self
.
on
(
name
,
proxy
);
};
/**
* Remove one or all callbacks.
*
* @param {String} name Event name.
* @param {Mixed} fn Callback, or an array of callback functions. Omit to remove all callbacks.
*
* @return {Void}
*/
self
.
off
=
function
(
name
,
fn
)
{
if
(
fn
instanceof
Array
)
{
for
(
var
f
=
0
,
fl
=
fn
.
length
;
f
<
fl
;
f
++
)
{
self
.
off
(
name
,
fn
[
f
]);
}
}
else
{
var
names
=
name
.
split
(
' '
);
for
(
var
n
=
0
,
nl
=
names
.
length
;
n
<
nl
;
n
++
)
{
callbacks
[
names
[
n
]]
=
callbacks
[
names
[
n
]]
||
[];
if
(
fn
==
null
)
{
callbacks
[
names
[
n
]].
length
=
0
;
}
else
{
var
index
=
callbackIndex
(
names
[
n
],
fn
);
if
(
index
!==
-
1
)
{
callbacks
[
names
[
n
]].
splice
(
index
,
1
);
}
}
}
}
};
/**
* Returns callback array index.
*
* @param {String} name Event name.
* @param {Function} fn Function
*
* @return {Int} Callback array index, or -1 if isn't registered.
*/
function
callbackIndex
(
name
,
fn
)
{
for
(
var
i
=
0
,
l
=
callbacks
[
name
].
length
;
i
<
l
;
i
++
)
{
if
(
callbacks
[
name
][
i
]
===
fn
)
{
return
i
;
}
}
return
-
1
;
}
/**
* Reset next cycle timeout.
*
* @return {Void}
*/
function
resetCycle
()
{
if
(
dragging
.
released
&&
!
self
.
isPaused
)
{
self
.
resume
();
}
}
/**
* Calculate SLIDEE representation of handle position.
*
* @param {Int} handlePos
*
* @return {Int}
*/
function
handleToSlidee
(
handlePos
)
{
return
round
(
within
(
handlePos
,
hPos
.
start
,
hPos
.
end
)
/
hPos
.
end
*
(
pos
.
end
-
pos
.
start
))
+
pos
.
start
;
}
/**
* Keeps track of a dragging delta history.
*
* @return {Void}
*/
function
draggingHistoryTick
()
{
// Looking at this, I know what you're thinking :) But as we need only 4 history states, doing it this way
// as opposed to a proper loop is ~25 bytes smaller (when minified with GCC), a lot faster, and doesn't
// generate garbage. The loop version would create 2 new variables on every tick. Unexaptable!
dragging
.
history
[
0
]
=
dragging
.
history
[
1
];
dragging
.
history
[
1
]
=
dragging
.
history
[
2
];
dragging
.
history
[
2
]
=
dragging
.
history
[
3
];
dragging
.
history
[
3
]
=
dragging
.
delta
;
}
/**
* Initialize continuous movement.
*
* @return {Void}
*/
function
continuousInit
(
source
)
{
dragging
.
released
=
0
;
dragging
.
source
=
source
;
dragging
.
slidee
=
source
===
'slidee'
;
}
/**
* Dragging initiator.
*
* @param {Event} event
*
* @return {Void}
*/
function
dragInit
(
event
)
{
var
isTouch
=
event
.
type
===
'touchstart'
;
var
source
=
event
.
data
.
source
;
var
isSlidee
=
source
===
'slidee'
;
// Ignore when already in progress, or interactive element in non-touch navivagion
if
(
dragging
.
init
||
!
isTouch
&&
isInteractive
(
event
.
target
))
{
return
;
}
// Handle dragging conditions
if
(
source
===
'handle'
&&
(
!
o
.
dragHandle
||
hPos
.
start
===
hPos
.
end
))
{
return
;
}
// SLIDEE dragging conditions
if
(
isSlidee
&&
!
(
isTouch
?
o
.
touchDragging
:
o
.
mouseDragging
&&
event
.
which
<
2
))
{
return
;
}
if
(
!
isTouch
)
{
// prevents native image dragging in Firefox
stopDefault
(
event
);
}
// Reset dragging object
continuousInit
(
source
);
// Properties used in dragHandler
dragging
.
init
=
0
;
dragging
.
$source
=
$
(
event
.
target
);
dragging
.
touch
=
isTouch
;
dragging
.
pointer
=
isTouch
?
event
.
originalEvent
.
touches
[
0
]
:
event
;
dragging
.
initX
=
dragging
.
pointer
.
pageX
;
dragging
.
initY
=
dragging
.
pointer
.
pageY
;
dragging
.
initPos
=
isSlidee
?
pos
.
cur
:
hPos
.
cur
;
dragging
.
start
=
+
new
Date
();
dragging
.
time
=
0
;
dragging
.
path
=
0
;
dragging
.
delta
=
0
;
dragging
.
locked
=
0
;
dragging
.
history
=
[
0
,
0
,
0
,
0
];
dragging
.
pathToLock
=
isSlidee
?
isTouch
?
30
:
10
:
0
;
// Bind dragging events
$doc
.
on
(
isTouch
?
dragTouchEvents
:
dragMouseEvents
,
dragHandler
);
// Pause ongoing cycle
self
.
pause
(
1
);
// Add dragging class
(
isSlidee
?
$slidee
:
$handle
).
addClass
(
o
.
draggedClass
);
// Trigger moveStart event
trigger
(
'moveStart'
);
// Keep track of a dragging path history. This is later used in the
// dragging release swing calculation when dragging SLIDEE.
if
(
isSlidee
)
{
historyID
=
setInterval
(
draggingHistoryTick
,
10
);
}
}
/**
* Handler for dragging scrollbar handle or SLIDEE.
*
* @param {Event} event
*
* @return {Void}
*/
function
dragHandler
(
event
)
{
dragging
.
released
=
event
.
type
===
'mouseup'
||
event
.
type
===
'touchend'
;
dragging
.
pointer
=
dragging
.
touch
?
event
.
originalEvent
[
dragging
.
released
?
'changedTouches'
:
'touches'
][
0
]
:
event
;
dragging
.
pathX
=
dragging
.
pointer
.
pageX
-
dragging
.
initX
;
dragging
.
pathY
=
dragging
.
pointer
.
pageY
-
dragging
.
initY
;
dragging
.
path
=
sqrt
(
pow
(
dragging
.
pathX
,
2
)
+
pow
(
dragging
.
pathY
,
2
));
dragging
.
delta
=
o
.
horizontal
?
dragging
.
pathX
:
dragging
.
pathY
;
if
(
!
dragging
.
released
&&
dragging
.
path
<
1
)
return
;
// We haven't decided whether this is a drag or not...
if
(
!
dragging
.
init
)
{
// If the drag path was very short, maybe it's not a drag?
if
(
dragging
.
path
<
o
.
dragThreshold
)
{
// If the pointer was released, the path will not become longer and it's
// definitely not a drag. If not released yet, decide on next iteration
return
dragging
.
released
?
dragEnd
()
:
undefined
;
}
else
{
// If dragging path is sufficiently long we can confidently start a drag
// if drag is in different direction than scroll, ignore it
if
(
o
.
horizontal
?
abs
(
dragging
.
pathX
)
>
abs
(
dragging
.
pathY
)
:
abs
(
dragging
.
pathX
)
<
abs
(
dragging
.
pathY
))
{
dragging
.
init
=
1
;
}
else
{
return
dragEnd
();
}
}
}
stopDefault
(
event
);
// Disable click on a source element, as it is unwelcome when dragging
if
(
!
dragging
.
locked
&&
dragging
.
path
>
dragging
.
pathToLock
&&
dragging
.
slidee
)
{
dragging
.
locked
=
1
;
dragging
.
$source
.
on
(
clickEvent
,
disableOneEvent
);
}
// Cancel dragging on release
if
(
dragging
.
released
)
{
dragEnd
();
// Adjust path with a swing on mouse release
if
(
o
.
releaseSwing
&&
dragging
.
slidee
)
{
dragging
.
swing
=
(
dragging
.
delta
-
dragging
.
history
[
0
])
/
40
*
300
;
dragging
.
delta
+=
dragging
.
swing
;
dragging
.
tweese
=
abs
(
dragging
.
swing
)
>
10
;
}
}
slideTo
(
dragging
.
slidee
?
round
(
dragging
.
initPos
-
dragging
.
delta
)
:
handleToSlidee
(
dragging
.
initPos
+
dragging
.
delta
));
}
/**
* Stops dragging and cleans up after it.
*
* @return {Void}
*/
function
dragEnd
()
{
clearInterval
(
historyID
);
dragging
.
released
=
true
;
$doc
.
off
(
dragging
.
touch
?
dragTouchEvents
:
dragMouseEvents
,
dragHandler
);
(
dragging
.
slidee
?
$slidee
:
$handle
).
removeClass
(
o
.
draggedClass
);
// Make sure that disableOneEvent is not active in next tick.
setTimeout
(
function
()
{
dragging
.
$source
.
off
(
clickEvent
,
disableOneEvent
);
});
// Normally, this is triggered in render(), but if there
// is nothing to render, we have to do it manually here.
if
(
pos
.
cur
===
pos
.
dest
&&
dragging
.
init
)
{
trigger
(
'moveEnd'
);
}
// Resume ongoing cycle
self
.
resume
(
1
);
dragging
.
init
=
0
;
}
/**
* Check whether element is interactive.
*
* @return {Boolean}
*/
function
isInteractive
(
element
)
{
return
~
$
.
inArray
(
element
.
nodeName
,
o
.
interactiveElements
)
||
$
(
element
).
is
(
o
.
interactive
);
}
/**
* Continuous movement cleanup on mouseup.
*
* @return {Void}
*/
function
movementReleaseHandler
()
{
self
.
stop
();
$doc
.
off
(
'mouseup'
,
movementReleaseHandler
);
}
/**
* Buttons navigation handler.
*
* @param {Event} event
*
* @return {Void}
*/
function
buttonsHandler
(
event
)
{
/*jshint validthis:true */
stopDefault
(
event
);
switch
(
this
)
{
case
$forwardButton
[
0
]
:
case
$backwardButton
[
0
]
:
self
.
moveBy
(
$forwardButton
.
is
(
this
)
?
o
.
moveBy
:
-
o
.
moveBy
);
$doc
.
on
(
'mouseup'
,
movementReleaseHandler
);
break
;
case
$prevButton
[
0
]
:
self
.
prev
();
break
;
case
$nextButton
[
0
]
:
self
.
next
();
break
;
case
$prevPageButton
[
0
]
:
self
.
prevPage
();
break
;
case
$nextPageButton
[
0
]
:
self
.
nextPage
();
break
;
}
}
/**
* Mouse wheel delta normalization.
*
* @param {Event} event
*
* @return {Int}
*/
function
normalizeWheelDelta
(
event
)
{
// wheelDelta needed only for IE8-
scrolling
.
curDelta
=
((
o
.
horizontal
?
event
.
deltaY
||
event
.
deltaX
:
event
.
deltaY
)
||
-
event
.
wheelDelta
);
scrolling
.
curDelta
/=
event
.
deltaMode
===
1
?
3
:
100
;
if
(
!
itemNav
)
{
return
scrolling
.
curDelta
;
}
time
=
+
new
Date
();
if
(
scrolling
.
last
<
time
-
scrolling
.
resetTime
)
{
scrolling
.
delta
=
0
;
}
scrolling
.
last
=
time
;
scrolling
.
delta
+=
scrolling
.
curDelta
;
if
(
abs
(
scrolling
.
delta
)
<
1
)
{
scrolling
.
finalDelta
=
0
;
}
else
{
scrolling
.
finalDelta
=
round
(
scrolling
.
delta
/
1
);
scrolling
.
delta
%=
1
;
}
return
scrolling
.
finalDelta
;
}
/**
* Mouse scrolling handler.
*
* @param {Event} event
*
* @return {Void}
*/
function
scrollHandler
(
event
)
{
// Mark event as originating in a Sly instance
event
.
originalEvent
[
namespace
]
=
self
;
// Don't hijack global scrolling
var
time
=
+
new
Date
();
if
(
lastGlobalWheel
+
o
.
scrollHijack
>
time
&&
$scrollSource
[
0
]
!==
document
&&
$scrollSource
[
0
]
!==
window
)
{
lastGlobalWheel
=
time
;
return
;
}
// Ignore if there is no scrolling to be done
if
(
!
o
.
scrollBy
||
pos
.
start
===
pos
.
end
)
{
return
;
}
var
delta
=
normalizeWheelDelta
(
event
.
originalEvent
);
// Trap scrolling only when necessary and/or requested
if
(
o
.
scrollTrap
||
delta
>
0
&&
pos
.
dest
<
pos
.
end
||
delta
<
0
&&
pos
.
dest
>
pos
.
start
)
{
stopDefault
(
event
,
1
);
}
self
.
slideBy
(
o
.
scrollBy
*
delta
);
}
/**
* Scrollbar click handler.
*
* @param {Event} event
*
* @return {Void}
*/
function
scrollbarHandler
(
event
)
{
// Only clicks on scroll bar. Ignore the handle.
if
(
o
.
clickBar
&&
event
.
target
===
$sb
[
0
])
{
stopDefault
(
event
);
// Calculate new handle position and sync SLIDEE to it
slideTo
(
handleToSlidee
((
o
.
horizontal
?
event
.
pageX
-
$sb
.
offset
().
left
:
event
.
pageY
-
$sb
.
offset
().
top
)
-
handleSize
/
2
));
}
}
/**
* Keyboard input handler.
*
* @param {Event} event
*
* @return {Void}
*/
function
keyboardHandler
(
event
)
{
if
(
!
o
.
keyboardNavBy
)
{
return
;
}
switch
(
event
.
which
)
{
// Left or Up
case
o
.
horizontal
?
37
:
38
:
stopDefault
(
event
);
self
[
o
.
keyboardNavBy
===
'pages'
?
'prevPage'
:
'prev'
]();
break
;
// Right or Down
case
o
.
horizontal
?
39
:
40
:
stopDefault
(
event
);
self
[
o
.
keyboardNavBy
===
'pages'
?
'nextPage'
:
'next'
]();
break
;
}
}
/**
* Click on item activation handler.
*
* @param {Event} event
*
* @return {Void}
*/
function
activateHandler
(
event
)
{
/*jshint validthis:true */
// Ignore clicks on interactive elements.
if
(
isInteractive
(
this
))
{
event
.
originalEvent
[
namespace
+
'ignore'
]
=
true
;
return
;
}
// Ignore events that:
// - are not originating from direct SLIDEE children
// - originated from interactive elements
if
(
this
.
parentNode
!==
$slidee
[
0
]
||
event
.
originalEvent
[
namespace
+
'ignore'
])
return
;
self
.
activate
(
this
);
}
/**
* Click on page button handler.
*
* @param {Event} event
*
* @return {Void}
*/
function
activatePageHandler
()
{
/*jshint validthis:true */
// Accept only events from direct pages bar children.
if
(
this
.
parentNode
===
$pb
[
0
])
{
self
.
activatePage
(
$pages
.
index
(
this
));
}
}
/**
* Pause on hover handler.
*
* @param {Event} event
*
* @return {Void}
*/
function
pauseOnHoverHandler
(
event
)
{
if
(
o
.
pauseOnHover
)
{
self
[
event
.
type
===
'mouseenter'
?
'pause'
:
'resume'
](
2
);
}
}
/**
* Trigger callbacks for event.
*
* @param {String} name Event name.
* @param {Mixed} argX Arguments passed to callbacks.
*
* @return {Void}
*/
function
trigger
(
name
,
arg1
)
{
if
(
callbacks
[
name
])
{
l
=
callbacks
[
name
].
length
;
// Callbacks will be stored and executed from a temporary array to not
// break the execution queue when one of the callbacks unbinds itself.
tmpArray
.
length
=
0
;
for
(
i
=
0
;
i
<
l
;
i
++
)
{
tmpArray
.
push
(
callbacks
[
name
][
i
]);
}
// Execute the callbacks
for
(
i
=
0
;
i
<
l
;
i
++
)
{
tmpArray
[
i
].
call
(
self
,
name
,
arg1
);
}
}
}
/**
* Destroys instance and everything it created.
*
* @return {Void}
*/
self
.
destroy
=
function
()
{
// Remove the reference to itself
Sly
.
removeInstance
(
frame
);
// Unbind all events
$scrollSource
.
add
(
$handle
)
.
add
(
$sb
)
.
add
(
$pb
)
.
add
(
$forwardButton
)
.
add
(
$backwardButton
)
.
add
(
$prevButton
)
.
add
(
$nextButton
)
.
add
(
$prevPageButton
)
.
add
(
$nextPageButton
)
.
off
(
'.'
+
namespace
);
// Unbinding specifically as to not nuke out other instances
$doc
.
off
(
'keydown'
,
keyboardHandler
);
// Remove classes
$prevButton
.
add
(
$nextButton
)
.
add
(
$prevPageButton
)
.
add
(
$nextPageButton
)
.
removeClass
(
o
.
disabledClass
);
if
(
$items
&&
rel
.
activeItem
!=
null
)
{
$items
.
eq
(
rel
.
activeItem
).
removeClass
(
o
.
activeClass
);
}
// Remove page items
$pb
.
empty
();
if
(
!
parallax
)
{
// Unbind events from frame
$frame
.
off
(
'.'
+
namespace
);
// Restore original styles
frameStyles
.
restore
();
slideeStyles
.
restore
();
sbStyles
.
restore
();
handleStyles
.
restore
();
// Remove the instance from element data storage
$
.
removeData
(
frame
,
namespace
);
}
// Clean up collections
items
.
length
=
pages
.
length
=
0
;
last
=
{};
// Reset initialized status and return the instance
self
.
initialized
=
0
;
return
self
;
};
/**
* Initialize.
*
* @return {Object}
*/
self
.
init
=
function
()
{
if
(
self
.
initialized
)
{
return
;
}
// Disallow multiple instances on the same element
if
(
Sly
.
getInstance
(
frame
))
throw
new
Error
(
'There is already a Sly instance on this element'
);
// Store the reference to itself
Sly
.
storeInstance
(
frame
,
self
);
// Register callbacks map
self
.
on
(
callbackMap
);
// Save styles
var
holderProps
=
[
'overflow'
,
'position'
];
var
movableProps
=
[
'position'
,
'webkitTransform'
,
'msTransform'
,
'transform'
,
'left'
,
'top'
,
'width'
,
'height'
];
frameStyles
.
save
.
apply
(
frameStyles
,
holderProps
);
sbStyles
.
save
.
apply
(
sbStyles
,
holderProps
);
slideeStyles
.
save
.
apply
(
slideeStyles
,
movableProps
);
handleStyles
.
save
.
apply
(
handleStyles
,
movableProps
);
// Set required styles
var
$movables
=
$handle
;
if
(
!
parallax
)
{
$movables
=
$movables
.
add
(
$slidee
);
$frame
.
css
(
'overflow'
,
'hidden'
);
if
(
!
transform
&&
$frame
.
css
(
'position'
)
===
'static'
)
{
$frame
.
css
(
'position'
,
'relative'
);
}
}
if
(
transform
)
{
if
(
gpuAcceleration
)
{
$movables
.
css
(
transform
,
gpuAcceleration
);
}
}
else
{
if
(
$sb
.
css
(
'position'
)
===
'static'
)
{
$sb
.
css
(
'position'
,
'relative'
);
}
$movables
.
css
({
position
:
'absolute'
});
}
// Navigation buttons
if
(
o
.
forward
)
{
$forwardButton
.
on
(
mouseDownEvent
,
buttonsHandler
);
}
if
(
o
.
backward
)
{
$backwardButton
.
on
(
mouseDownEvent
,
buttonsHandler
);
}
if
(
o
.
prev
)
{
$prevButton
.
on
(
clickEvent
,
buttonsHandler
);
}
if
(
o
.
next
)
{
$nextButton
.
on
(
clickEvent
,
buttonsHandler
);
}
if
(
o
.
prevPage
)
{
$prevPageButton
.
on
(
clickEvent
,
buttonsHandler
);
}
if
(
o
.
nextPage
)
{
$nextPageButton
.
on
(
clickEvent
,
buttonsHandler
);
}
// Scrolling navigation
$scrollSource
.
on
(
wheelEvent
,
scrollHandler
);
// Clicking on scrollbar navigation
if
(
$sb
[
0
])
{
$sb
.
on
(
clickEvent
,
scrollbarHandler
);
}
// Click on items navigation
if
(
itemNav
&&
o
.
activateOn
)
{
$frame
.
on
(
o
.
activateOn
+
'.'
+
namespace
,
'*'
,
activateHandler
);
}
// Pages navigation
if
(
$pb
[
0
]
&&
o
.
activatePageOn
)
{
$pb
.
on
(
o
.
activatePageOn
+
'.'
+
namespace
,
'*'
,
activatePageHandler
);
}
// Dragging navigation
$dragSource
.
on
(
dragInitEvents
,
{
source
:
'slidee'
},
dragInit
);
// Scrollbar dragging navigation
if
(
$handle
)
{
$handle
.
on
(
dragInitEvents
,
{
source
:
'handle'
},
dragInit
);
}
// Keyboard navigation
$doc
.
on
(
'keydown'
,
keyboardHandler
);
if
(
!
parallax
)
{
// Pause on hover
$frame
.
on
(
'mouseenter.'
+
namespace
+
' mouseleave.'
+
namespace
,
pauseOnHoverHandler
);
// Reset native FRAME element scroll
$frame
.
on
(
'scroll.'
+
namespace
,
resetScroll
);
}
// Mark instance as initialized
self
.
initialized
=
1
;
// Load
load
(
true
);
// Initiate automatic cycling
if
(
o
.
cycleBy
&&
!
parallax
)
{
self
[
o
.
startPaused
?
'pause'
:
'resume'
]();
}
// Return instance
return
self
;
};
}
Sly
.
getInstance
=
function
(
element
)
{
return
$
.
data
(
element
,
namespace
);
};
Sly
.
storeInstance
=
function
(
element
,
sly
)
{
return
$
.
data
(
element
,
namespace
,
sly
);
};
Sly
.
removeInstance
=
function
(
element
)
{
return
$
.
removeData
(
element
,
namespace
);
};
/**
* Return type of the value.
*
* @param {Mixed} value
*
* @return {String}
*/
function
type
(
value
)
{
if
(
value
==
null
)
{
return
String
(
value
);
}
if
(
typeof
value
===
'object'
||
typeof
value
===
'function'
)
{
return
Object
.
prototype
.
toString
.
call
(
value
).
match
(
/\s([a-z]+)/i
)[
1
].
toLowerCase
()
||
'object'
;
}
return
typeof
value
;
}
/**
* Event preventDefault & stopPropagation helper.
*
* @param {Event} event Event object.
* @param {Bool} noBubbles Cancel event bubbling.
*
* @return {Void}
*/
function
stopDefault
(
event
,
noBubbles
)
{
event
.
preventDefault
();
if
(
noBubbles
)
{
event
.
stopPropagation
();
}
}
/**
* Disables an event it was triggered on and unbinds itself.
*
* @param {Event} event
*
* @return {Void}
*/
function
disableOneEvent
(
event
)
{
/*jshint validthis:true */
stopDefault
(
event
,
1
);
$
(
this
).
off
(
event
.
type
,
disableOneEvent
);
}
/**
* Resets native element scroll values to 0.
*
* @return {Void}
*/
function
resetScroll
()
{
/*jshint validthis:true */
this
.
scrollLeft
=
0
;
this
.
scrollTop
=
0
;
}
/**
* Check if variable is a number.
*
* @param {Mixed} value
*
* @return {Boolean}
*/
function
isNumber
(
value
)
{
return
!
isNaN
(
parseFloat
(
value
))
&&
isFinite
(
value
);
}
/**
* Parse style to pixels.
*
* @param {Object} $item jQuery object with element.
* @param {Property} property CSS property to get the pixels from.
*
* @return {Int}
*/
function
getPx
(
$item
,
property
)
{
return
0
|
round
(
String
(
$item
.
css
(
property
)).
replace
(
/[^\-0-9.]/g
,
''
));
}
/**
* Make sure that number is within the limits.
*
* @param {Number} number
* @param {Number} min
* @param {Number} max
*
* @return {Number}
*/
function
within
(
number
,
min
,
max
)
{
return
number
<
min
?
min
:
number
>
max
?
max
:
number
;
}
/**
* Saves element styles for later restoration.
*
* Example:
* var styles = new StyleRestorer(frame);
* styles.save('position');
* element.style.position = 'absolute';
* styles.restore(); // restores to state before the assignment above
*
* @param {Element} element
*/
function
StyleRestorer
(
element
)
{
var
self
=
{};
self
.
style
=
{};
self
.
save
=
function
()
{
if
(
!
element
||
!
element
.
nodeType
)
return
;
for
(
var
i
=
0
;
i
<
arguments
.
length
;
i
++
)
{
self
.
style
[
arguments
[
i
]]
=
element
.
style
[
arguments
[
i
]];
}
return
self
;
};
self
.
restore
=
function
()
{
if
(
!
element
||
!
element
.
nodeType
)
return
;
for
(
var
prop
in
self
.
style
)
{
if
(
self
.
style
.
hasOwnProperty
(
prop
))
element
.
style
[
prop
]
=
self
.
style
[
prop
];
}
return
self
;
};
return
self
;
}
// Local WindowAnimationTiming interface polyfill
(
function
(
w
)
{
rAF
=
w
.
requestAnimationFrame
||
w
.
webkitRequestAnimationFrame
||
fallback
;
/**
* Fallback implementation.
*/
var
prev
=
new
Date
().
getTime
();
function
fallback
(
fn
)
{
var
curr
=
new
Date
().
getTime
();
var
ms
=
Math
.
max
(
0
,
16
-
(
curr
-
prev
));
var
req
=
setTimeout
(
fn
,
ms
);
prev
=
curr
;
return
req
;
}
/**
* Cancel.
*/
var
cancel
=
w
.
cancelAnimationFrame
||
w
.
webkitCancelAnimationFrame
||
w
.
clearTimeout
;
cAF
=
function
(
id
){
cancel
.
call
(
w
,
id
);
};
}(
window
));
// Feature detects
(
function
()
{
var
prefixes
=
[
''
,
'Webkit'
,
'Moz'
,
'ms'
,
'O'
];
var
el
=
document
.
createElement
(
'div'
);
function
testProp
(
prop
)
{
for
(
var
p
=
0
,
pl
=
prefixes
.
length
;
p
<
pl
;
p
++
)
{
var
prefixedProp
=
prefixes
[
p
]
?
prefixes
[
p
]
+
prop
.
charAt
(
0
).
toUpperCase
()
+
prop
.
slice
(
1
)
:
prop
;
if
(
el
.
style
[
prefixedProp
]
!=
null
)
{
return
prefixedProp
;
}
}
}
// Global support indicators
transform
=
testProp
(
'transform'
);
gpuAcceleration
=
testProp
(
'perspective'
)
?
'translateZ(0) '
:
''
;
}());
// Expose class globally
w
[
className
]
=
Sly
;
// jQuery proxy
$
.
fn
[
pluginName
]
=
function
(
options
,
callbackMap
)
{
var
method
,
methodArgs
;
// Attributes logic
if
(
!
$
.
isPlainObject
(
options
))
{
if
(
type
(
options
)
===
'string'
||
options
===
false
)
{
method
=
options
===
false
?
'destroy'
:
options
;
methodArgs
=
Array
.
prototype
.
slice
.
call
(
arguments
,
1
);
}
options
=
{};
}
// Apply to all elements
return
this
.
each
(
function
(
i
,
element
)
{
// Call with prevention against multiple instantiations
var
plugin
=
Sly
.
getInstance
(
element
);
if
(
!
plugin
&&
!
method
)
{
// Create a new object if it doesn't exist yet
plugin
=
new
Sly
(
element
,
options
,
callbackMap
).
init
();
}
else
if
(
plugin
&&
method
)
{
// Call method
if
(
plugin
[
method
])
{
plugin
[
method
].
apply
(
plugin
,
methodArgs
);
}
}
});
};
// Default options
Sly
.
defaults
=
{
slidee
:
null
,
// Selector, DOM element, or jQuery object with DOM element representing SLIDEE.
horizontal
:
false
,
// Switch to horizontal mode.
// Item based navigation
itemNav
:
null
,
// Item navigation type. Can be: 'basic', 'centered', 'forceCentered'.
itemSelector
:
null
,
// Select only items that match this selector.
smart
:
false
,
// Repositions the activated item to help with further navigation.
activateOn
:
null
,
// Activate an item on this event. Can be: 'click', 'mouseenter', ...
activateMiddle
:
false
,
// Always activate the item in the middle of the FRAME. forceCentered only.
// Scrolling
scrollSource
:
null
,
// Element for catching the mouse wheel scrolling. Default is FRAME.
scrollBy
:
0
,
// Pixels or items to move per one mouse scroll. 0 to disable scrolling.
scrollHijack
:
300
,
// Milliseconds since last wheel event after which it is acceptable to hijack global scroll.
scrollTrap
:
false
,
// Don't bubble scrolling when hitting scrolling limits.
// Dragging
dragSource
:
null
,
// Selector or DOM element for catching dragging events. Default is FRAME.
mouseDragging
:
false
,
// Enable navigation by dragging the SLIDEE with mouse cursor.
touchDragging
:
false
,
// Enable navigation by dragging the SLIDEE with touch events.
releaseSwing
:
false
,
// Ease out on dragging swing release.
swingSpeed
:
0.2
,
// Swing synchronization speed, where: 1 = instant, 0 = infinite.
elasticBounds
:
false
,
// Stretch SLIDEE position limits when dragging past FRAME boundaries.
dragThreshold
:
3
,
// Distance in pixels before Sly recognizes dragging.
interactive
:
null
,
// Selector for special interactive elements.
interactiveElements
:
[
'INPUT'
,
'SELECT'
,
'BUTTON'
,
'TEXTAREA'
],
// Scrollbar
scrollBar
:
null
,
// Selector or DOM element for scrollbar container.
dragHandle
:
false
,
// Whether the scrollbar handle should be draggable.
dynamicHandle
:
false
,
// Scrollbar handle represents the ratio between hidden and visible content.
minHandleSize
:
50
,
// Minimal height or width (depends on sly direction) of a handle in pixels.
clickBar
:
false
,
// Enable navigation by clicking on scrollbar.
syncSpeed
:
0.5
,
// Handle => SLIDEE synchronization speed, where: 1 = instant, 0 = infinite.
// Pagesbar
pagesBar
:
null
,
// Selector or DOM element for pages bar container.
activatePageOn
:
null
,
// Event used to activate page. Can be: click, mouseenter, ...
pageBuilder
:
// Page item generator.
function
(
index
)
{
return
'<li>'
+
(
index
+
1
)
+
'</li>'
;
},
// Navigation buttons
forward
:
null
,
// Selector or DOM element for "forward movement" button.
backward
:
null
,
// Selector or DOM element for "backward movement" button.
prev
:
null
,
// Selector or DOM element for "previous item" button.
next
:
null
,
// Selector or DOM element for "next item" button.
prevPage
:
null
,
// Selector or DOM element for "previous page" button.
nextPage
:
null
,
// Selector or DOM element for "next page" button.
// Automated cycling
cycleBy
:
null
,
// Enable automatic cycling by 'items' or 'pages'.
cycleInterval
:
5000
,
// Delay between cycles in milliseconds.
pauseOnHover
:
false
,
// Pause cycling when mouse hovers over the FRAME.
startPaused
:
false
,
// Whether to start in paused sate.
// Mixed options
moveBy
:
300
,
// Speed in pixels per second used by forward and backward buttons.
speed
:
0
,
// Animations speed in milliseconds. 0 to disable animations.
easing
:
'swing'
,
// Easing for duration based (tweening) animations.
startAt
:
null
,
// Starting offset in pixels or items.
keyboardNavBy
:
null
,
// Enable keyboard navigation by 'items' or 'pages'.
// Classes
draggedClass
:
'dragged'
,
// Class for dragged elements (like SLIDEE or scrollbar handle).
activeClass
:
'active'
,
// Class for active items and pages.
disabledClass
:
'disabled'
// Class for disabled navigation elements.
};
//Export module for nodejs browserify
if
(
typeof
exports
===
'object'
)
{
module
.
exports
=
Sly
;
}
}(
jQuery
,
window
));
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 7, 04:34 (17 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4251618
Default Alt Text
sly.js (75 KB)
Attached To
Mode
rLAUNCH Launch website
Attached
Detach File
Event Timeline
Log In to Comment