Mozilla Cross-Reference seamonkey
mozilla/ xpfe/ communicator/ resources/ content/ utilityOverlay.js
CVS Log
CVS Blame
CVS Graph
Diff file
Raw file
changes to
this file in
the last:
day
week
month
view using tree:
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is mozilla.org code.
16  *
17  * The Initial Developer of the Original Code is
18  * Netscape Communications Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 1998
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *   Alec Flett <alecf@netscape.com>
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either of the GNU General Public License Version 2 or later (the "GPL"),
27  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  *
37  * ***** END LICENSE BLOCK ***** */
38 
39 /**
40  * Communicator Shared Utility Library
41  * for shared application glue for the Communicator suite of applications
42  **/
43 
44 /*
45   Note: All Editor/Composer-related methods have been moved to editorApplicationOverlay.js,
46   so app windows that require those must include editorNavigatorOverlay.xul
47 */
48 
49 /**
50  * Go into online/offline mode
51  **/
52 
53 const kIOServiceProgID = "@mozilla.org/network/io-service;1";
54 const kObserverServiceProgID = "@mozilla.org/observer-service;1";
55 const kProxyManual = ["network.proxy.ftp",
56                       "network.proxy.gopher",
57                       "network.proxy.http",
58                       "network.proxy.socks",
59                       "network.proxy.ssl"];
60 var gShowBiDi = false;
61 
62 function toggleOfflineStatus()
63 {
64   var checkfunc;
65   try {
66     checkfunc = document.getElementById("offline-status").getAttribute('checkfunc');
67   }
68   catch (ex) {
69     checkfunc = null;
70   }
71 
72   var ioService = Components.classes[kIOServiceProgID]
73                             .getService(Components.interfaces.nsIIOService2);
74   if (checkfunc) {
75     if (!eval(checkfunc)) {
76       // the pre-offline check function returned false, so don't go offline
77       return;
78     }
79   }
80   ioService.manageOfflineStatus = false;
81   ioService.offline = !ioService.offline;
82 }
83 
84 function setNetworkStatus(networkProxyType)
85 {
86   var prefService = Components.classes["@mozilla.org/preferences-service;1"];
87   prefService = prefService.getService(Components.interfaces.nsIPrefService);
88   var prefBranch = prefService.getBranch(null);
89   try {
90     prefBranch.setIntPref("network.proxy.type", networkProxyType);
91   }
92   catch (ex) {}
93 }
94 
95 function InitProxyMenu()
96 {
97   var networkProxyNo = document.getElementById("network-proxy-no");
98   var networkProxyManual = document.getElementById("network-proxy-manual");
99   var networkProxyPac = document.getElementById("network-proxy-pac");
100   var networkProxyWpad = document.getElementById("network-proxy-wpad");
101   var prefService = Components.classes["@mozilla.org/preferences-service;1"];
102   prefService = prefService.getService(Components.interfaces.nsIPrefService);
103   var prefBranch = prefService.getBranch(null);
104 
105   var proxyLocked = prefBranch.prefIsLocked("network.proxy.type");
106   if (proxyLocked) {
107     networkProxyNo.setAttribute("disabled", "true");
108     networkProxyWpad.setAttribute("disabled", "true");
109   }
110   else {
111     networkProxyNo.removeAttribute("disabled");
112     networkProxyWpad.removeAttribute("disabled");
113   }
114 
115   // If no proxy is configured, disable the menuitems.
116   // Checking for proxy manual settings.
117   var proxyManuallyConfigured = false;
118   for (var i = 0; i < kProxyManual.length; i++) {
119     if (GetStringPref(kProxyManual[i]) != "") {
120       proxyManuallyConfigured = true;
121       break;
122     }
123   }
124 
125   if (proxyManuallyConfigured && !proxyLocked) {
126     networkProxyManual.removeAttribute("disabled");
127   }
128   else {
129     networkProxyManual.setAttribute("disabled", "true");
130   }
131 
132   //Checking for proxy PAC settings.
133   var proxyAutoConfigured = false;
134   if (GetStringPref("network.proxy.autoconfig_url") != "")
135     proxyAutoConfigured = true;
136 
137   if (proxyAutoConfigured && !proxyLocked) {
138     networkProxyPac.removeAttribute("disabled");
139   }
140   else {
141     networkProxyPac.setAttribute("disabled", "true");
142   }
143 
144   var networkProxyType;
145   try {
146     networkProxyType = prefBranch.getIntPref("network.proxy.type");
147   } catch(e) {}
148 
149   // The pref value 3 for network.proxy.type is unused to maintain
150   // backwards compatibility. Treat 3 equally to 0. See bug 115720.
151   var networkProxyStatus = [networkProxyNo, networkProxyManual, networkProxyPac,
152                             networkProxyNo, networkProxyWpad];
153   networkProxyStatus[networkProxyType].setAttribute("checked", "true");
154 }
155 
156 function setProxyTypeUI()
157 {
158   var panel = document.getElementById("offline-status");
159   if (!panel)
160     return;
161 
162   var prefService = Components.classes["@mozilla.org/preferences-service;1"];
163   prefService = prefService.getService(Components.interfaces.nsIPrefService);
164   var prefBranch = prefService.getBranch(null);
165 
166   try {
167     var networkProxyType = prefBranch.getIntPref("network.proxy.type");
168   } catch(e) {}
169 
170   var onlineTooltip = "onlineTooltip" + networkProxyType;
171   var bundle = srGetStrBundle("chrome://communicator/locale/utilityOverlay.properties");
172   panel.setAttribute("tooltiptext", bundle.GetStringFromName(onlineTooltip));
173 }
174 
175 function GetStringPref(name)
176 {
177   try {
178     return pref.getComplexValue(name, Components.interfaces.nsISupportsString).data;
179   } catch (e) {}
180   return "";
181 }
182 
183 function setOfflineUI(offline)
184 {
185   var broadcaster = document.getElementById("Communicator:WorkMode");
186   var panel = document.getElementById("offline-status");
187   if (!broadcaster || !panel) return;
188 
189   //Checking for a preference "network.online", if it's locked, disabling 
190   // network icon and menu item
191   var prefService = Components.classes["@mozilla.org/preferences-service;1"];
192   prefService = prefService.getService(Components.interfaces.nsIPrefService);
193   var prefBranch = prefService.getBranch(null);
194   
195   var offlineLocked = prefBranch.prefIsLocked("network.online"); 
196   
197   if (offlineLocked ) {
198       broadcaster.setAttribute("disabled","true");
199   }
200 
201   var bundle = srGetStrBundle("chrome://communicator/locale/utilityOverlay.properties");
202 
203   if (offline)
204     {
205       broadcaster.setAttribute("offline", "true");
206       broadcaster.setAttribute("checked", "true");
207       panel.removeAttribute("context");
208       panel.setAttribute("tooltiptext", bundle.GetStringFromName("offlineTooltip"));
209     }
210   else
211     {
212       broadcaster.removeAttribute("offline");
213       broadcaster.removeAttribute("checked");
214       panel.setAttribute("context", "networkProperties");
215       try {
216         var networkProxyType = prefBranch.getIntPref("network.proxy.type");
217       } catch(e) {}
218       var onlineTooltip = "onlineTooltip" + networkProxyType;
219       panel.setAttribute("tooltiptext", bundle.GetStringFromName(onlineTooltip));
220     }
221 }
222 
223 var goPrefWindow = 0;
224 
225 function getBrowserURL() {
226 
227   try {
228     var prefs = Components.classes["@mozilla.org/preferences-service;1"]
229                          .getService(Components.interfaces.nsIPrefBranch);
230     var url = prefs.getCharPref("browser.chromeURL");
231     if (url)
232       return url;
233   } catch(e) {
234   }
235   return "chrome://navigator/content/navigator.xul";
236 }
237 
238 function goPreferences(containerID, paneURL, itemID)
239 {
240   var resizable;
241   var pref = Components.classes["@mozilla.org/preferences-service;1"]
242                        .getService(Components.interfaces.nsIPrefBranch);
243   try {
244     // We are resizable ONLY if in box debugging mode, because in
245     // this special debug mode it is often impossible to see the 
246     // content of the debug panel in order to disable debug mode.
247     resizable = pref.getBoolPref("xul.debug.box");
248   }
249   catch (e) {
250     resizable = false;
251   }
252 
253   //check for an existing pref window and focus it; it's not application modal
254   const kWindowMediatorContractID = "@mozilla.org/appshell/window-mediator;1";
255   const kWindowMediatorIID = Components.interfaces.nsIWindowMediator;
256   const kWindowMediator = Components.classes[kWindowMediatorContractID].getService(kWindowMediatorIID);
257   var lastPrefWindow = kWindowMediator.getMostRecentWindow("mozilla:preferences");
258   if (lastPrefWindow)
259     lastPrefWindow.focus();
260   else {
261     var resizability = resizable ? "yes" : "no";
262     var features = "chrome,titlebar,resizable=" + resizability;
263     openDialog("chrome://communicator/content/pref/pref.xul","PrefWindow", 
264                features, paneURL, containerID, itemID);
265   }
266 }
267 
268 function goToggleToolbar( id, elementID )
269 {
270   var toolbar = document.getElementById( id );
271   var element = document.getElementById( elementID );
272   if ( toolbar )
273   {
274     var attribValue = toolbar.getAttribute("hidden") ;
275 
276     if ( attribValue == "true" )
277     {
278       toolbar.setAttribute("hidden", "false" );
279       if ( element )
280         element.setAttribute("checked","true")
281     }
282     else
283     {
284       toolbar.setAttribute("hidden", true );
285       if ( element )
286         element.setAttribute("checked","false")
287     }
288     document.persist(id, 'hidden');
289     document.persist(elementID, 'checked');
290   }
291 }
292 
293 
294 function goClickThrobber( urlPref )
295 {
296   var url;
297   try {
298     var pref = Components.classes["@mozilla.org/preferences-service;1"]
299                          .getService(Components.interfaces.nsIPrefBranch);
300     url = pref.getComplexValue(urlPref, Components.interfaces.nsIPrefLocalizedString).data;
301   }
302 
303   catch(e) {
304     url = null;
305   }
306 
307   if ( url )
308     openTopWin(url);
309 }
310 
311 
312 //No longer needed.  Rip this out since we are using openTopWin
313 function goHelpMenu( url )
314 {
315   /* note that this chrome url should probably change to not have all of the navigator controls */
316   /* also, do we want to limit the number of help windows that can be spawned? */
317   window.openDialog( getBrowserURL(), "_blank", "chrome,all,dialog=no", url );
318 }
319 
320 function getTopWin()
321 {
322     var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
323     var windowManagerInterface = windowManager.QueryInterface( Components.interfaces.nsIWindowMediator);
324     var topWindowOfType = windowManagerInterface.getMostRecentWindow( "navigator:browser" );
325 
326     if (topWindowOfType) {
327         return topWindowOfType;
328     }
329     return null;
330 }
331 
332 function openTopWin( url )
333 {
334     /* note that this chrome url should probably change to not have
335        all of the navigator controls, but if we do this we need to have
336        the option for chrome controls because goClickThrobber() needs to
337        use this function with chrome controls */
338     /* also, do we want to
339        limit the number of help windows that can be spawned? */
340     if ((url == null) || (url == "")) return null;
341 
342     // xlate the URL if necessary
343     if (url.indexOf("urn:") == 0)
344     {
345         url = xlateURL(url);        // does RDF urn expansion
346     }
347 
348     // avoid loading "", since this loads a directory listing
349     if (url == "") {
350         url = "about:blank";
351     }
352 
353     var topWindowOfType = getTopWin();
354     if ( topWindowOfType )
355     {
356         topWindowOfType.focus();
357         topWindowOfType.loadURI(url);
358         return topWindowOfType;
359     }
360     return window.openDialog( getBrowserURL(), "_blank", "chrome,all,dialog=no", url );
361 }
362 
363 function goAboutDialog()
364 {
365   var defaultAboutState = false;
366   try {
367     var pref = Components.classes["@mozilla.org/preferences-service;1"]
368                          .getService(Components.interfaces.nsIPrefBranch);
369     defaultAboutState = pref.getBoolPref("browser.show_about_as_stupid_modal_window");
370   }
371   catch(e) {
372     defaultAboutState = false;
373   }
374   if( defaultAboutState )
375     window.openDialog("chrome://global/content/about.xul", "About", "modal,chrome,resizable=yes,height=450,width=550");
376   else
377     window.openDialog( getBrowserURL(), "_blank", "chrome,all,dialog=no", 'about:' );
378 }
379 
380 // update menu items that rely on focus
381 function goUpdateGlobalEditMenuItems()
382 {
383   goUpdateCommand('cmd_undo');
384   goUpdateCommand('cmd_redo');
385   goUpdateCommand('cmd_cut');
386   goUpdateCommand('cmd_copy');
387   goUpdateCommand('cmd_paste');
388   goUpdateCommand('cmd_selectAll');
389   goUpdateCommand('cmd_delete');
390   if (gShowBiDi)
391     goUpdateCommand('cmd_switchTextDirection');
392 }
393 
394 // update menu items that rely on the current selection
395 function goUpdateSelectEditMenuItems()
396 {
397   goUpdateCommand('cmd_cut');
398   goUpdateCommand('cmd_copy');
399   goUpdateCommand('cmd_delete');
400   goUpdateCommand('cmd_selectAll');
401 }
402 
403 // update menu items that relate to undo/redo
404 function goUpdateUndoEditMenuItems()
405 {
406   goUpdateCommand('cmd_undo');
407   goUpdateCommand('cmd_redo');
408 }
409 
410 // update menu items that depend on clipboard contents
411 function goUpdatePasteMenuItems()
412 {
413   goUpdateCommand('cmd_paste');
414 }
415 
416 // update Find As You Type menu items, they rely on focus
417 function goUpdateFindTypeMenuItems()
418 {
419   goUpdateCommand('cmd_findTypeText');
420   goUpdateCommand('cmd_findTypeLinks');
421 }
422 
423 // function that extracts the filename from a url
424 function extractFileNameFromUrl(urlstr) {
425   if (!urlstr) return null;
426 
427   // For "http://foo/bar/cheese.jpg", return "cheese.jpg".
428   // For "imap://user@host.com:143/fetch>UID>/INBOX>951?part=1.2&type=image/gif&filename=foo.jpeg", return "foo.jpeg".
429   // The 2nd url (ie, "imap://...") is generated for inline images by MimeInlineImage_parse_begin() in mimeiimg.cpp.
430   var lastSlash = urlstr.slice(urlstr.lastIndexOf( "/" )+1);
431   if (lastSlash)
432   { 
433     var nameIndex = lastSlash.lastIndexOf( "filename=" );
434     if (nameIndex != -1)
435       return (lastSlash.slice(nameIndex+9));
436     else
437       return lastSlash;
438   }
439   return null; 
440 }
441 
442 // Gather all descendent text under given document node.
443 function gatherTextUnder ( root ) 
444 {
445   var text = "";
446   var node = root.firstChild;
447   var depth = 1;
448   while ( node && depth > 0 ) {
449     // See if this node is text.
450     if ( node.nodeType == Node.TEXT_NODE ) {
451       // Add this text to our collection.
452       text += " " + node.data;
453     } else if ( node instanceof HTMLImageElement ) {
454       // If it has an alt= attribute, add that.
455       var altText = node.getAttribute( "alt" );
456       if ( altText && altText != "" ) {
457         text += " " + altText;
458       }
459     }
460     // Find next node to test.
461     // First, see if this node has children.
462     if ( node.hasChildNodes() ) {
463       // Go to first child.
464       node = node.firstChild;
465       depth++;
466     } else {
467       // No children, try next sibling.
468       if ( node.nextSibling ) {
469         node = node.nextSibling;
470       } else {
471         // Last resort is a sibling of an ancestor
472         while ( node && depth > 0 ) {
473           node = node.parentNode;
474           depth--;
475           if ( node.nextSibling ) {
476             node = node.nextSibling;
477             break;
478           }
479         }
480       }
481     }
482   }
483   // Strip leading whitespace.
484   text = text.replace( /^\s+/, "" );
485   // Strip trailing whitespace.
486   text = text.replace( /\s+$/, "" );
487   // Compress remaining whitespace.
488   text = text.replace( /\s+/g, " " );
489   return text;
490 }
491 
492 var offlineObserver = {
493   observe: function(subject, topic, state) {
494     // sanity checks
495     if (topic != "network:offline-status-changed") return;
496     setOfflineUI(state == "offline");
497   }
498 }
499 
500 var proxyTypeObserver = {
501   observe: function(subject, topic, state) {
502     // sanity checks
503     var ioService = Components.classes[kIOServiceProgID]
504                               .getService(Components.interfaces.nsIIOService);
505     if (state == "network.proxy.type" && !ioService.offline)
506       setProxyTypeUI();
507   }
508 }
509 
510 function utilityOnLoad(aEvent)
511 {
512   var broadcaster = document.getElementById("Communicator:WorkMode");
513   if (!broadcaster) return;
514 
515   var observerService = Components.classes[kObserverServiceProgID]
516 		          .getService(Components.interfaces.nsIObserverService);
517   observerService.addObserver(offlineObserver, "network:offline-status-changed", false);
518   // make sure we remove this observer later
519   var prefService = Components.classes["@mozilla.org/preferences-service;1"];
520   prefService = prefService.getService(Components.interfaces.nsIPrefService);
521   var prefBranch = prefService.getBranch(null);
522   prefBranch = prefBranch.QueryInterface(Components.interfaces.nsIPrefBranch2);
523 
524   prefBranch.addObserver("network.proxy.type", proxyTypeObserver, false);
525 
526   addEventListener("unload", utilityOnUnload, false);
527 
528   // set the initial state
529   var ioService = Components.classes[kIOServiceProgID]
530 		      .getService(Components.interfaces.nsIIOService);
531   setOfflineUI(ioService.offline);
532 }
533 
534 function utilityOnUnload(aEvent) 
535 {
536   var observerService = Components.classes[kObserverServiceProgID]
537 			  .getService(Components.interfaces.nsIObserverService);
538   observerService.removeObserver(offlineObserver, "network:offline-status-changed");
539   var prefService = Components.classes["@mozilla.org/preferences-service;1"];
540   prefService = prefService.getService(Components.interfaces.nsIPrefService);
541   var prefBranch = prefService.getBranch(null);
542   prefBranch = prefBranch.QueryInterface(Components.interfaces.nsIPrefBranch2);
543   
544   prefBranch.removeObserver("network.proxy.type", proxyTypeObserver);
545 }
546 
547 addEventListener("load", utilityOnLoad, false);
548 
549 function GenerateValidFilename(filename, extension)
550 {
551   if (filename) // we have a title; let's see if it's usable
552   {
553     // clean up the filename to make it usable and
554     // then trim whitespace from beginning and end
555     filename = validateFileName(filename).replace(/^\s+|\s+$/g, "");
556     if (filename.length > 0)
557       return filename + extension;
558   }
559   return null;
560 }
561 
562 function validateFileName(aFileName)
563 {
564   var re = /[\/]+/g;
565   if (navigator.appVersion.indexOf("Windows") != -1) {
566     re = /[\\\/\|]+/g;
567     aFileName = aFileName.replace(/[\"]+/g, "'");
568     aFileName = aFileName.replace(/[\*\:\?]+/g, " ");
569     aFileName = aFileName.replace(/[\<]+/g, "(");
570     aFileName = aFileName.replace(/[\>]+/g, ")");
571   }
572   else if (navigator.appVersion.indexOf("Macintosh") != -1)
573     re = /[\:\/]+/g;
574   
575   return aFileName.replace(re, "_");
576 }
577 
578 // autoscroll
579 var gStartX;
580 var gStartY;
581 var gCurrX;
582 var gCurrY;
583 var gScrollingView;
584 var gAutoScrollTimer;
585 var gIgnoreMouseEvents;
586 var gAutoScrollPopup = null;
587 var gAccumulatedScrollErrorX;
588 var gAccumulatedScrollErrorY;
589 
590 function startScrolling(event)
591 {
592   var pref = Components.classes["@mozilla.org/preferences-service;1"]
593                        .getService(Components.interfaces.nsIPrefBranch);
594 
595   if (gScrollingView || event.button != 1)
596     return;
597 
598   if (!pref.getBoolPref("general.autoScroll"))
599     return;
600 
601   if (event.originalTarget instanceof XULElement &&
602       ((event.originalTarget.localName == "thumb")
603         || (event.originalTarget.localName == "slider")
604         || (event.originalTarget.localName == "scrollbarbutton")))
605     return;
606 
607   if (!gAutoScrollPopup) {
608     const XUL_NS
609           = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
610     gAutoScrollPopup = document.createElementNS(XUL_NS, "popup");
611     gAutoScrollPopup.id = "autoscroller";
612     gAutoScrollPopup.addEventListener("popuphidden", stopScrolling, true);
613     document.documentElement.appendChild(gAutoScrollPopup);
614   }
615 
616   gScrollingView = event.originalTarget.ownerDocument.defaultView;
617   var scrollingDir;
618   if (gScrollingView.scrollMaxX > 0) {
619     gAutoScrollPopup.setAttribute("scrolldir", gScrollingView.scrollMaxY > 0 ? "NSEW" : "EW");
620   }
621   else if (gScrollingView.scrollMaxY > 0) {
622     gAutoScrollPopup.setAttribute("scrolldir", "NS");
623   }
624   else {
625     gScrollingView = null; // abort scrolling
626     return;
627   }
628 
629   document.popupNode = null;
630   gAutoScrollPopup.showPopup(document.documentElement, event.screenX, event.screenY,
631                              "popup", null, null);
632   gIgnoreMouseEvents = true;
633   gStartX = event.screenX;
634   gStartY = event.screenY;
635   gCurrX = event.screenX;
636   gCurrY = event.screenY;
637   addEventListener('mousemove', handleMouseMove, true);
638   addEventListener('mouseup', handleMouseUpDown, true);
639   addEventListener('mousedown', handleMouseUpDown, true);
640   addEventListener('contextmenu', handleMouseUpDown, true);
641   gAutoScrollTimer = setInterval(autoScrollLoop, 10);
642   gAccumulatedScrollErrorX = 0;
643   gAccumulatedScrollErrorY = 0;
644 }
645 
646 function handleMouseMove(event)
647 {
648   gCurrX = event.screenX;
649   gCurrY = event.screenY;
650 }
651 
652 function roundToZero(num)
653 {
654   if (num > 0)
655     return Math.floor(num);
656   return Math.ceil(num);
657 }
658 
659 function accelerate(curr, start)
660 {
661     var speed = 12;
662     var val = (curr - start) / speed;
663 
664     if (val > 1)
665         return val * Math.sqrt(val) - 1;
666     if (val < -1)
667         return val * Math.sqrt(-val) + 1;
668     return 0;
669 }
670 
671 function autoScrollLoop()
672 {
673   var x = accelerate(gCurrX, gStartX);
674   var y = accelerate(gCurrY, gStartY);
675 
676   if (x || y)
677     gIgnoreMouseEvents = false;
678 
679   var desiredScrollX = gAccumulatedScrollErrorX + x;
680   var actualScrollX = roundToZero(desiredScrollX);
681   gAccumulatedScrollErrorX = (desiredScrollX - actualScrollX);
682   var desiredScrollY = gAccumulatedScrollErrorY + y;
683   var actualScrollY = roundToZero(desiredScrollY);
684   gAccumulatedScrollErrorY = (desiredScrollY - actualScrollY);
685   gScrollingView.scrollBy(actualScrollX, actualScrollY);
686 }
687 
688 function handleMouseUpDown(event)
689 {
690   if (!gIgnoreMouseEvents)
691     gAutoScrollPopup.hidePopup();
692   gIgnoreMouseEvents = false;
693 }
694 
695 function stopScrolling()
696 {
697   if (gScrollingView) {
698     gScrollingView = null;
699     removeEventListener('mousemove', handleMouseMove, true);
700     removeEventListener('mousedown', handleMouseUpDown, true);
701     removeEventListener('mouseup', handleMouseUpDown, true);
702     removeEventListener('contextmenu', handleMouseUpDown, true);
703     clearInterval(gAutoScrollTimer);
704   }
705 }
706