root / snf-cyclades-app / synnefo / ui / new_ui / ui / javascripts / jquery.scrollintoview.js @ 0467b6cd
History | View | Annotate | Download (6.6 kB)
1 |
/*!
|
---|---|
2 |
* jQuery scrollintoview() plugin and :scrollable selector filter
|
3 |
*
|
4 |
* Version 1.8 (14 Jul 2011)
|
5 |
* Requires jQuery 1.4 or newer
|
6 |
*
|
7 |
* Copyright (c) 2011 Robert Koritnik
|
8 |
* Licensed under the terms of the MIT license
|
9 |
* http://www.opensource.org/licenses/mit-license.php
|
10 |
*/
|
11 |
|
12 |
(function ($) { |
13 |
var converter = {
|
14 |
vertical: { x: false, y: true }, |
15 |
horizontal: { x: true, y: false }, |
16 |
both: { x: true, y: true }, |
17 |
x: { x: true, y: false }, |
18 |
y: { x: false, y: true } |
19 |
}; |
20 |
|
21 |
var settings = {
|
22 |
duration: "fast", |
23 |
direction: "both" |
24 |
}; |
25 |
|
26 |
var rootrx = /^(?:html)$/i; |
27 |
|
28 |
// gets border dimensions
|
29 |
var borders = function (domElement, styles) { |
30 |
styles = styles || (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(domElement, null) : domElement.currentStyle);
|
31 |
var px = document.defaultView && document.defaultView.getComputedStyle ? true : false; |
32 |
var b = {
|
33 |
top: (parseFloat(px ? styles.borderTopWidth : $.css(domElement, "borderTopWidth")) || 0), |
34 |
left: (parseFloat(px ? styles.borderLeftWidth : $.css(domElement, "borderLeftWidth")) || 0), |
35 |
bottom: (parseFloat(px ? styles.borderBottomWidth : $.css(domElement, "borderBottomWidth")) || 0), |
36 |
right: (parseFloat(px ? styles.borderRightWidth : $.css(domElement, "borderRightWidth")) || 0) |
37 |
}; |
38 |
return {
|
39 |
top: b.top,
|
40 |
left: b.left,
|
41 |
bottom: b.bottom,
|
42 |
right: b.right,
|
43 |
vertical: b.top + b.bottom,
|
44 |
horizontal: b.left + b.right
|
45 |
}; |
46 |
}; |
47 |
|
48 |
var dimensions = function ($element) { |
49 |
var win = $(window); |
50 |
var isRoot = rootrx.test($element[0].nodeName); |
51 |
return {
|
52 |
border: isRoot ? { top: 0, left: 0, bottom: 0, right: 0} : borders($element[0]), |
53 |
scroll: {
|
54 |
top: (isRoot ? win : $element).scrollTop(), |
55 |
left: (isRoot ? win : $element).scrollLeft() |
56 |
}, |
57 |
scrollbar: {
|
58 |
right: isRoot ? 0 : $element.innerWidth() - $element[0].clientWidth, |
59 |
bottom: isRoot ? 0 : $element.innerHeight() - $element[0].clientHeight |
60 |
}, |
61 |
rect: (function () { |
62 |
var r = $element[0].getBoundingClientRect(); |
63 |
return {
|
64 |
top: isRoot ? 0 : r.top, |
65 |
left: isRoot ? 0 : r.left, |
66 |
bottom: isRoot ? $element[0].clientHeight : r.bottom, |
67 |
right: isRoot ? $element[0].clientWidth : r.right |
68 |
}; |
69 |
})() |
70 |
}; |
71 |
}; |
72 |
|
73 |
$.fn.extend({
|
74 |
scrollintoview: function (options) { |
75 |
/// <summary>Scrolls the first element in the set into view by scrolling its closest scrollable parent.</summary>
|
76 |
/// <param name="options" type="Object">Additional options that can configure scrolling:
|
77 |
/// duration (default: "fast") - jQuery animation speed (can be a duration string or number of milliseconds)
|
78 |
/// direction (default: "both") - select possible scrollings ("vertical" or "y", "horizontal" or "x", "both")
|
79 |
/// complete (default: none) - a function to call when scrolling completes (called in context of the DOM element being scrolled)
|
80 |
/// </param>
|
81 |
/// <return type="jQuery">Returns the same jQuery set that this function was run on.</return>
|
82 |
|
83 |
options = $.extend({}, settings, options);
|
84 |
options.direction = converter[typeof (options.direction) === "string" && options.direction.toLowerCase()] || converter.both; |
85 |
|
86 |
var dirStr = ""; |
87 |
if (options.direction.x === true) dirStr = "horizontal"; |
88 |
if (options.direction.y === true) dirStr = dirStr ? "both" : "vertical"; |
89 |
|
90 |
var el = this.eq(0); |
91 |
var scroller = el.closest(":scrollable(" + dirStr + ")"); |
92 |
|
93 |
// check if there's anything to scroll in the first place
|
94 |
if (scroller.length > 0) |
95 |
{ |
96 |
scroller = scroller.eq(0);
|
97 |
|
98 |
var dim = {
|
99 |
e: dimensions(el),
|
100 |
s: dimensions(scroller)
|
101 |
}; |
102 |
|
103 |
var rel = {
|
104 |
top: dim.e.rect.top - (dim.s.rect.top + dim.s.border.top),
|
105 |
bottom: dim.s.rect.bottom - dim.s.border.bottom - dim.s.scrollbar.bottom - dim.e.rect.bottom,
|
106 |
left: dim.e.rect.left - (dim.s.rect.left + dim.s.border.left),
|
107 |
right: dim.s.rect.right - dim.s.border.right - dim.s.scrollbar.right - dim.e.rect.right
|
108 |
}; |
109 |
|
110 |
var animOptions = {};
|
111 |
|
112 |
// vertical scroll
|
113 |
if (options.direction.y === true) |
114 |
{ |
115 |
if (rel.top < 0) |
116 |
{ |
117 |
animOptions.scrollTop = dim.s.scroll.top + rel.top; |
118 |
} |
119 |
else if (rel.top > 0 && rel.bottom < 0) |
120 |
{ |
121 |
animOptions.scrollTop = dim.s.scroll.top + Math.min(rel.top, -rel.bottom); |
122 |
} |
123 |
} |
124 |
|
125 |
// horizontal scroll
|
126 |
if (options.direction.x === true) |
127 |
{ |
128 |
if (rel.left < 0) |
129 |
{ |
130 |
animOptions.scrollLeft = dim.s.scroll.left + rel.left; |
131 |
} |
132 |
else if (rel.left > 0 && rel.right < 0) |
133 |
{ |
134 |
animOptions.scrollLeft = dim.s.scroll.left + Math.min(rel.left, -rel.right); |
135 |
} |
136 |
} |
137 |
|
138 |
// scroll if needed
|
139 |
if (!$.isEmptyObject(animOptions)) |
140 |
{ |
141 |
if (rootrx.test(scroller[0].nodeName)) |
142 |
{ |
143 |
scroller = $("html,body"); |
144 |
} |
145 |
scroller |
146 |
.animate(animOptions, options.duration) |
147 |
.eq(0) // we want function to be called just once (ref. "html,body") |
148 |
.queue(function (next) {
|
149 |
$.isFunction(options.complete) && options.complete.call(scroller[0]); |
150 |
next(); |
151 |
}); |
152 |
} |
153 |
else
|
154 |
{ |
155 |
// when there's nothing to scroll, just call the "complete" function
|
156 |
$.isFunction(options.complete) && options.complete.call(scroller[0]); |
157 |
} |
158 |
} |
159 |
|
160 |
// return set back
|
161 |
return this; |
162 |
} |
163 |
}); |
164 |
|
165 |
var scrollValue = {
|
166 |
auto: true, |
167 |
scroll: true, |
168 |
visible: false, |
169 |
hidden: false |
170 |
}; |
171 |
|
172 |
$.extend($.expr[":"], { |
173 |
scrollable: function (element, index, meta, stack) { |
174 |
var direction = converter[typeof (meta[3]) === "string" && meta[3].toLowerCase()] || converter.both; |
175 |
var styles = (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(element, null) : element.currentStyle); |
176 |
var overflow = {
|
177 |
x: scrollValue[styles.overflowX.toLowerCase()] || false, |
178 |
y: scrollValue[styles.overflowY.toLowerCase()] || false, |
179 |
isRoot: rootrx.test(element.nodeName)
|
180 |
}; |
181 |
|
182 |
// check if completely unscrollable (exclude HTML element because it's special)
|
183 |
if (!overflow.x && !overflow.y && !overflow.isRoot)
|
184 |
{ |
185 |
return false; |
186 |
} |
187 |
|
188 |
var size = {
|
189 |
height: {
|
190 |
scroll: element.scrollHeight,
|
191 |
client: element.clientHeight
|
192 |
}, |
193 |
width: {
|
194 |
scroll: element.scrollWidth,
|
195 |
client: element.clientWidth
|
196 |
}, |
197 |
// check overflow.x/y because iPad (and possibly other tablets) don't dislay scrollbars
|
198 |
scrollableX: function () { |
199 |
return (overflow.x || overflow.isRoot) && this.width.scroll > this.width.client; |
200 |
}, |
201 |
scrollableY: function () { |
202 |
return (overflow.y || overflow.isRoot) && this.height.scroll > this.height.client; |
203 |
} |
204 |
}; |
205 |
return direction.y && size.scrollableY() || direction.x && size.scrollableX();
|
206 |
} |
207 |
}); |
208 |
})(jQuery); |