1 /* See license.txt for terms of usage */ 2 3 define([ 4 "firebug/lib/object", 5 "firebug/firebug", 6 "firebug/lib/locale", 7 "firebug/lib/url", 8 "firebug/chrome/tabWatcher", 9 "firebug/chrome/annotations", 10 ], 11 function(Obj, Firebug, Locale, Url, TabWatcher, Annotations) { 12 13 // ********************************************************************************************* // 14 // Constants 15 16 const Cc = Components.classes; 17 const Ci = Components.interfaces; 18 19 // ********************************************************************************************* // 20 21 /** 22 * @module Implements Firebug activation logic. 23 * 24 * 1) Part of the logic is based on annotation service (see components/firebug-annotations.js) 25 * in order to remember whether Firebug is activated for given site or not. 26 * If there is "firebugged.showFirebug" annotation for a given site Firbug is activated. 27 * If there is "firebugged.closed" annotation for a given site Firbug is not activated. 28 * 29 * 2) Other part is based on extensions.firebug.allPagesActivation option. This option 30 * can be set to the following values: 31 * none: The option isn't used (default value) 32 * on: Firebug is activated for all URLs. 33 * off: Firebug is never activated. 34 * 35 * This logic has higher priority over the URL annotations. 36 * If "off" options is selected, all existing URL annotations are removed. 37 */ 38 Firebug.Activation = Obj.extend(Firebug.Module, 39 { 40 dispatchName: "activation", 41 42 // called once 43 initializeUI: function() 44 { 45 Firebug.Module.initializeUI.apply(this, arguments); 46 47 TabWatcher.initializeUI(); 48 TabWatcher.addListener(this); 49 }, 50 51 shutdown: function() 52 { 53 Firebug.Module.shutdown.apply(this, arguments); 54 55 TabWatcher.removeListener(this); 56 }, 57 58 // true if the Places annotation the URI "firebugged" 59 shouldCreateContext: function(browser, url, userCommands) 60 { 61 if (FBTrace.DBG_ACTIVATION) 62 FBTrace.sysout("shouldCreateContext allPagesActivation " + 63 Firebug.allPagesActivation); 64 65 if (Firebug.allPagesActivation == "on") 66 return true; 67 68 // if about:blank gets through, issue 1483 fails 69 if (Firebug.filterSystemURLs && Url.isSystemURL(url)) 70 return false; 71 72 if (userCommands) 73 return true; 74 75 // document.open on a firebugged page 76 if (browser && browser.showFirebug && url.substr(0, 8) === "wyciwyg:") 77 return true; 78 79 try 80 { 81 var uri = this.convertToURIKey(url, Firebug.activateSameOrigin); 82 if (!uri) 83 return false; 84 85 var hasAnnotation = Annotations.pageHasAnnotation(uri); 86 87 if (FBTrace.DBG_ACTIVATION) 88 { 89 FBTrace.sysout("shouldCreateContext hasAnnotation " + hasAnnotation + 90 " for " + uri.spec + " in " + 91 (browser ? browser.contentWindow.location : "no browser") + 92 " using activateSameOrigin: " + Firebug.activateSameOrigin); 93 } 94 95 // Annotated, so return the value. 96 if (hasAnnotation) 97 return this.checkAnnotation(browser, uri); 98 99 // Then Firebug.TabWatcher found a connection. 100 if (browser.FirebugLink) 101 { 102 var dst = browser.FirebugLink.dst; 103 var dstURI = this.convertToURIKey(dst.spec, Firebug.activateSameOrigin); 104 105 if (FBTrace.DBG_ACTIVATION) 106 { 107 FBTrace.sysout("shouldCreateContext found FirebugLink pointing to " + 108 dstURI.spec, browser.FirebugLink); 109 } 110 111 // And it matches us now. 112 if (dstURI && dstURI.equals(uri)) 113 { 114 var srcURI = this.convertToURIKey(browser.FirebugLink.src.spec, 115 Firebug.activateSameOrigin); 116 117 if (srcURI) 118 { 119 if (FBTrace.DBG_ACTIVATION) 120 { 121 FBTrace.sysout("shouldCreateContext found FirebugLink pointing from " + 122 srcURI.spec, browser.FirebugLink); 123 } 124 125 // And it's on the same domain. 126 if (srcURI.schemeIs("file") || (dstURI.host == srcURI.host)) 127 { 128 hasAnnotation = Annotations.pageHasAnnotation(srcURI); 129 // And the source page was annotated. 130 if (hasAnnotation) 131 { 132 var srcShow = this.checkAnnotation(browser, srcURI); 133 // And the source annotation said show it. 134 if (srcShow) 135 { 136 // So we show dst as well. 137 this.watchBrowser(browser); 138 } 139 return srcShow; 140 } 141 } 142 } 143 } 144 else 145 { 146 if (FBTrace.DBG_ACTIVATION) 147 FBTrace.sysout("shouldCreateContext FirebugLink does not match " + 148 uri.spec, browser.FirebugLink); 149 } 150 } 151 else if (browser.contentWindow.opener) 152 { 153 var openerContext = Firebug.TabWatcher.getContextByWindow( 154 browser.contentWindow.opener); 155 156 if (FBTrace.DBG_ACTIVATION) 157 FBTrace.sysout("shouldCreateContext opener found, has " + 158 (openerContext ? "a " : "no ") + " context: " + 159 browser.contentWindow.opener.location); 160 161 if (openerContext) 162 { 163 // popup windows of Firebugged windows are Firebugged 164 return true; 165 } 166 } 167 168 // don't createContext 169 return false; 170 } 171 catch (exc) 172 { 173 if (FBTrace.DBG_ERRORS) 174 FBTrace.sysout("pageHasAnnotation FAILS for url: " + url + " which gave uri " + 175 (uri ? uri.spec : "null"), exc); 176 } 177 }, 178 179 shouldShowContext: function(context) 180 { 181 return this.shouldCreateContext(context.browser, context.getWindowLocation().toString()); 182 }, 183 184 // Firebug is opened in the browser. 185 watchBrowser: function(browser) 186 { 187 try 188 { 189 var annotation = "firebugged.showFirebug"; 190 this.setPageAnnotation(browser.currentURI.spec, annotation); 191 } 192 catch (e) 193 { 194 if (FBTrace.DBG_ERRORS) 195 FBTrace.sysout("activation.watchBrowser; EXCEPTION " + e, e); 196 } 197 }, 198 199 // Firebug closes in the browser. 200 unwatchBrowser: function(browser, userCommands) 201 { 202 var uri = browser.currentURI.spec; 203 // Then mark to not open virally. 204 if (userCommands) 205 { 206 this.setPageAnnotation(uri, "firebugged.closed"); 207 } 208 else 209 { 210 // unmark this URI 211 this.removePageAnnotation(uri); 212 } 213 }, 214 215 clearAnnotations: function() 216 { 217 Annotations.clear(); 218 Annotations.flush(); 219 220 Firebug.connection.dispatch("onClearAnnotations", []); 221 }, 222 223 // Process the URL to canonicalize it. This needs not be reversible. 224 convertToURIKey: function(url, sameOrigin) 225 { 226 // Remove the fragment. It shouldn't have any impact on the activation. 227 url = url.replace(/#.*/, ""); 228 229 var uri = Url.makeURI(Url.normalizeURL(url)); 230 231 if (Firebug.filterSystemURLs && Url.isSystemURL(url)) 232 return uri; 233 234 // avoid exceptions 235 if (url == "about:blank") 236 return uri; 237 238 if (uri && sameOrigin) 239 { 240 try 241 { 242 // Returns the string before the path (such as "scheme://user:password@host:port"). 243 var prePath = uri.prePath; 244 var shortURI = Url.makeURI(prePath); 245 if (!shortURI) 246 return uri; 247 248 // Annoying "about" URIs throw if .host is accessed 249 if (shortURI.scheme === "about") 250 return shortURI; 251 252 if (shortURI.scheme === "file") 253 return shortURI; 254 255 return shortURI; 256 257 // This makes a.co.uk -> co.uk, mail.cn.mozilla.com -> cn.mozilla.com and 258 // blog.getfirebug.com -> getfirebug.com, which is wrong. See issue 2202.) 259 /* 260 var host = shortURI.host; 261 if (host) 262 { 263 // Slice the subdomain (if any) from the URL so that activateSameOrigin works 264 // for domains (including TLD domains). So we want: 265 // 1) www.google.com -> google.com 266 // 2) www.stuff.co.nz -> stuff.co.nz 267 // 3) getfirebug.com -> getfirebug.com 268 var levels = host.split('.'); 269 if (levels.length > 2) 270 levels = levels.slice(1); 271 shortURI.host = levels.join('.'); 272 return shortURI; 273 } 274 */ 275 } 276 catch (exc) 277 { 278 if (FBTrace.DBG_ERRORS) 279 FBTrace.sysout("activation.convertToURIKey returning full URI, " + 280 "activateSameOrigin FAILS for shortURI " + shortURI + " because: " + exc, 281 exc); 282 283 return uri; 284 } 285 } 286 287 return uri; 288 }, 289 290 checkAnnotation: function(browser, uri) 291 { 292 var annotation = Annotations.getPageAnnotation(uri); 293 294 if (FBTrace.DBG_ACTIVATION) 295 FBTrace.sysout("shouldCreateContext read back annotation " + annotation + 296 " for uri " + uri.spec); 297 298 // Then the user closed Firebug on this page last time. 299 if ((Firebug.allPagesActivation != "on") && (annotation.indexOf("closed") > 0)) 300 { 301 // annotated as 'closed', don't create 302 return false; 303 } 304 else 305 { 306 // annotated, createContext 307 return true; 308 } 309 }, 310 311 setPageAnnotation: function(currentURI, annotation) 312 { 313 var uri = this.convertToURIKey(currentURI, Firebug.activateSameOrigin); 314 if (uri) 315 Annotations.setPageAnnotation(uri, annotation); 316 317 if (FBTrace.DBG_ACTIVATION || FBTrace.DBG_ANNOTATION) 318 FBTrace.sysout("setPageAnnotation currentURI " + currentURI + " becomes URI key "+ 319 (uri ? uri.spec : "ERROR")); 320 321 if (Firebug.activateSameOrigin) 322 { 323 uri = this.convertToURIKey(currentURI, false); 324 if (uri) 325 Annotations.setPageAnnotation(uri, annotation); 326 327 if (FBTrace.DBG_ACTIVATION || FBTrace.DBG_ANNOTATION) 328 FBTrace.sysout("setPageAnnotation with activeSameOrigin currentURI " + 329 currentURI.spec + " becomes URI key " + (uri ? uri.spec : "ERROR")); 330 } 331 }, 332 333 removePageAnnotation: function(currentURI) 334 { 335 var uri = this.convertToURIKey(currentURI, Firebug.activateSameOrigin); 336 if (uri) 337 Annotations.removePageAnnotation(uri); 338 339 if (Firebug.activateSameOrigin) 340 { 341 uri = this.convertToURIKey(currentURI, false); 342 if (uri) 343 Annotations.removePageAnnotation(uri); 344 } 345 346 if (FBTrace.DBG_ACTIVATION) 347 FBTrace.sysout("Firebug.Activation.unwatchBrowser untagged "+uri.spec); 348 }, 349 350 // Stops at the first fn(uri) that returns a true value. 351 iterateAnnotations: function(fn) 352 { 353 var annotations = Annotations.getAnnotations(this.annotationName); 354 for (var uri in annotations) 355 { 356 var rc = fn(uri, annotations[uri]); 357 if (rc) 358 return rc; 359 } 360 }, 361 }); 362 363 // ********************************************************************************************* // 364 // Registration 365 366 Firebug.registerModule(Firebug.Activation); 367 368 return Firebug.Activation; 369 370 // ********************************************************************************************* // 371 }); 372