 |
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