NOBUG: Fixed file access permissions
[moodle.git] / lib / yuilib / 3.13.0 / dd-scroll / dd-scroll.js
blob859f0e459c8d7068b678e9309207cbcb101066cb
1 /*
2 YUI 3.13.0 (build 508226d)
3 Copyright 2013 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
6 */
8 YUI.add('dd-scroll', function (Y, NAME) {
11     /**
12      * Base scroller class used to create the Plugin.DDNodeScroll and Plugin.DDWinScroll.
13      * This class should not be called on it's own, it's designed to be a plugin.
14      * @module dd
15      * @submodule dd-scroll
16      */
17     /**
18      * Base scroller class used to create the Plugin.DDNodeScroll and Plugin.DDWinScroll.
19      * This class should not be called on it's own, it's designed to be a plugin.
20      * @class Scroll
21      * @extends Base
22      * @namespace DD
23      * @constructor
24      */
26     var S = function() {
27         S.superclass.constructor.apply(this, arguments);
29     },
30     WS, NS,
31     HOST = 'host',
32     BUFFER = 'buffer',
33     PARENT_SCROLL = 'parentScroll',
34     WINDOW_SCROLL = 'windowScroll',
35     SCROLL_TOP = 'scrollTop',
36     SCROLL_LEFT = 'scrollLeft',
37     OFFSET_WIDTH = 'offsetWidth',
38     OFFSET_HEIGHT = 'offsetHeight';
41     S.ATTRS = {
42         /**
43         * Internal config option to hold the node that we are scrolling. Should not be set by the developer.
44         * @attribute parentScroll
45         * @protected
46         * @type Node
47         */
48         parentScroll: {
49             value: false,
50             setter: function(node) {
51                 if (node) {
52                     return node;
53                 }
54                 return false;
55             }
56         },
57         /**
58         * The number of pixels from the edge of the screen to turn on scrolling. Default: 30
59         * @attribute buffer
60         * @type Number
61         */
62         buffer: {
63             value: 30,
64             validator: Y.Lang.isNumber
65         },
66         /**
67         * The number of milliseconds delay to pass to the auto scroller. Default: 235
68         * @attribute scrollDelay
69         * @type Number
70         */
71         scrollDelay: {
72             value: 235,
73             validator: Y.Lang.isNumber
74         },
75         /**
76         * The host we are plugged into.
77         * @attribute host
78         * @type Object
79         */
80         host: {
81             value: null
82         },
83         /**
84         * Turn on window scroll support, default: false
85         * @attribute windowScroll
86         * @type Boolean
87         */
88         windowScroll: {
89             value: false,
90             validator: Y.Lang.isBoolean
91         },
92         /**
93         * Allow vertical scrolling, default: true.
94         * @attribute vertical
95         * @type Boolean
96         */
97         vertical: {
98             value: true,
99             validator: Y.Lang.isBoolean
100         },
101         /**
102         * Allow horizontal scrolling, default: true.
103         * @attribute horizontal
104         * @type Boolean
105         */
106         horizontal: {
107             value: true,
108             validator: Y.Lang.isBoolean
109         }
110     };
112     Y.extend(S, Y.Base, {
113         /**
114         * Tells if we are actively scrolling or not.
115         * @private
116         * @property _scrolling
117         * @type Boolean
118         */
119         _scrolling: null,
120         /**
121         * Cache of the Viewport dims.
122         * @private
123         * @property _vpRegionCache
124         * @type Object
125         */
126         _vpRegionCache: null,
127         /**
128         * Cache of the dragNode dims.
129         * @private
130         * @property _dimCache
131         * @type Object
132         */
133         _dimCache: null,
134         /**
135         * Holder for the Timer object returned from Y.later.
136         * @private
137         * @property _scrollTimer
138         * @type {Y.later}
139         */
140         _scrollTimer: null,
141         /**
142         * Sets the _vpRegionCache property with an Object containing the dims from the viewport.
143         * @private
144         * @method _getVPRegion
145         */
146         _getVPRegion: function() {
147             var r = {},
148                 n = this.get(PARENT_SCROLL),
149             b = this.get(BUFFER),
150             ws = this.get(WINDOW_SCROLL),
151             xy = ((ws) ? [] : n.getXY()),
152             w = ((ws) ? 'winWidth' : OFFSET_WIDTH),
153             h = ((ws) ? 'winHeight' : OFFSET_HEIGHT),
154             t = ((ws) ? n.get(SCROLL_TOP) : xy[1]),
155             l = ((ws) ? n.get(SCROLL_LEFT) : xy[0]);
157             r = {
158                 top: t + b,
159                 right: (n.get(w) + l) - b,
160                 bottom: (n.get(h) + t) - b,
161                 left: l + b
162             };
163             this._vpRegionCache = r;
164             return r;
165         },
166         initializer: function() {
167             var h = this.get(HOST);
168             h.after('drag:start', Y.bind(this.start, this));
169             h.after('drag:end', Y.bind(this.end, this));
170             h.on('drag:align', Y.bind(this.align, this));
172             //TODO - This doesn't work yet??
173             Y.one('win').on('scroll', Y.bind(function() {
174                 this._vpRegionCache = null;
175             }, this));
176         },
177         /**
178         * Check to see if we need to fire the scroll timer. If scroll timer is running this will scroll the window.
179         * @private
180         * @method _checkWinScroll
181         * @param {Boolean} move Should we move the window. From Y.later
182         */
183         _checkWinScroll: function(move) {
184             var r = this._getVPRegion(),
185                 ho = this.get(HOST),
186                 ws = this.get(WINDOW_SCROLL),
187                 xy = ho.lastXY,
188                 scroll = false,
189                 b = this.get(BUFFER),
190                 win = this.get(PARENT_SCROLL),
191                 sTop = win.get(SCROLL_TOP),
192                 sLeft = win.get(SCROLL_LEFT),
193                 w = this._dimCache.w,
194                 h = this._dimCache.h,
195                 bottom = xy[1] + h,
196                 top = xy[1],
197                 right = xy[0] + w,
198                 left = xy[0],
199                 nt = top,
200                 nl = left,
201                 st = sTop,
202                 sl = sLeft;
204             if (this.get('horizontal')) {
205                 if (left <= r.left) {
206                     scroll = true;
207                     nl = xy[0] - ((ws) ? b : 0);
208                     sl = sLeft - b;
209                 }
210                 if (right >= r.right) {
211                     scroll = true;
212                     nl = xy[0] + ((ws) ? b : 0);
213                     sl = sLeft + b;
214                 }
215             }
216             if (this.get('vertical')) {
217                 if (bottom >= r.bottom) {
218                     scroll = true;
219                     nt = xy[1] + ((ws) ? b : 0);
220                     st = sTop + b;
222                 }
223                 if (top <= r.top) {
224                     scroll = true;
225                     nt = xy[1] - ((ws) ? b : 0);
226                     st = sTop - b;
227                 }
228             }
230             if (st < 0) {
231                 st = 0;
232                 nt = xy[1];
233             }
235             if (sl < 0) {
236                 sl = 0;
237                 nl = xy[0];
238             }
240             if (nt < 0) {
241                 nt = xy[1];
242             }
243             if (nl < 0) {
244                 nl = xy[0];
245             }
246             if (move) {
247                 ho.actXY = [nl, nt];
248                 ho._alignNode([nl, nt], true); //We are srolling..
249                 xy = ho.actXY;
250                 ho.actXY = [nl, nt];
251                 ho._moveNode({ node: win, top: st, left: sl});
252                 if (!st && !sl) {
253                     this._cancelScroll();
254                 }
255             } else {
256                 if (scroll) {
257                     this._initScroll();
258                 } else {
259                     this._cancelScroll();
260                 }
261             }
262         },
263         /**
264         * Cancel a previous scroll timer and init a new one.
265         * @private
266         * @method _initScroll
267         */
268         _initScroll: function() {
269             this._cancelScroll();
270             this._scrollTimer = Y.Lang.later(this.get('scrollDelay'), this, this._checkWinScroll, [true], true);
272         },
273         /**
274         * Cancel a currently running scroll timer.
275         * @private
276         * @method _cancelScroll
277         */
278         _cancelScroll: function() {
279             this._scrolling = false;
280             if (this._scrollTimer) {
281                 this._scrollTimer.cancel();
282                 delete this._scrollTimer;
283             }
284         },
285         /**
286         * Called from the drag:align event to determine if we need to scroll.
287         * @method align
288         */
289         align: function(e) {
290             if (this._scrolling) {
291                 this._cancelScroll();
292                 e.preventDefault();
293             }
294             if (!this._scrolling) {
295                 this._checkWinScroll();
296             }
297         },
298         /**
299         * Set the cache of the dragNode dims.
300         * @private
301         * @method _setDimCache
302         */
303         _setDimCache: function() {
304             var node = this.get(HOST).get('dragNode');
305             this._dimCache = {
306                 h: node.get(OFFSET_HEIGHT),
307                 w: node.get(OFFSET_WIDTH)
308             };
309         },
310         /**
311         * Called from the drag:start event
312         * @method start
313         */
314         start: function() {
315             this._setDimCache();
316         },
317         /**
318         * Called from the drag:end event
319         * @method end
320         */
321         end: function() {
322             this._dimCache = null;
323             this._cancelScroll();
324         }
325     });
327     Y.namespace('Plugin');
330     /**
331      * Extends the Scroll class to make the window scroll while dragging.
332      * @class DDWindowScroll
333      * @extends Scroll
334      * @namespace Plugin
335      * @constructor
336      */
337     WS = function() {
338         WS.superclass.constructor.apply(this, arguments);
339     };
340     WS.ATTRS = Y.merge(S.ATTRS, {
341         /**
342         * Turn on window scroll support, default: true
343         * @attribute windowScroll
344         * @type Boolean
345         */
346         windowScroll: {
347             value: true,
348             setter: function(scroll) {
349                 if (scroll) {
350                     this.set(PARENT_SCROLL, Y.one('win'));
351                 }
352                 return scroll;
353             }
354         }
355     });
356     Y.extend(WS, S, {
357         //Shouldn't have to do this..
358         initializer: function() {
359             this.set('windowScroll', this.get('windowScroll'));
360         }
361     });
362     /**
363     * The Scroll instance will be placed on the Drag instance under the winscroll namespace.
364     * @property NS
365     * @default winscroll
366     * @readonly
367     * @protected
368     * @static
369     * @type {String}
370     */
371     WS.NAME = WS.NS = 'winscroll';
372     Y.Plugin.DDWinScroll = WS;
375     /**
376      * Extends the Scroll class to make a parent node scroll while dragging.
377      * @class DDNodeScroll
378      * @extends Scroll
379      * @namespace Plugin
380      * @constructor
381      */
382     NS = function() {
383         NS.superclass.constructor.apply(this, arguments);
385     };
386     NS.ATTRS = Y.merge(S.ATTRS, {
387         /**
388         * The node we want to scroll. Used to set the internal parentScroll attribute.
389         * @attribute node
390         * @type Node
391         */
392         node: {
393             value: false,
394             setter: function(node) {
395                 var n = Y.one(node);
396                 if (!n) {
397                     if (node !== false) {
398                         Y.error('DDNodeScroll: Invalid Node Given: ' + node);
399                     }
400                 } else {
401                     this.set(PARENT_SCROLL, n);
402                 }
403                 return n;
404             }
405         }
406     });
407     Y.extend(NS, S, {
408         //Shouldn't have to do this..
409         initializer: function() {
410             this.set('node', this.get('node'));
411         }
412     });
413     /**
414     * The NodeScroll instance will be placed on the Drag instance under the nodescroll namespace.
415     * @property NS
416     * @default nodescroll
417     * @readonly
418     * @protected
419     * @static
420     * @type {String}
421     */
422     NS.NAME = NS.NS = 'nodescroll';
423     Y.Plugin.DDNodeScroll = NS;
425     Y.DD.Scroll = S;
430 }, '3.13.0', {"requires": ["dd-drag"]});