Index: dreditor.user.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/dreditor/dreditor.user.js,v
retrieving revision 1.63
diff -u -p -r1.63 dreditor.user.js
--- dreditor.user.js	18 Dec 2010 19:44:04 -0000	1.63
+++ dreditor.user.js	18 Dec 2010 22:02:44 -0000
@@ -8,12 +8,62 @@
 // @include        https://drupal.org/*
 // ==/UserScript==
 
-// Initialize window objects.
-$ = window.$ = window.jQuery = unsafeWindow.jQuery;
-Drupal = window.Drupal = unsafeWindow.Drupal;
-// Bail out in (the unlikely) case that JS has been disabled.
-if (Drupal === undefined) {
-  return false;
+/**
+ * User script environment negotiation and initialization.
+ *
+ * Support and available features for user scripts highly varies across browser
+ * vendors. Some browsers (e.g., Firefox) require to install a browser extension
+ * (GreaseMonkey) in order to install and execute user scripts. Some others
+ * have built-in support for user scripts, but do not support all features of
+ * GreaseMonkey (variable storage, cross-domain XHR, etc). In the special case
+ * of Chrome, user scripts are executed before the DOM has been fully loaded and
+ * initialized; they can only access and manipulate the plain DOM document as
+ * is, but none of the scripts on the actual page are loaded yet.
+ *
+ * Therefore, different environments need to be negotiated:
+ * - A fully-fledged GreaseMonkey environment: Two execution environments exist,
+ *   unsafeWindow and window (scope-limited to the user script). Initialization
+ *   has to ensure that the required objects of unsafeWindow (jQuery and Drupal)
+ *   are available in the scope-limited window.
+ * - A pre-execution environment: None of the scripts on the actual page have
+ *   been loaded or executed yet, so this entire user script cannot do anything.
+ *   The initialization injects a SCRIPT tag into the document and ends. The
+ *   page will load a hosted copy of the entire user script, which will be
+ *   executed within the normal window environment of the actual page.
+ * - A regular window environment (derived from previous bullet): The script is
+ *   executed as if it would have been loaded by the actual page itself.
+ */
+
+// If unsafeWindow is defined, then we are in a user script environment.
+if (typeof unsafeWindow != 'undefined') {
+  // If unsafeWindow does not contain the jQuery object, then we are in a
+  // pre-execution environment and this script will break, since jQuery and
+  // Drupal objects are missing. We inject a SCRIPT tag that loads a hosted
+  // version of the script.
+  if (typeof unsafeWindow.jQuery == 'undefined') {
+    var script = document.createElement("script");
+    script.setAttribute('type', 'text/javascript');
+    // ViewVC on drupalcode.org would involve server-side processing on every
+    // single access, so we use a manual mirror.
+    script.setAttribute('src', 'http://drupal.unleashedmind.com/dreditor/dreditor.user.js');
+    document.getElementsByTagName('head')[0].appendChild(script);
+
+    // End execution.
+    return;
+  }
+
+  // Otherwise, ensure that jQuery and Drupal objects of the unsafeWindow are
+  // available in the scope-limited window environment.
+  // @todo Implement usual closure to provide jQuery in $.
+  $ = window.$ = window.jQuery = unsafeWindow.jQuery;
+  Drupal = window.Drupal = unsafeWindow.Drupal;
+}
+// If we are in a GreaseMonkey environment and JavaScript is disabled, user
+// scripts are executed nevertheless and can still act on the DOM, but none of
+// the scripts on the actual page are executed. Cancel processing in this case.
+// Drupal is also undefined when drupal.org is down.
+if (typeof Drupal == 'undefined') {
+  return;
 }
 
 /**
@@ -31,7 +81,11 @@ if (Drupal === undefined) {
 jQuery.extend({
   debug: function () {
     // Setup debug storage in global window. We want to look into it.
-    window.debug = unsafeWindow.debug = window.debug || [];
+    window.debug = window.debug || {};
+    // @todo Is this needed at all?
+    if (typeof unsafeWindow != 'undefined') {
+      unsafeWindow.debug = window.debug;
+    }
 
     args = jQuery.makeArray(arguments);
     // Determine data source; this is an object for $variable.debug().
