yepkeynav-rails 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +6 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/javascripts/yepKeyNav/README.md +66 -0
  6. data/app/assets/javascripts/yepKeyNav/jquery.hotkeys.js +223 -0
  7. data/app/assets/javascripts/yepKeyNav/jquery.scrollTo-1.4.3.1.js +218 -0
  8. data/app/assets/javascripts/yepKeyNav/yepKeyNav.js +192 -0
  9. data/app/assets/javascripts/yepKeyNav.js +1 -0
  10. data/lib/tasks/yepkeynav-rails_tasks.rake +4 -0
  11. data/lib/yepkeynav-rails/engine.rb +5 -0
  12. data/lib/yepkeynav-rails/version.rb +3 -0
  13. data/lib/yepkeynav-rails.rb +4 -0
  14. data/test/dummy/README.rdoc +261 -0
  15. data/test/dummy/Rakefile +7 -0
  16. data/test/dummy/app/assets/javascripts/application.js +15 -0
  17. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  18. data/test/dummy/app/controllers/application_controller.rb +3 -0
  19. data/test/dummy/app/helpers/application_helper.rb +2 -0
  20. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  21. data/test/dummy/config/application.rb +59 -0
  22. data/test/dummy/config/boot.rb +10 -0
  23. data/test/dummy/config/database.yml +25 -0
  24. data/test/dummy/config/environment.rb +5 -0
  25. data/test/dummy/config/environments/development.rb +37 -0
  26. data/test/dummy/config/environments/production.rb +67 -0
  27. data/test/dummy/config/environments/test.rb +37 -0
  28. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  29. data/test/dummy/config/initializers/inflections.rb +15 -0
  30. data/test/dummy/config/initializers/mime_types.rb +5 -0
  31. data/test/dummy/config/initializers/secret_token.rb +7 -0
  32. data/test/dummy/config/initializers/session_store.rb +8 -0
  33. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  34. data/test/dummy/config/locales/en.yml +5 -0
  35. data/test/dummy/config/routes.rb +4 -0
  36. data/test/dummy/config.ru +4 -0
  37. data/test/dummy/public/404.html +26 -0
  38. data/test/dummy/public/422.html +26 -0
  39. data/test/dummy/public/500.html +25 -0
  40. data/test/dummy/public/favicon.ico +0 -0
  41. data/test/dummy/script/rails +6 -0
  42. data/test/integration/navigation_test.rb +10 -0
  43. data/test/test_helper.rb +15 -0
  44. data/test/yepkeynav-rails_test.rb +7 -0
  45. metadata +145 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ N2UwZGRhOTU0YThhYjAyMWRkMDRmYjYxZDUwZTlhMWQ4NDQyZDMxMA==
5
+ data.tar.gz: !binary |-
6
+ YWM1OTA0MTYxOWYzZmM3YjBiZGJkZDEyNzk5YjExMDIwYjYwOWEzZQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NjA4ZDg3YjYzMTc0ZGFkZmIzMmIyMGMxZGVjMGM2ZjZkMGYxY2ExOWRmZTkw
10
+ MTBlNmY3MzlmNzFmNDQwMjI5OWI1YjA5ZWYxOWI1ZmU1NDQyY2ZhZDgxNWZl
11
+ MzFlMDk1YjhkY2QzZjUxN2YzODgxMGZhZDZjNWUzYTI3YWYxZTA=
12
+ data.tar.gz: !binary |-
13
+ Nzg4NzYxZDM5NTI1OTI2NzUyMzc2MDZkNGEyMmM5YWEzMTUwZmRjZDUwMjMz
14
+ ZWVjM2UwMjU3MTdjMjM0ZGM5MzgxZmUwMWYwZTc5OGIyMmNhN2FjNjQ4NjNj
15
+ MWFiNTljMjJhYzRjMTMyM2E1ZGQ1MTAxMGExZTMwOTMxYjdiYzI=
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,6 @@
1
+ = YepkeynavRails
2
+
3
+ This project rocks and uses MIT-LICENSE.
4
+
5
+ == Usage
6
+
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'yepKeyNav-Rails'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ require 'rake/testtask'
31
+
32
+ Rake::TestTask.new(:test) do |t|
33
+ t.libs << 'lib'
34
+ t.libs << 'test'
35
+ t.pattern = 'test/**/*_test.rb'
36
+ t.verbose = false
37
+ end
38
+
39
+
40
+ task :default => :test
@@ -0,0 +1,66 @@
1
+ yepKeyNav
2
+ ==========
3
+
4
+ JQuery plugin provides a way to navigate or select items on a page using keyboad shortcuts.
5
+
6
+ # Dependencies
7
+ https://github.com/tzuryby/jquery.hotkeys/
8
+ and http://flesler.blogspot.com/2007/10/jqueryscrollto.html
9
+
10
+
11
+ # USAGE
12
+
13
+ $("selector of a list").yepNavKey()
14
+
15
+ all itens with class yep-key-nav are navigable
16
+
17
+ example to return the jquery selector for all selected itens:
18
+
19
+ $("selector of a list").yepNavKey('selected', function(ret) {
20
+ ret.each(function() {
21
+ //do something
22
+ });
23
+ });
24
+
25
+ ## Events
26
+
27
+ current.yepKeyNav - when the current item is changed
28
+ lostCurrent.yepKeyNav - when item lost the current selecion
29
+ select.yepKeyNav - when an item is selected
30
+ unselect.yepKeyNav - when an item is unselected
31
+
32
+ Example:
33
+
34
+ $("list").on('current.yepKeyNav', function(evt) {
35
+ $current = $(event.target)
36
+
37
+ #... do someting with new $current item
38
+ })
39
+
40
+
41
+ ## Default Options
42
+ classes: {
43
+ navigable: "yep-key-nav",
44
+ currentItem: "yep-key-nav-current",
45
+ selectedItem: "yep-key-nav-selected",
46
+ itemSelector: "yep-key-nav-selector", //should be a checkbox
47
+ selectAll: "yep-key-nav-select-all" //should be a checkbox, when cliecked all itens will be selected or unselected
48
+ },
49
+ scrollSelector: 'window', //selector of panel with scroll of items
50
+ shortcuts: {
51
+ next: "j",
52
+ prev: "k",
53
+ toggleSelect: "x"
54
+ }
55
+
56
+
57
+ # Default Shortcuts
58
+
59
+ j -> next element
60
+ k -> previous element
61
+ x -> select current element
62
+ space -> exec a configured function
63
+
64
+ # BUGS
65
+
66
+ - navigable itens are found on entire document, and not only on $(this) scope
@@ -0,0 +1,223 @@
1
+ /**
2
+ * http://www.openjs.com/scripts/events/keyboard_shortcuts/
3
+ * Version : 2.01.B
4
+ * By Binny V A
5
+ * License : BSD
6
+ */
7
+ shortcut = {
8
+ 'all_shortcuts':{},//All the shortcuts are stored in this array
9
+ 'add': function(shortcut_combination,callback,opt) {
10
+ //Provide a set of default options
11
+ var default_options = {
12
+ 'type':'keydown',
13
+ 'propagate':false,
14
+ 'disable_in_input':false,
15
+ 'target':document,
16
+ 'keycode':false
17
+ }
18
+ if(!opt) opt = default_options;
19
+ else {
20
+ for(var dfo in default_options) {
21
+ if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
22
+ }
23
+ }
24
+
25
+ var ele = opt.target;
26
+ if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
27
+ var ths = this;
28
+ shortcut_combination = shortcut_combination.toLowerCase();
29
+
30
+ //The function to be called at keypress
31
+ var func = function(e) {
32
+ e = e || window.event;
33
+
34
+ if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
35
+ var element;
36
+ if(e.target) element=e.target;
37
+ else if(e.srcElement) element=e.srcElement;
38
+ if(element.nodeType==3) element=element.parentNode;
39
+
40
+ if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
41
+ }
42
+
43
+ //Find Which key is pressed
44
+ if (e.keyCode) code = e.keyCode;
45
+ else if (e.which) code = e.which;
46
+ var character = String.fromCharCode(code).toLowerCase();
47
+
48
+ if(code == 188) character=","; //If the user presses , when the type is onkeydown
49
+ if(code == 190) character="."; //If the user presses , when the type is onkeydown
50
+
51
+ var keys = shortcut_combination.split("+");
52
+ //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
53
+ var kp = 0;
54
+
55
+ //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
56
+ var shift_nums = {
57
+ "`":"~",
58
+ "1":"!",
59
+ "2":"@",
60
+ "3":"#",
61
+ "4":"$",
62
+ "5":"%",
63
+ "6":"^",
64
+ "7":"&",
65
+ "8":"*",
66
+ "9":"(",
67
+ "0":")",
68
+ "-":"_",
69
+ "=":"+",
70
+ ";":":",
71
+ "'":"\"",
72
+ ",":"<",
73
+ ".":">",
74
+ "/":"?",
75
+ "\\":"|"
76
+ }
77
+ //Special Keys - and their codes
78
+ var special_keys = {
79
+ 'esc':27,
80
+ 'escape':27,
81
+ 'tab':9,
82
+ 'space':32,
83
+ 'return':13,
84
+ 'enter':13,
85
+ 'backspace':8,
86
+
87
+ 'scrolllock':145,
88
+ 'scroll_lock':145,
89
+ 'scroll':145,
90
+ 'capslock':20,
91
+ 'caps_lock':20,
92
+ 'caps':20,
93
+ 'numlock':144,
94
+ 'num_lock':144,
95
+ 'num':144,
96
+
97
+ 'pause':19,
98
+ 'break':19,
99
+
100
+ 'insert':45,
101
+ 'home':36,
102
+ 'delete':46,
103
+ 'end':35,
104
+
105
+ 'pageup':33,
106
+ 'page_up':33,
107
+ 'pu':33,
108
+
109
+ 'pagedown':34,
110
+ 'page_down':34,
111
+ 'pd':34,
112
+
113
+ 'left':37,
114
+ 'up':38,
115
+ 'right':39,
116
+ 'down':40,
117
+
118
+ 'f1':112,
119
+ 'f2':113,
120
+ 'f3':114,
121
+ 'f4':115,
122
+ 'f5':116,
123
+ 'f6':117,
124
+ 'f7':118,
125
+ 'f8':119,
126
+ 'f9':120,
127
+ 'f10':121,
128
+ 'f11':122,
129
+ 'f12':123
130
+ }
131
+
132
+ var modifiers = {
133
+ shift: { wanted:false, pressed:false},
134
+ ctrl : { wanted:false, pressed:false},
135
+ alt : { wanted:false, pressed:false},
136
+ meta : { wanted:false, pressed:false} //Meta is Mac specific
137
+ };
138
+
139
+ if(e.ctrlKey) modifiers.ctrl.pressed = true;
140
+ if(e.shiftKey) modifiers.shift.pressed = true;
141
+ if(e.altKey) modifiers.alt.pressed = true;
142
+ if(e.metaKey) modifiers.meta.pressed = true;
143
+
144
+ for(var i=0; k=keys[i],i<keys.length; i++) {
145
+ //Modifiers
146
+ if(k == 'ctrl' || k == 'control') {
147
+ kp++;
148
+ modifiers.ctrl.wanted = true;
149
+
150
+ } else if(k == 'shift') {
151
+ kp++;
152
+ modifiers.shift.wanted = true;
153
+
154
+ } else if(k == 'alt') {
155
+ kp++;
156
+ modifiers.alt.wanted = true;
157
+ } else if(k == 'meta') {
158
+ kp++;
159
+ modifiers.meta.wanted = true;
160
+ } else if(k.length > 1) { //If it is a special key
161
+ if(special_keys[k] == code) kp++;
162
+
163
+ } else if(opt['keycode']) {
164
+ if(opt['keycode'] == code) kp++;
165
+
166
+ } else { //The special keys did not match
167
+ if(character == k) kp++;
168
+ else {
169
+ if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
170
+ character = shift_nums[character];
171
+ if(character == k) kp++;
172
+ }
173
+ }
174
+ }
175
+ }
176
+
177
+ if(kp == keys.length &&
178
+ modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
179
+ modifiers.shift.pressed == modifiers.shift.wanted &&
180
+ modifiers.alt.pressed == modifiers.alt.wanted &&
181
+ modifiers.meta.pressed == modifiers.meta.wanted) {
182
+ callback(e);
183
+
184
+ if(!opt['propagate']) { //Stop the event
185
+ //e.cancelBubble is supported by IE - this will kill the bubbling process.
186
+ e.cancelBubble = true;
187
+ e.returnValue = false;
188
+
189
+ //e.stopPropagation works in Firefox.
190
+ if (e.stopPropagation) {
191
+ e.stopPropagation();
192
+ e.preventDefault();
193
+ }
194
+ return false;
195
+ }
196
+ }
197
+ }
198
+ this.all_shortcuts[shortcut_combination] = {
199
+ 'callback':func,
200
+ 'target':ele,
201
+ 'event': opt['type']
202
+ };
203
+ //Attach the function with the event
204
+ if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
205
+ else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
206
+ else ele['on'+opt['type']] = func;
207
+ },
208
+
209
+ //Remove the shortcut - just specify the shortcut and I will remove the binding
210
+ 'remove':function(shortcut_combination) {
211
+ shortcut_combination = shortcut_combination.toLowerCase();
212
+ var binding = this.all_shortcuts[shortcut_combination];
213
+ delete(this.all_shortcuts[shortcut_combination])
214
+ if(!binding) return;
215
+ var type = binding['event'];
216
+ var ele = binding['target'];
217
+ var callback = binding['callback'];
218
+
219
+ if(ele.detachEvent) ele.detachEvent('on'+type, callback);
220
+ else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
221
+ else ele['on'+type] = false;
222
+ }
223
+ }
@@ -0,0 +1,218 @@
1
+ /*!
2
+ * jQuery.ScrollTo
3
+ * Copyright (c) 2007-2012 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
4
+ * Dual licensed under MIT and GPL.
5
+ * Date: 4/09/2012
6
+ *
7
+ * @projectDescription Easy element scrolling using jQuery.
8
+ * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
9
+ * @author Ariel Flesler
10
+ * @version 1.4.3.1
11
+ *
12
+ * @id jQuery.scrollTo
13
+ * @id jQuery.fn.scrollTo
14
+ * @param {String, Number, DOMElement, jQuery, Object} target Where to scroll the matched elements.
15
+ * The different options for target are:
16
+ * - A number position (will be applied to all axes).
17
+ * - A string position ('44', '100px', '+=90', etc ) will be applied to all axes
18
+ * - A jQuery/DOM element ( logically, child of the element to scroll )
19
+ * - A string selector, that will be relative to the element to scroll ( 'li:eq(2)', etc )
20
+ * - A hash { top:x, left:y }, x and y can be any kind of number/string like above.
21
+ * - A percentage of the container's dimension/s, for example: 50% to go to the middle.
22
+ * - The string 'max' for go-to-end.
23
+ * @param {Number, Function} duration The OVERALL length of the animation, this argument can be the settings object instead.
24
+ * @param {Object,Function} settings Optional set of settings or the onAfter callback.
25
+ * @option {String} axis Which axis must be scrolled, use 'x', 'y', 'xy' or 'yx'.
26
+ * @option {Number, Function} duration The OVERALL length of the animation.
27
+ * @option {String} easing The easing method for the animation.
28
+ * @option {Boolean} margin If true, the margin of the target element will be deducted from the final position.
29
+ * @option {Object, Number} offset Add/deduct from the end position. One number for both axes or { top:x, left:y }.
30
+ * @option {Object, Number} over Add/deduct the height/width multiplied by 'over', can be { top:x, left:y } when using both axes.
31
+ * @option {Boolean} queue If true, and both axis are given, the 2nd axis will only be animated after the first one ends.
32
+ * @option {Function} onAfter Function to be called after the scrolling ends.
33
+ * @option {Function} onAfterFirst If queuing is activated, this function will be called after the first scrolling ends.
34
+ * @return {jQuery} Returns the same jQuery object, for chaining.
35
+ *
36
+ * @desc Scroll to a fixed position
37
+ * @example $('div').scrollTo( 340 );
38
+ *
39
+ * @desc Scroll relatively to the actual position
40
+ * @example $('div').scrollTo( '+=340px', { axis:'y' } );
41
+ *
42
+ * @desc Scroll using a selector (relative to the scrolled element)
43
+ * @example $('div').scrollTo( 'p.paragraph:eq(2)', 500, { easing:'swing', queue:true, axis:'xy' } );
44
+ *
45
+ * @desc Scroll to a DOM element (same for jQuery object)
46
+ * @example var second_child = document.getElementById('container').firstChild.nextSibling;
47
+ * $('#container').scrollTo( second_child, { duration:500, axis:'x', onAfter:function(){
48
+ * alert('scrolled!!');
49
+ * }});
50
+ *
51
+ * @desc Scroll on both axes, to different values
52
+ * @example $('div').scrollTo( { top: 300, left:'+=200' }, { axis:'xy', offset:-20 } );
53
+ */
54
+
55
+ ;(function( $ ){
56
+
57
+ var $scrollTo = $.scrollTo = function( target, duration, settings ){
58
+ $(window).scrollTo( target, duration, settings );
59
+ };
60
+
61
+ $scrollTo.defaults = {
62
+ axis:'xy',
63
+ duration: parseFloat($.fn.jquery) >= 1.3 ? 0 : 1,
64
+ limit:true
65
+ };
66
+
67
+ // Returns the element that needs to be animated to scroll the window.
68
+ // Kept for backwards compatibility (specially for localScroll & serialScroll)
69
+ $scrollTo.window = function( scope ){
70
+ return $(window)._scrollable();
71
+ };
72
+
73
+ // Hack, hack, hack :)
74
+ // Returns the real elements to scroll (supports window/iframes, documents and regular nodes)
75
+ $.fn._scrollable = function(){
76
+ return this.map(function(){
77
+ var elem = this,
78
+ isWin = !elem.nodeName || $.inArray( elem.nodeName.toLowerCase(), ['iframe','#document','html','body'] ) != -1;
79
+
80
+ if( !isWin )
81
+ return elem;
82
+
83
+ var doc = (elem.contentWindow || elem).document || elem.ownerDocument || elem;
84
+
85
+ return /webkit/i.test(navigator.userAgent) || doc.compatMode == 'BackCompat' ?
86
+ doc.body :
87
+ doc.documentElement;
88
+ });
89
+ };
90
+
91
+ $.fn.scrollTo = function( target, duration, settings ){
92
+ if( typeof duration == 'object' ){
93
+ settings = duration;
94
+ duration = 0;
95
+ }
96
+ if( typeof settings == 'function' )
97
+ settings = { onAfter:settings };
98
+
99
+ if( target == 'max' )
100
+ target = 9e9;
101
+
102
+ settings = $.extend( {}, $scrollTo.defaults, settings );
103
+ // Speed is still recognized for backwards compatibility
104
+ duration = duration || settings.duration;
105
+ // Make sure the settings are given right
106
+ settings.queue = settings.queue && settings.axis.length > 1;
107
+
108
+ if( settings.queue )
109
+ // Let's keep the overall duration
110
+ duration /= 2;
111
+ settings.offset = both( settings.offset );
112
+ settings.over = both( settings.over );
113
+
114
+ return this._scrollable().each(function(){
115
+ // Null target yields nothing, just like jQuery does
116
+ if (target == null) return;
117
+
118
+ var elem = this,
119
+ $elem = $(elem),
120
+ targ = target, toff, attr = {},
121
+ win = $elem.is('html,body');
122
+
123
+ switch( typeof targ ){
124
+ // A number will pass the regex
125
+ case 'number':
126
+ case 'string':
127
+ if( /^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(targ) ){
128
+ targ = both( targ );
129
+ // We are done
130
+ break;
131
+ }
132
+ // Relative selector, no break!
133
+ targ = $(targ,this);
134
+ if (!targ.length) return;
135
+ case 'object':
136
+ // DOMElement / jQuery
137
+ if( targ.is || targ.style )
138
+ // Get the real position of the target
139
+ toff = (targ = $(targ)).offset();
140
+ }
141
+ $.each( settings.axis.split(''), function( i, axis ){
142
+ var Pos = axis == 'x' ? 'Left' : 'Top',
143
+ pos = Pos.toLowerCase(),
144
+ key = 'scroll' + Pos,
145
+ old = elem[key],
146
+ max = $scrollTo.max(elem, axis);
147
+
148
+ if( toff ){// jQuery / DOMElement
149
+ attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] );
150
+
151
+ // If it's a dom element, reduce the margin
152
+ if( settings.margin ){
153
+ attr[key] -= parseInt(targ.css('margin'+Pos)) || 0;
154
+ attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0;
155
+ }
156
+
157
+ attr[key] += settings.offset[pos] || 0;
158
+
159
+ if( settings.over[pos] )
160
+ // Scroll to a fraction of its width/height
161
+ attr[key] += targ[axis=='x'?'width':'height']() * settings.over[pos];
162
+ }else{
163
+ var val = targ[pos];
164
+ // Handle percentage values
165
+ attr[key] = val.slice && val.slice(-1) == '%' ?
166
+ parseFloat(val) / 100 * max
167
+ : val;
168
+ }
169
+
170
+ // Number or 'number'
171
+ if( settings.limit && /^\d+$/.test(attr[key]) )
172
+ // Check the limits
173
+ attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max );
174
+
175
+ // Queueing axes
176
+ if( !i && settings.queue ){
177
+ // Don't waste time animating, if there's no need.
178
+ if( old != attr[key] )
179
+ // Intermediate animation
180
+ animate( settings.onAfterFirst );
181
+ // Don't animate this axis again in the next iteration.
182
+ delete attr[key];
183
+ }
184
+ });
185
+
186
+ animate( settings.onAfter );
187
+
188
+ function animate( callback ){
189
+ $elem.animate( attr, duration, settings.easing, callback && function(){
190
+ callback.call(this, target, settings);
191
+ });
192
+ };
193
+
194
+ }).end();
195
+ };
196
+
197
+ // Max scrolling position, works on quirks mode
198
+ // It only fails (not too badly) on IE, quirks mode.
199
+ $scrollTo.max = function( elem, axis ){
200
+ var Dim = axis == 'x' ? 'Width' : 'Height',
201
+ scroll = 'scroll'+Dim;
202
+
203
+ if( !$(elem).is('html,body') )
204
+ return elem[scroll] - $(elem)[Dim.toLowerCase()]();
205
+
206
+ var size = 'client' + Dim,
207
+ html = elem.ownerDocument.documentElement,
208
+ body = elem.ownerDocument.body;
209
+
210
+ return Math.max( html[scroll], body[scroll] )
211
+ - Math.min( html[size] , body[size] );
212
+ };
213
+
214
+ function both( val ){
215
+ return typeof val == 'object' ? val : { top:val, left:val };
216
+ };
217
+
218
+ })( jQuery );