| 1 | efrain | 1 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 2 | //
 | 
        
           |  |  | 3 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 4 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 5 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 6 | // (at your option) any later version.
 | 
        
           |  |  | 7 | //
 | 
        
           |  |  | 8 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 11 | // GNU General Public License for more details.
 | 
        
           |  |  | 12 | //
 | 
        
           |  |  | 13 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 14 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 15 |   | 
        
           |  |  | 16 | /*
 | 
        
           |  |  | 17 |  * JavaScript to provide automatic scrolling, e.g. during a drag operation.
 | 
        
           |  |  | 18 |  *
 | 
        
           |  |  | 19 |  * Note: this module is defined statically. It is a singleton. You
 | 
        
           |  |  | 20 |  * can only have one use of it active at any time. However, since this
 | 
        
           |  |  | 21 |  * is usually used in relation to drag-drop, and since you only ever
 | 
        
           |  |  | 22 |  * drag one thing at a time, this is not a problem in practice.
 | 
        
           |  |  | 23 |  *
 | 
        
           |  |  | 24 |  * @module     core/autoscroll
 | 
        
           |  |  | 25 |  * @copyright  2016 The Open University
 | 
        
           |  |  | 26 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 27 |  * @since      3.6
 | 
        
           |  |  | 28 |  */
 | 
        
           |  |  | 29 | define(['jquery'], function($) {
 | 
        
           |  |  | 30 |     /**
 | 
        
           |  |  | 31 |      * @alias module:core/autoscroll
 | 
        
           |  |  | 32 |      */
 | 
        
           |  |  | 33 |     var autoscroll = {
 | 
        
           |  |  | 34 |         /**
 | 
        
           |  |  | 35 |          * Size of area near edge of screen that triggers scrolling.
 | 
        
           |  |  | 36 |          * @private
 | 
        
           |  |  | 37 |          */
 | 
        
           |  |  | 38 |         SCROLL_THRESHOLD: 30,
 | 
        
           |  |  | 39 |   | 
        
           |  |  | 40 |         /**
 | 
        
           |  |  | 41 |          * How frequently to scroll window.
 | 
        
           |  |  | 42 |          * @private
 | 
        
           |  |  | 43 |          */
 | 
        
           |  |  | 44 |         SCROLL_FREQUENCY: 1000 / 60,
 | 
        
           |  |  | 45 |   | 
        
           |  |  | 46 |         /**
 | 
        
           |  |  | 47 |          * How many pixels to scroll per unit (1 = max scroll 30).
 | 
        
           |  |  | 48 |          * @private
 | 
        
           |  |  | 49 |          */
 | 
        
           |  |  | 50 |         SCROLL_SPEED: 0.5,
 | 
        
           |  |  | 51 |   | 
        
           |  |  | 52 |         /**
 | 
        
           |  |  | 53 |          * Set if currently scrolling up/down.
 | 
        
           |  |  | 54 |          * @private
 | 
        
           |  |  | 55 |          */
 | 
        
           |  |  | 56 |         scrollingId: null,
 | 
        
           |  |  | 57 |   | 
        
           |  |  | 58 |         /**
 | 
        
           |  |  | 59 |          * Speed we are supposed to scroll (range 1 to SCROLL_THRESHOLD).
 | 
        
           |  |  | 60 |          * @private
 | 
        
           |  |  | 61 |          */
 | 
        
           |  |  | 62 |         scrollAmount: 0,
 | 
        
           |  |  | 63 |   | 
        
           |  |  | 64 |         /**
 | 
        
           |  |  | 65 |          * Optional callback called when it scrolls
 | 
        
           |  |  | 66 |          * @private
 | 
        
           |  |  | 67 |          */
 | 
        
           |  |  | 68 |         callback: null,
 | 
        
           |  |  | 69 |   | 
        
           |  |  | 70 |         /**
 | 
        
           |  |  | 71 |          * Starts automatically scrolling if user moves near edge of window.
 | 
        
           |  |  | 72 |          * This should be called in response to mouse down or touch start.
 | 
        
           |  |  | 73 |          *
 | 
        
           |  |  | 74 |          * @public
 | 
        
           |  |  | 75 |          * @param {Function} callback Optional callback that is called every time it scrolls
 | 
        
           |  |  | 76 |          */
 | 
        
           |  |  | 77 |         start: function(callback) {
 | 
        
           |  |  | 78 |             $(window).on('mousemove', autoscroll.mouseMove);
 | 
        
           |  |  | 79 |             $(window).on('touchmove', autoscroll.touchMove);
 | 
        
           |  |  | 80 |             autoscroll.callback = callback;
 | 
        
           |  |  | 81 |         },
 | 
        
           |  |  | 82 |   | 
        
           |  |  | 83 |         /**
 | 
        
           |  |  | 84 |          * Stops automatically scrolling. This should be called in response to mouse up or touch end.
 | 
        
           |  |  | 85 |          *
 | 
        
           |  |  | 86 |          * @public
 | 
        
           |  |  | 87 |          */
 | 
        
           |  |  | 88 |         stop: function() {
 | 
        
           |  |  | 89 |             $(window).off('mousemove', autoscroll.mouseMove);
 | 
        
           |  |  | 90 |             $(window).off('touchmove', autoscroll.touchMove);
 | 
        
           |  |  | 91 |             if (autoscroll.scrollingId !== null) {
 | 
        
           |  |  | 92 |                 autoscroll.stopScrolling();
 | 
        
           |  |  | 93 |             }
 | 
        
           |  |  | 94 |         },
 | 
        
           |  |  | 95 |   | 
        
           |  |  | 96 |         /**
 | 
        
           |  |  | 97 |          * Event handler for touch move.
 | 
        
           |  |  | 98 |          *
 | 
        
           |  |  | 99 |          * @private
 | 
        
           |  |  | 100 |          * @param {Object} e Event
 | 
        
           |  |  | 101 |          */
 | 
        
           |  |  | 102 |         touchMove: function(e) {
 | 
        
           |  |  | 103 |             for (var i = 0; i < e.changedTouches.length; i++) {
 | 
        
           |  |  | 104 |                 autoscroll.handleMove(e.changedTouches[i].clientX, e.changedTouches[i].clientY);
 | 
        
           |  |  | 105 |             }
 | 
        
           |  |  | 106 |         },
 | 
        
           |  |  | 107 |   | 
        
           |  |  | 108 |         /**
 | 
        
           |  |  | 109 |          * Event handler for mouse move.
 | 
        
           |  |  | 110 |          *
 | 
        
           |  |  | 111 |          * @private
 | 
        
           |  |  | 112 |          * @param {Object} e Event
 | 
        
           |  |  | 113 |          */
 | 
        
           |  |  | 114 |         mouseMove: function(e) {
 | 
        
           |  |  | 115 |             autoscroll.handleMove(e.clientX, e.clientY);
 | 
        
           |  |  | 116 |         },
 | 
        
           |  |  | 117 |   | 
        
           |  |  | 118 |         /**
 | 
        
           |  |  | 119 |          * Handles user moving.
 | 
        
           |  |  | 120 |          *
 | 
        
           |  |  | 121 |          * @private
 | 
        
           |  |  | 122 |          * @param {number} clientX X
 | 
        
           |  |  | 123 |          * @param {number} clientY Y
 | 
        
           |  |  | 124 |          */
 | 
        
           |  |  | 125 |         handleMove: function(clientX, clientY) {
 | 
        
           |  |  | 126 |             // If near the bottom or top, start auto-scrolling.
 | 
        
           |  |  | 127 |             if (clientY < autoscroll.SCROLL_THRESHOLD) {
 | 
        
           |  |  | 128 |                 autoscroll.scrollAmount = -Math.min(autoscroll.SCROLL_THRESHOLD - clientY, autoscroll.SCROLL_THRESHOLD);
 | 
        
           |  |  | 129 |             } else if (clientY > $(window).height() - autoscroll.SCROLL_THRESHOLD) {
 | 
        
           |  |  | 130 |                 autoscroll.scrollAmount = Math.min(clientY - ($(window).height() - autoscroll.SCROLL_THRESHOLD),
 | 
        
           |  |  | 131 |                     autoscroll.SCROLL_THRESHOLD);
 | 
        
           |  |  | 132 |             } else {
 | 
        
           |  |  | 133 |                 autoscroll.scrollAmount = 0;
 | 
        
           |  |  | 134 |             }
 | 
        
           |  |  | 135 |             if (autoscroll.scrollAmount && autoscroll.scrollingId === null) {
 | 
        
           |  |  | 136 |                 autoscroll.startScrolling();
 | 
        
           |  |  | 137 |             } else if (!autoscroll.scrollAmount && autoscroll.scrollingId !== null) {
 | 
        
           |  |  | 138 |                 autoscroll.stopScrolling();
 | 
        
           |  |  | 139 |             }
 | 
        
           |  |  | 140 |         },
 | 
        
           |  |  | 141 |   | 
        
           |  |  | 142 |         /**
 | 
        
           |  |  | 143 |          * Starts automatic scrolling.
 | 
        
           |  |  | 144 |          *
 | 
        
           |  |  | 145 |          * @private
 | 
        
           |  |  | 146 |          */
 | 
        
           |  |  | 147 |         startScrolling: function() {
 | 
        
           |  |  | 148 |             var maxScroll = $(document).height() - $(window).height();
 | 
        
           |  |  | 149 |             autoscroll.scrollingId = window.setInterval(function() {
 | 
        
           |  |  | 150 |                 // Work out how much to scroll.
 | 
        
           |  |  | 151 |                 var y = $(window).scrollTop();
 | 
        
           |  |  | 152 |                 var offset = Math.round(autoscroll.scrollAmount * autoscroll.SCROLL_SPEED);
 | 
        
           |  |  | 153 |                 if (y + offset < 0) {
 | 
        
           |  |  | 154 |                     offset = -y;
 | 
        
           |  |  | 155 |                 }
 | 
        
           |  |  | 156 |                 if (y + offset > maxScroll) {
 | 
        
           |  |  | 157 |                     offset = maxScroll - y;
 | 
        
           |  |  | 158 |                 }
 | 
        
           |  |  | 159 |                 if (offset === 0) {
 | 
        
           |  |  | 160 |                     return;
 | 
        
           |  |  | 161 |                 }
 | 
        
           |  |  | 162 |   | 
        
           |  |  | 163 |                 // Scroll.
 | 
        
           |  |  | 164 |                 $(window).scrollTop(y + offset);
 | 
        
           |  |  | 165 |                 var realOffset = $(window).scrollTop() - y;
 | 
        
           |  |  | 166 |                 if (realOffset === 0) {
 | 
        
           |  |  | 167 |                     return;
 | 
        
           |  |  | 168 |                 }
 | 
        
           |  |  | 169 |   | 
        
           |  |  | 170 |                 // Inform callback
 | 
        
           |  |  | 171 |                 if (autoscroll.callback) {
 | 
        
           |  |  | 172 |                     autoscroll.callback(realOffset);
 | 
        
           |  |  | 173 |                 }
 | 
        
           |  |  | 174 |   | 
        
           |  |  | 175 |             }, autoscroll.SCROLL_FREQUENCY);
 | 
        
           |  |  | 176 |         },
 | 
        
           |  |  | 177 |   | 
        
           |  |  | 178 |         /**
 | 
        
           |  |  | 179 |          * Stops the automatic scrolling.
 | 
        
           |  |  | 180 |          *
 | 
        
           |  |  | 181 |          * @private
 | 
        
           |  |  | 182 |          */
 | 
        
           |  |  | 183 |         stopScrolling: function() {
 | 
        
           |  |  | 184 |             window.clearInterval(autoscroll.scrollingId);
 | 
        
           |  |  | 185 |             autoscroll.scrollingId = null;
 | 
        
           |  |  | 186 |         }
 | 
        
           |  |  | 187 |     };
 | 
        
           |  |  | 188 |   | 
        
           |  |  | 189 |     return {
 | 
        
           |  |  | 190 |         /**
 | 
        
           |  |  | 191 |          * Starts automatic scrolling if user moves near edge of window.
 | 
        
           |  |  | 192 |          * This should be called in response to mouse down or touch start.
 | 
        
           |  |  | 193 |          *
 | 
        
           |  |  | 194 |          * @public
 | 
        
           |  |  | 195 |          * @param {Function} callback Optional callback that is called every time it scrolls
 | 
        
           |  |  | 196 |          */
 | 
        
           |  |  | 197 |         start: autoscroll.start,
 | 
        
           |  |  | 198 |   | 
        
           |  |  | 199 |         /**
 | 
        
           |  |  | 200 |          * Stops automatic scrolling. This should be called in response to mouse up or touch end.
 | 
        
           |  |  | 201 |          *
 | 
        
           |  |  | 202 |          * @public
 | 
        
           |  |  | 203 |          */
 | 
        
           |  |  | 204 |         stop: autoscroll.stop
 | 
        
           |  |  | 205 |     };
 | 
        
           |  |  | 206 |   | 
        
           |  |  | 207 | });
 |