1 | define(["../_base/lang", "../sniff", "../_base/window", "../dom-geometry", "../dom-style", "../window"], |
---|
2 | function(lang, has, win, domGeom, domStyle, winUtils){ |
---|
3 | |
---|
4 | // module: |
---|
5 | // dojo/dnd/autoscroll |
---|
6 | |
---|
7 | var exports = { |
---|
8 | // summary: |
---|
9 | // Used by dojo/dnd/Manager to scroll document or internal node when the user |
---|
10 | // drags near the edge of the viewport or a scrollable node |
---|
11 | }; |
---|
12 | lang.setObject("dojo.dnd.autoscroll", exports); |
---|
13 | |
---|
14 | exports.getViewport = winUtils.getBox; |
---|
15 | |
---|
16 | exports.V_TRIGGER_AUTOSCROLL = 32; |
---|
17 | exports.H_TRIGGER_AUTOSCROLL = 32; |
---|
18 | |
---|
19 | exports.V_AUTOSCROLL_VALUE = 16; |
---|
20 | exports.H_AUTOSCROLL_VALUE = 16; |
---|
21 | |
---|
22 | // These are set by autoScrollStart(). |
---|
23 | // Set to default values in case autoScrollStart() isn't called. (back-compat, remove for 2.0) |
---|
24 | var viewport, |
---|
25 | doc = win.doc, |
---|
26 | maxScrollTop = Infinity, |
---|
27 | maxScrollLeft = Infinity; |
---|
28 | |
---|
29 | exports.autoScrollStart = function(d){ |
---|
30 | // summary: |
---|
31 | // Called at the start of a drag. |
---|
32 | // d: Document |
---|
33 | // The document of the node being dragged. |
---|
34 | |
---|
35 | doc = d; |
---|
36 | viewport = winUtils.getBox(doc); |
---|
37 | |
---|
38 | // Save height/width of document at start of drag, before it gets distorted by a user dragging an avatar past |
---|
39 | // the document's edge |
---|
40 | var html = win.body(doc).parentNode; |
---|
41 | maxScrollTop = Math.max(html.scrollHeight - viewport.h, 0); |
---|
42 | maxScrollLeft = Math.max(html.scrollWidth - viewport.w, 0); // usually 0 |
---|
43 | }; |
---|
44 | |
---|
45 | exports.autoScroll = function(e){ |
---|
46 | // summary: |
---|
47 | // a handler for mousemove and touchmove events, which scrolls the window, if |
---|
48 | // necessary |
---|
49 | // e: Event |
---|
50 | // mousemove/touchmove event |
---|
51 | |
---|
52 | // FIXME: needs more docs! |
---|
53 | var v = viewport || winUtils.getBox(doc), // getBox() call for back-compat, in case autoScrollStart() wasn't called |
---|
54 | html = win.body(doc).parentNode, |
---|
55 | dx = 0, dy = 0; |
---|
56 | if(e.clientX < exports.H_TRIGGER_AUTOSCROLL){ |
---|
57 | dx = -exports.H_AUTOSCROLL_VALUE; |
---|
58 | }else if(e.clientX > v.w - exports.H_TRIGGER_AUTOSCROLL){ |
---|
59 | dx = Math.min(exports.H_AUTOSCROLL_VALUE, maxScrollLeft - html.scrollLeft); // don't scroll past edge of doc |
---|
60 | } |
---|
61 | if(e.clientY < exports.V_TRIGGER_AUTOSCROLL){ |
---|
62 | dy = -exports.V_AUTOSCROLL_VALUE; |
---|
63 | }else if(e.clientY > v.h - exports.V_TRIGGER_AUTOSCROLL){ |
---|
64 | dy = Math.min(exports.V_AUTOSCROLL_VALUE, maxScrollTop - html.scrollTop); // don't scroll past edge of doc |
---|
65 | } |
---|
66 | window.scrollBy(dx, dy); |
---|
67 | }; |
---|
68 | |
---|
69 | exports._validNodes = {"div": 1, "p": 1, "td": 1}; |
---|
70 | exports._validOverflow = {"auto": 1, "scroll": 1}; |
---|
71 | |
---|
72 | exports.autoScrollNodes = function(e){ |
---|
73 | // summary: |
---|
74 | // a handler for mousemove and touchmove events, which scrolls the first available |
---|
75 | // Dom element, it falls back to exports.autoScroll() |
---|
76 | // e: Event |
---|
77 | // mousemove/touchmove event |
---|
78 | |
---|
79 | // FIXME: needs more docs! |
---|
80 | |
---|
81 | var b, t, w, h, rx, ry, dx = 0, dy = 0, oldLeft, oldTop; |
---|
82 | |
---|
83 | for(var n = e.target; n;){ |
---|
84 | if(n.nodeType == 1 && (n.tagName.toLowerCase() in exports._validNodes)){ |
---|
85 | var s = domStyle.getComputedStyle(n), |
---|
86 | overflow = (s.overflow.toLowerCase() in exports._validOverflow), |
---|
87 | overflowX = (s.overflowX.toLowerCase() in exports._validOverflow), |
---|
88 | overflowY = (s.overflowY.toLowerCase() in exports._validOverflow); |
---|
89 | if(overflow || overflowX || overflowY){ |
---|
90 | b = domGeom.getContentBox(n, s); |
---|
91 | t = domGeom.position(n, true); |
---|
92 | } |
---|
93 | // overflow-x |
---|
94 | if(overflow || overflowX){ |
---|
95 | w = Math.min(exports.H_TRIGGER_AUTOSCROLL, b.w / 2); |
---|
96 | rx = e.pageX - t.x; |
---|
97 | if(has("webkit") || has("opera")){ |
---|
98 | // FIXME: this code should not be here, it should be taken into account |
---|
99 | // either by the event fixing code, or the domGeom.position() |
---|
100 | // FIXME: this code doesn't work on Opera 9.5 Beta |
---|
101 | rx += win.body().scrollLeft; |
---|
102 | } |
---|
103 | dx = 0; |
---|
104 | if(rx > 0 && rx < b.w){ |
---|
105 | if(rx < w){ |
---|
106 | dx = -w; |
---|
107 | }else if(rx > b.w - w){ |
---|
108 | dx = w; |
---|
109 | } |
---|
110 | oldLeft = n.scrollLeft; |
---|
111 | n.scrollLeft = n.scrollLeft + dx; |
---|
112 | } |
---|
113 | } |
---|
114 | // overflow-y |
---|
115 | if(overflow || overflowY){ |
---|
116 | //console.log(b.l, b.t, t.x, t.y, n.scrollLeft, n.scrollTop); |
---|
117 | h = Math.min(exports.V_TRIGGER_AUTOSCROLL, b.h / 2); |
---|
118 | ry = e.pageY - t.y; |
---|
119 | if(has("webkit") || has("opera")){ |
---|
120 | // FIXME: this code should not be here, it should be taken into account |
---|
121 | // either by the event fixing code, or the domGeom.position() |
---|
122 | // FIXME: this code doesn't work on Opera 9.5 Beta |
---|
123 | ry += win.body().scrollTop; |
---|
124 | } |
---|
125 | dy = 0; |
---|
126 | if(ry > 0 && ry < b.h){ |
---|
127 | if(ry < h){ |
---|
128 | dy = -h; |
---|
129 | }else if(ry > b.h - h){ |
---|
130 | dy = h; |
---|
131 | } |
---|
132 | oldTop = n.scrollTop; |
---|
133 | n.scrollTop = n.scrollTop + dy; |
---|
134 | } |
---|
135 | } |
---|
136 | if(dx || dy){ return; } |
---|
137 | } |
---|
138 | try{ |
---|
139 | n = n.parentNode; |
---|
140 | }catch(x){ |
---|
141 | n = null; |
---|
142 | } |
---|
143 | } |
---|
144 | exports.autoScroll(e); |
---|
145 | }; |
---|
146 | |
---|
147 | return exports; |
---|
148 | |
---|
149 | }); |
---|