home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 December / PCWorld_2005-12_cd.bin / komunikace / netscape / nsb-install-8-0.exe / chrome / browser.jar / content / browser / spui.js < prev    next >
Text File  |  2005-09-26  |  41KB  |  1,182 lines

  1.  
  2. var spui = {
  3.  
  4.     SPUI_DEBUG : false,     // Set this to false to disable debug output
  5.  
  6.     SPUI_NS : "http://home.netscape.com/NC-spui#",
  7.     SPUI_PREF_BRANCH : "spui.",
  8.     RES_URL : null,
  9.     RES_TYPE : null,
  10.     RES_LABEL : null,
  11.     RES_SRC : null,
  12.     RES_FRAMESTYLE : null,
  13.     RES_PREVIEWIMAGE : null,
  14.     RES_OVERFLOWURL : null,
  15.     RDFService : null,
  16.     RDFDataSource : null,
  17.     RDFLoadObserver : null,
  18.     RemoteRDFLoadObserver : null,
  19.     SPUI_CUSTOM_FEED_PREF_NAME : "spui.newsticker.",
  20.     SPUI_CUSTOM_REF_PREF_NAME : "",
  21. SPUI_BROWSER_VERSION : "8.0.4",
  22.     SPUI_BROWSER_LOCALE : "",
  23.     SPUI_BROWSER_THEME : "",
  24.     k_idleTimer : 2000,
  25.     GLOBALS : new Object(),           // global things that can be referenced by all SPUI's
  26.  
  27.     Init : function() {
  28.         if (gPrefService.getPrefType("spui.debug")) {
  29.             this.SPUI_DEBUG = gPrefService.getBoolPref("spui.debug");
  30.         }
  31.         this.debug("Init()");
  32.         this.SPUI_BROWSER_THEME = gPrefService.getCharPref("general.skins.selectedSkin");
  33.         this.SPUI_BROWSER_LOCALE = gPrefService.getCharPref("general.useragent.locale");
  34.         
  35.         if (!this.RDFService) {
  36.             this.RDFService = Components.classes["@mozilla.org/rdf/rdf-service;1"]
  37.             .getService(Components.interfaces.nsIRDFService);
  38.             this.RES_URL = this.RDFService.GetResource(this.SPUI_NS+'url');
  39.             this.RES_TYPE = this.RDFService.GetResource(this.SPUI_NS+'type');
  40.             this.RES_LABEL = this.RDFService.GetResource(this.SPUI_NS+'label');
  41.             this.RES_TOOLGROUP = this.RDFService.GetResource(this.SPUI_NS+'toolgroup');
  42.             this.RES_SRC = this.RDFService.GetResource(this.SPUI_NS+'src');
  43.             this.RES_FRAMESTYLE = this.RDFService.GetResource(this.SPUI_NS+'framestyle');
  44.             this.RES_PREVIEWIMAGE = this.RDFService.GetResource(this.SPUI_NS+'previewimage');
  45.             this.RES_OVERFLOWURL = this.RDFService.GetResource(this.SPUI_NS+'overflowurl');
  46.             this.RDFDataSource = null;
  47.         }
  48.         if (!this.RDFLoadObserver) {
  49.             this.debug("Instantiating observer");
  50.             this.RDFLoadObserver = {
  51.                 onBeginLoad : function(sink){},
  52.                 onInterrupt : function(sink){},
  53.                 onResume : function(sink){},
  54.                 onError : function(sink,status,msg){},
  55.                 onEndLoad : function(sink) {
  56.                     RDFService = Components.classes["@mozilla.org/rdf/rdf-service;1"]
  57.                     .getService(Components.interfaces.nsIRDFService);
  58.                     this.debug("onEndLoad()");
  59.                     sink.removeXMLSinkObserver(this);
  60.                     sink.QueryInterface(Components.interfaces.nsIRDFDataSource);
  61.                     this.debug('Loaded datasource: '+sink.URI);
  62.                     resources = sink.GetAllResources();
  63.                     while (resources.hasMoreElements()) {
  64.                         res = resources.getNext();
  65.                         res.QueryInterface(Components.interfaces.nsIRDFResource);
  66.                         this.parent.HandleResource(sink, res);
  67.                         // RDFService.UnregisterResource(res);
  68.                     }
  69.                     // RDFService.UnregisterDataSource(sink);
  70.                     // JMC: Just slap ordinals on the spui children to set their toolbar order
  71.                     var toolbar = document.getElementById('navigator-toolbox').firstChild;
  72.                     while (toolbar && (toolbar.localName == 'toolbar' || toolbar.localName == 'multibartray')) {
  73.                         if (toolbar.localName == 'multibar')
  74.                         {
  75.                             toolbar = toolbar.firstChild;
  76.                         } else if (toolbar.localName == 'multibartray' && (!toolbar.nextSibling)) {
  77.                             toolbar.reorderItems();
  78.                             toolbar = toolbar.parentNode.nextSibling;
  79.                         } else {
  80.                             toolbar.reorderItems();
  81.                             toolbar = toolbar.nextSibling;
  82.                         }
  83.                     }
  84.  
  85.                     // Now update from the server
  86.                     this.parent.RefreshRemoteComponents();
  87.                 },
  88.                 debug : function(msg) {
  89.                     this.parent.debug('RDFLoadObserver: '+msg);
  90.                 }
  91.             };
  92.             this.RDFLoadObserver.parent = this;
  93.         }
  94.  
  95.         if (!this.RemoteRDFLoadObserver) {
  96.             this.debug("Instantiating other observer");
  97.             this.RemoteRDFLoadObserver = {
  98.                 bNewComponents : false,
  99.                 newList : null,
  100.                 onBeginLoad : function(sink){},
  101.                 onInterrupt : function(sink){},
  102.                 onResume : function(sink){},
  103.                 onError : function(sink,status,msg){},
  104.                 onEndLoad : function(sink) {
  105.                     RDFService = Components.classes["@mozilla.org/rdf/rdf-service;1"]
  106.                     .getService(Components.interfaces.nsIRDFService);
  107.                     this.debug("onEndLoad()");
  108.                     sink.removeXMLSinkObserver(this);
  109.                     sink.QueryInterface(Components.interfaces.nsIRDFDataSource);
  110.                     this.debug('Loaded datasource: '+sink.URI);
  111.                     resources = sink.GetAllResources();
  112.                     this.bNewComponents = false;
  113.                     this.newList = new Array();
  114.                     while (resources.hasMoreElements()) {
  115.                         res = resources.getNext();
  116.                         res.QueryInterface(Components.interfaces.nsIRDFResource);
  117.                         this.CheckResource(sink, res);
  118.                     //    RDFService.UnregisterResource(res);
  119.                     }
  120.                     // If it's flagged, we'll save it locally
  121.                     //if (this.bNewComponents) {
  122.                     var fileURI = this.parent.GetLocalSupportedFile();
  123.                     sink.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
  124.                     sink.FlushTo(fileURI.spec);
  125.                     if (this.bNewComponents) {
  126.                         this.sendNotify();
  127.                     }
  128.                     // Pop notify
  129.                     //}
  130.                     // RDFService.UnregisterDataSource(sink);
  131.                 },
  132.                 debug : function(msg) {
  133.                     this.parent.debug('RemoteRDFLoadObserver: '+msg);
  134.                 },
  135.  
  136.                 sendNotify : function() {
  137.                     // var showNotification = gPref.getBoolPref("spui.showNotifications");
  138.                     var showNotification = true;
  139.                     if (showNotification) {
  140.                         /*
  141.                         var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
  142.                         .getService(Components.interfaces.nsIStringBundleService);
  143.                         var bundle = sbs.createBundle("chrome://mozapps/locale/update/update.properties");
  144.  
  145.                         var alertTitle = bundle.GetStringFromName("updatesAvailableTitle");
  146.                         var alertText = bundle.GetStringFromName("updatesAvailableText");
  147.                         */
  148.  
  149.                         // JMC - Make a string bundle for this, too
  150.                         var alertText = "";
  151.                         var lineDivider = "|";
  152.                         for (var i = 0; i < this.newList.length; i++) {
  153.                             alertText += this.newList[i] + lineDivider;
  154.                         }
  155.  
  156.                         var alerts = Components.classes["@mozilla.org/alerts-service;1"]
  157.                         .getService(Components.interfaces.nsIAlertsService);
  158.                         alerts.showAlertNotification("chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png",
  159.                         "New Personal Buttons Available",
  160.                         alertText, true, "", this);
  161.                     }
  162.                 },
  163.  
  164.                 QueryInterface: function(aIID)
  165.                 {
  166.                     if (!aIID.equals(Components.interfaces.nsIObserver) &&
  167.                     !aIID.equals(Components.interfaces.nsIAlertListener) &&
  168.                     !aIID.equals(Components.interfaces.nsISupports) &&
  169.                     !aIID.equals(Components.interfaces.nsIRDFXMLSinkObserver))
  170.                     throw Components.results.NS_ERROR_NO_INTERFACE;
  171.                     return this;
  172.                 },
  173.  
  174.                 onAlertClickCallback : function (aAlertCookie)
  175.                 {
  176.                     BrowserCustomizeToolbar();
  177.                 },
  178.  
  179.                 onAlertFinished : function (aAlertCookie) {
  180.                 },
  181.  
  182.                 /*
  183.                 If this component doesn't exist in the palette, it's a new one
  184.  
  185.                 */
  186.                 CheckResource : function(sink, res) {
  187.                     if (!(sink.hasArcOut(res, this.parent.RES_URL) &&
  188.                     sink.hasArcOut(res, this.parent.RES_TYPE) &&
  189.                     sink.hasArcOut(res, this.parent.RES_LABEL)
  190.                     )) {
  191.                         return;
  192.                     }
  193.  
  194.  
  195.                     type = sink.GetTarget(res, this.parent.RES_TYPE, true);
  196.                     type.QueryInterface(Components.interfaces.nsIRDFLiteral);
  197.                     if (type.Value != 'toolbarframe') {
  198.                         return;
  199.                     }
  200.  
  201.                     var toolbox = document.getElementById('navigator-toolbox');
  202.                     var palette = toolbox.palette;
  203.                     var paletteButton = palette.firstChild;
  204.                     while (paletteButton) {
  205.                         if (paletteButton.id == res.Value) {
  206.                             return;
  207.                         }
  208.                         paletteButton = paletteButton.nextSibling;
  209.                     }
  210.                     this.bNewComponents = true;
  211.                     var label = sink.GetTarget(res, this.parent.RES_LABEL, true);
  212.                     label.QueryInterface(Components.interfaces.nsIRDFLiteral);
  213.                     this.newList.push(label.Value);
  214.                     this.parent.HandleResource(sink, res);
  215.                 }
  216.  
  217.             };
  218.             this.RemoteRDFLoadObserver.parent = this;
  219.         }
  220.     },
  221.  
  222.  
  223.     GetLocalSupportedFile : function() {
  224.         var profileDir = Components.classes["@mozilla.org/file/directory_service;1"].
  225.         getService(Components.interfaces.nsIProperties).
  226.         get("ProfD", Components.interfaces.nsIFile);
  227.         profileDir.append("supported-spui-components.rdf");
  228.  
  229.         var ios = Components.classes["@mozilla.org/network/io-service;1"]
  230.         .getService(Components.interfaces.nsIIOService);
  231.         var fileURI = ios.newFileURI(profileDir);
  232.         return fileURI;
  233.     },
  234.  
  235.  
  236.     RefreshRemoteComponents : function() {
  237.         this.debug("RefreshRemoteComponents()");
  238.  
  239.         // var user_guid = gPrefService.getCharPref("browser.info.guid");
  240.         // var partnerId;
  241.         // try {
  242.         //    partnerId = gPrefService.getCharPref("browser.partnerId");
  243.         //} catch (ex) {
  244.         //    partnerId = 'chapera';
  245.         // }
  246.         var SPUI_LOCAL_RDF_URL = gPrefService.getCharPref("spui.supportedURL");
  247.         //+ "?guid=" + user_guid + "&partnerId=" + partnerId;
  248.         try {
  249.             this.RDFDataSource = this.RDFService.GetDataSource(SPUI_LOCAL_RDF_URL);
  250.             this.RDFDataSource.QueryInterface(Components.interfaces.nsIRDFXMLSink);
  251.             this.RDFDataSource.addXMLSinkObserver(this.RemoteRDFLoadObserver);
  252.         } catch (ex) { }
  253.  
  254.         this.debug("Finished RefreshRemoteComponents()");
  255.     },
  256.  
  257.     PersistPref: function (newSpuiIds) {
  258.         var branch = gPrefService.getBranch("spui.");
  259.         var prefs = branch.getChildList("", {});
  260.         for(var i = 0; i < prefs.length; i++) {
  261.             var tokens = prefs[i].split(".");
  262.             if(tokens.length > 0 && !isNaN(tokens[0])) {
  263.                 var oldId = tokens[0];
  264.                 if(!(oldId in newSpuiIds)) {
  265.                     branch.deleteBranch("" + prefs[i] + ".");
  266.                     dump("deleting .. " + prefs[i]);
  267.                 }
  268.             }
  269.         }
  270.     },
  271.  
  272.     /**
  273.     * Grabs a local RDF file describing what SPUI components are
  274.     * currently available, and sets listener on the loading of that
  275.     * file.
  276.     **/
  277.     RefreshComponentList : function() {
  278.         this.debug("RefreshComponentList()");
  279.         this.Init();
  280.  
  281.         // Load the local supported file, build the toolbar and palette
  282.         // Then load the remote file
  283.  
  284.         // For each component in the remote file,
  285.         // If it doesn't exist in the palette,
  286.         // Then add it to the array of new ones,
  287.         // and set the flag to notify and copy.
  288.  
  289.         // When done, check flag.
  290.         // If true, copy the remote rdf file into the local file.
  291.         // And call notification service
  292.  
  293.         // get profile directory
  294.         var fileURI = this.GetLocalSupportedFile();
  295.         // this.debug("Gonna go get local file called : " + fileURI.spec + "\n");
  296.         try {
  297.             // Start loading RDF file of supported components
  298.             // this.RDFDataSource = this.RDFService.GetDataSource(SPUI_LOCAL_RDF_URL);
  299.             this.RDFDataSource = this.RDFService.GetDataSource(fileURI.spec);
  300.  
  301.             // Register a listener to pick things up when the file is done
  302.             // loading.  (Control will go to the onEndLoad function...)
  303.             this.RDFDataSource.QueryInterface(Components.interfaces.nsIRDFXMLSink);
  304.             this.RDFDataSource.addXMLSinkObserver(this.RDFLoadObserver);
  305.  
  306.         } catch (ex) {  this.RefreshRemoteComponents(); }
  307.         // For now, tell the RDF Service NOT to cache our datasource,
  308.         // because we don't know how to handle that properly yet.
  309.         // this.RDFService.UnregisterDataSource(this.RDFDataSource);
  310.  
  311.         this.debug("Finished RefreshComponentList()");
  312.     },
  313.  
  314.     
  315.     /**
  316.     * Called after browser customize finishes, to re-establish SPUI links
  317.     * with all the active items.
  318.     **/
  319.     RedrawComponents : function() {
  320.         var newSpuiIds = new Object();
  321.         this.debug("Redrawing Components after browser customize...\n" );
  322.         var toolbox = document.getElementById('navigator-toolbox');
  323.         var toolbar = toolbox.firstChild;
  324.         while (toolbar) {
  325.             // this.debug(' Redrawing toolbar: '+toolbar.id+', currentSet: ' +toolbar.currentSetAtLoadTime);
  326.             var spuiButton = toolbar.firstChild;
  327.             while (spuiButton) {
  328.                 // this.debug(' SpuiButton is '+spuiButton.id + '\n');
  329.  
  330.                 var tokens = spuiButton.id.split('|');
  331.                 if(tokens.length > 0 && !isNaN(tokens[tokens.length-1])) {
  332.                     newSpuiIds[tokens[tokens.length-1]] = "new";
  333.                 }
  334.                             
  335.                 var iframe = document.getElementById(spuiButton.id+'-iframe');
  336.                 if (iframe) {
  337.                     setTimeout("establishRemoteSPUILink('"+spuiButton.id+"');",500);
  338.                 }
  339.                 spuiButton = spuiButton.nextSibling;
  340.             }
  341.             if (toolbar.localName == 'multibar')
  342.             {
  343.                 toolbar = toolbar.firstChild;
  344.             } else if (toolbar.localName == 'multibartray' && (!toolbar.nextSibling)) {
  345.                 toolbar = toolbar.parentNode.nextSibling;
  346.             } else {
  347.                 toolbar = toolbar.nextSibling;
  348.             }
  349.         }
  350.         this.PersistPref(newSpuiIds);
  351.     },
  352.  
  353.     /**
  354.     * Parse the description for a particular resource
  355.     **/
  356.     HandleResource : function(datasource, res) {
  357.         // this.debug('Found resource: '+res.Value);
  358.         // This is basically just debug output
  359.         var labels = datasource.ArcLabelsOut(res);
  360.         while (labels.hasMoreElements()) {
  361.             var label = labels.getNext();
  362.             if (label instanceof Components.interfaces.nsIRDFResource) {
  363.                 var dbg = '* '+label.Value;
  364.                 var target = datasource.GetTarget(res, label, true);
  365.                 if (target instanceof Components.interfaces.nsIRDFResource) {
  366.                     dbg += ' => '+target.Value;
  367.                 } else if (target instanceof Components.interfaces.nsIRDFLiteral) {
  368.                     dbg += ' => '+target.Value;
  369.                 } else {
  370.                     try {
  371.                         dbg += ' => '+target.Value;
  372.                     } catch (ex) { }
  373.                 }
  374.                 // this.debug(dbg);
  375.             }
  376.         }
  377.         // See if this resource specifies an actual SPUI component
  378.         if (datasource.hasArcOut(res, this.RES_URL) &&
  379.         datasource.hasArcOut(res, this.RES_TYPE) &&
  380.         datasource.hasArcOut(res, this.RES_LABEL))
  381.         {
  382.             // this.debug('^** this is a SPUI component! **^');
  383.             this.HandleComponent(datasource, res);
  384.         }
  385.     },
  386.  
  387.  
  388.     /**
  389.     * Handle SPUI component loading
  390.     **/
  391.     HandleComponent : function(datasource, res) {
  392.         // this.debug('HandleComponent('+res.Value+')');
  393.         type = datasource.GetTarget(res, this.RES_TYPE, true);
  394.         type.QueryInterface(Components.interfaces.nsIRDFLiteral);
  395.         if (type.Value == 'toolbarframe') {
  396.             this.HandleToolbaritem(datasource, res);
  397.         } else {
  398.             this.debug('*** WARNING: component type not handled: '+type.Value);
  399.         }
  400.     },
  401.     
  402.     ConstructComponent : function(datasource, res, newid) {
  403.         // Construct the new XUL component
  404.         // this.debug('ConstructComponent('+res.Value+')');
  405.         try {
  406.             var newItem = document.createElement('toolbaritem');
  407.             newItem.setAttribute('id', newid);
  408.             var label = datasource.GetTarget(res, this.RES_LABEL, true);
  409.             label.QueryInterface(Components.interfaces.nsIRDFLiteral);
  410.             // JMC added to support multiple customize panels
  411.             var toolgroup = datasource.GetTarget(res, this.RES_TOOLGROUP, true);
  412.             toolgroup.QueryInterface(Components.interfaces.nsIRDFLiteral);
  413.             newItem.setAttribute('label', label.Value);
  414.             newItem.setAttribute('title', label.Value);
  415.             newItem.setAttribute('class', 'spui-toolbaritem');
  416.             newItem.setAttribute('toolgroup', toolgroup.Value);
  417.             if (datasource.hasArcOut(res,this.RES_OVERFLOWURL)) {
  418.                 var ovfURL = datasource.GetTarget(res, this.RES_OVERFLOWURL, true);
  419.                 ovfURL.QueryInterface(Components.interfaces.nsIRDFLiteral);
  420.                 newItem.setAttribute('overflowcommand','loadURIWithOpenPref("'+ovfURL.Value+'","browser.tabs.personaltoolbarbutton.open",null,null);');
  421.             }
  422.             // JMC - should read this from the rdf
  423.             var vbox = document.createElement('vbox');
  424.             var iframe = document.createElement('iframe');
  425.             var src = datasource.GetTarget(res, this.RES_SRC, true);
  426.             src.QueryInterface(Components.interfaces.nsIRDFLiteral);
  427.             iframe.setAttribute('id', newid+'-iframe');
  428.             iframe.setAttribute('name', newid+'-iframe');
  429.             iframe.setAttribute('type','content');
  430.             iframe.setAttribute('src', src.Value);
  431.             iframe.setAttribute('flex', '1');
  432.             iframe.setAttribute('allowtransparency',true);
  433.             iframe.setAttribute('scrolling','no');    
  434.             iframe.setAttribute('isActive', 'true');
  435.  
  436.             var framestyle = datasource.GetTarget(res, this.RES_FRAMESTYLE, true);
  437.             var iframestyle = "visibility: hidden;";
  438.             if (framestyle) {
  439.                 framestyle.QueryInterface(Components.interfaces.nsIRDFLiteral);
  440.                 iframestyle += framestyle.Value;    
  441.             }                    
  442.             iframe.setAttribute('style', iframestyle);
  443.                             
  444.             newItem.setAttribute('allowDuplicate', true);
  445.             // JMC - Can be duplicate? Get property from RDF, push into button
  446.             vbox.appendChild(iframe);
  447.             vbox.setAttribute('class', 'spui-content');
  448.             var previewSrc = datasource.GetTarget(res, this.RES_PREVIEWIMAGE, true);
  449.             previewSrc.QueryInterface(Components.interfaces.nsIRDFLiteral);
  450.             previewImage = document.createElement('image');
  451.             previewImage.setAttribute('src', previewSrc.Value);
  452.             var spacer = document.createElement('spacer');
  453.             previewBox = document.createElement('toolbarbutton');
  454.             previewBox.appendChild(previewImage);
  455.             previewBox.setAttribute('class', 'spui-preview');
  456.             previewBox.setAttribute('mousethrough', 'never');
  457.             previewBox.setAttribute('label', label.Value);
  458.             var draggableBox = document.createElement('toolbarbutton');
  459.             draggableBox.setAttribute('class', 'spui-draggable');
  460.             draggableBox.setAttribute('mousethrough', 'never');
  461.             draggableBox.setAttribute('label', label.Value);
  462.             if (framestyle) {
  463.                 previewBox.setAttribute('style', framestyle.Value);
  464.                 draggableBox.setAttribute('style', framestyle.Value);
  465.             }
  466.             var stack = document.createElement('stack');
  467.             stack.appendChild(vbox);
  468.             stack.appendChild(previewBox);
  469.             stack.appendChild(draggableBox);
  470.             newItem.appendChild(stack);
  471.             iframe.setAttribute('onload', "establishRemoteSPUILink('"+newid+"');"); // JMC: Is this right?
  472.             return newItem;
  473.         } catch (ex) {
  474.             this.debug('WARNING: could not create component!');
  475.             return;
  476.         }
  477.     },
  478.  
  479.     /**
  480.     * Handle toolbar item components
  481.     **/
  482.     HandleToolbaritem : function(datasource, res) {
  483.         // this.debug('HandleToobaritem('+res.Value+')');
  484.         var newSpuiIds = new Object();
  485.         // See if this component is supposed to go in a toolbar
  486.         // or just into the tool palette
  487.  
  488.         var toolbox = document.getElementById('navigator-toolbox');
  489.         var toolbar = toolbox.firstChild;
  490.         var placed = true; // Force to create first component
  491.         while (toolbar) {
  492.             if (toolbar.currentSetAtLoadTime) {
  493.                 // this.debug(' looking at toolbar: '+toolbar.id+', currentSet: '+toolbar.currentSetAtLoadTime);
  494.                 var currentSet = toolbar.currentSetAtLoadTime.split(',');
  495.                 for (var i = 0; i < currentSet.length; i++) {
  496.                     placed = false;
  497.                     // this.debug('  '+currentSet[i]);
  498.  
  499.                     // JMC - Peel the unique ID off the toolbar currentSet
  500.                     // And match against the base id
  501.                     // Save the suffix
  502.  
  503.                     var suffix;
  504.                     var baseId;
  505.  
  506.                     if (currentSet[i].indexOf("|") > -1) // This has a unique id
  507.                     {
  508.                         suffix = currentSet[i].substring(currentSet[i].indexOf("|") + 1,currentSet[i].length);
  509.                         baseId = currentSet[i].substring(0, currentSet[i].indexOf("|"));
  510.                         newSpuiIds[suffix] = "new";
  511.                     } else {
  512.                         baseId = currentSet[i];
  513.                     }
  514.  
  515.                     if (baseId == res.Value) {
  516.                         // Found it!
  517.                         var newid = res.Value;
  518.                         // JMC - Update the ids with the suffix
  519.                         if (suffix) {
  520.                             newid = res.Value + "|" + suffix;
  521.                         }
  522.                         var newItem = this.ConstructComponent(datasource, res, newid);
  523.  
  524.                         placed = this.placeItemRelative(newItem, toolbar, currentSet, i, 10);
  525.                         if (!placed) {
  526.                             // That didn't work, so just tack it on the end
  527.                             toolbar.appendChild(newItem);
  528.                             this.debug('   placed at end of toolbar!');
  529.                             placed = true;
  530.                         }
  531.                         setTimeout("establishRemoteSPUILink('"+newItem.id+"');",500);
  532.                         // JMC: removed to support dups -- break;
  533.                     }
  534.                 }
  535.             }
  536.             if (toolbar.localName == 'multibar')
  537.             {
  538.                 toolbar = toolbar.firstChild;
  539.             } else if (toolbar.localName == 'multibartray' && (!toolbar.nextSibling)) {
  540.                 toolbar = toolbar.parentNode.nextSibling;
  541.             } else {
  542.                 toolbar = toolbar.nextSibling;
  543.             }
  544.         }
  545.  
  546.         // Regardless of whether this component got placed on a toolbar, we still
  547.         // need to put it in the tool palette as well, because that represents the
  548.         // set of all available toolbar items.
  549.         // this.debug(' No appropriate toolbar, so putting it on the palette.');
  550.         var palette = toolbox.palette;
  551.         var newItem = this.ConstructComponent(datasource, res, res.Value);
  552.         palette.appendChild(newItem);
  553.         this.PersistPref(newSpuiIds);
  554.     },
  555.  
  556.     placeItemRelative : function(newItem, toolbar, currentSet, index) {
  557.  
  558.         var bestBefore;
  559.         var beforeMe;
  560.         if (index == currentSet.length - 1) {
  561.             toolbar.appendChild(newItem);
  562.             return;
  563.         }
  564.  
  565.         if (currentSet[index+1] &&
  566.         (currentSet[index+1] == 'spring') ||
  567.         (currentSet[index+1] == 'spacer') ||
  568.         (currentSet[index+1] == 'separator'))
  569.         {
  570.             // How many to be before?
  571.             var i;
  572.             var itemCount = 0;
  573.             for (i = currentSet.length; i > index; --i)
  574.             {
  575.                 if (currentSet[index+1] == currentSet[i])
  576.                 itemCount++;
  577.             }
  578.  
  579.             // Get the nth instance of this item,
  580.             // and insert before it
  581.             var instanceCount = 0;
  582.             var child = toolbar.lastChild;
  583.             while (child)
  584.             {
  585.                 if (currentSet[index+1] == child.id.substring(0,child.id.indexOf("|")))
  586.                 {
  587.                     this.debug("placement: found a matching " + currentSet[index+1]);
  588.                     instanceCount++;
  589.                     if (instanceCount == itemCount) {
  590.                         beforeMe = child;
  591.                         break;
  592.                     }
  593.                 }
  594.                 child = child.previousSibling;
  595.             }
  596.         } else {
  597.             for (var j=currentSet.length; j > index; --j)
  598.             {
  599.                 var toolbarChild = document.getElementById(currentSet[j]);
  600.                 if (!toolbarChild) continue;
  601.                 beforeMe = toolbarChild;
  602.             }
  603.         }
  604.         toolbar.insertBefore(newItem, beforeMe);
  605.         return true;
  606.     },
  607.     /*
  608.     placeItemRelative2 : function(newItem, toolbar, currentSet, index, maxIterations) {
  609.     // Look for toolbar buttons that are progressively further away in
  610.     // the currentSet
  611.  
  612.     // JMC - Special case, index = 0
  613.  
  614.     if (index == 0) {
  615.     var nextItem = toolbar.firstChild;
  616.     if (nextItem) {
  617.     toolbar.insertBefore(newItem, nextItem);
  618.     } else {
  619.     toolbar.appendChild(newItem);
  620.     }
  621.     return true;
  622.     }
  623.  
  624.     var j = 1;
  625.     var placed = false;
  626.     if (!maxIterations) maxIterations = 10;
  627.     while (!placed && (j < maxIterations)) {
  628.     // First try placing it AFTER the previous item
  629.     var nextItem;
  630.     if (index >= j) {
  631.     // this doesnt work for spacers and other anonymous elements
  632.     var prevItem = document.getElementById(currentSet[index-j]);
  633.     if (!prevItem)
  634.     {
  635.     // Count the number of these special elements which occur in the toolbarset
  636.     // BEFORE this point, and then get the xth of them
  637.     var specialCountLimit = 0;
  638.     for (var i=0; i < index; i++) {
  639.     if (currentSet[i] == currentSet[index-j])
  640.     specialCountLimit++;
  641.     }
  642.  
  643.     var paletteItem = toolbar.firstChild;
  644.     var specialCount =0;
  645.  
  646.     while (paletteItem) {
  647.     var paletteId = paletteItem.id;
  648.     var stringLen = currentSet[index-j].length;
  649.     var aId = currentSet[index-j];
  650.     if (paletteId.substring(0,stringLen) == aId) {
  651.     specialCount++;
  652.     if (specialCount >= specialCountLimit) {
  653.     prevItem = paletteItem;
  654.     break;
  655.     }
  656.     }
  657.     paletteItem = paletteItem.nextSibling;
  658.     }
  659.     }
  660.     if (prevItem) {
  661.     nextItem = prevItem.nextSibling;
  662.     if (prevItem.nextSibling) {
  663.     toolbar.insertBefore(newItem, prevItem.nextSibling);
  664.     this.debug('   placed after '+currentSet[index-j]+'!');
  665.     placed = true;
  666.     } else {
  667.     toolbar.appendChild(newItem);
  668.     placed = true;
  669.     }
  670.     }
  671.     }
  672.     if (!placed && (index < currentSet.length-j)) {
  673.     // That didn't work, so try placing it BEFORE the next item
  674.     nextItem = document.getElementById(currentSet[index+1]);
  675.     if (!nextItem)
  676.     {
  677.     // Count the number of these special elements which occur in the toolbarset
  678.     // BEFORE this point, and then get the xth of them
  679.     var specialCountLimit = 0;
  680.     for (var i=index; i > 0; i--) {
  681.     if (currentSet[i] == currentSet[index+1])
  682.     specialCountLimit++;
  683.     }
  684.  
  685.     var paletteItem = toolbar.lastChild;
  686.     var specialCount =0;
  687.  
  688.     while (paletteItem) {
  689.     var paletteId = paletteItem.id;
  690.     var stringLen = currentSet[index+1].length;
  691.     var aId = currentSet[index+1];
  692.     if (paletteId.substring(0,stringLen) == aId) {
  693.     specialCount++;
  694.     if (specialCount >= specialCountLimit) {
  695.     nextItem = paletteItem;
  696.     break;
  697.     }
  698.     }
  699.     paletteItem = paletteItem.previousSibling;
  700.     }
  701.     }
  702.     if (nextItem) {
  703.     toolbar.insertBefore(newItem, nextItem);
  704.     this.debug('   placed before '+currentSet[index+1]+'!');
  705.     placed = true;
  706.     }
  707.     }
  708.     j++;
  709.     }
  710.     return placed;
  711.     },
  712.     */
  713.  
  714.     /**
  715.     * Print out debug text
  716.     **/
  717.     logger : null,
  718.  
  719.     debug : function(msg) {
  720.         // To disabled debug output, set SPUI_DEBUG to "false"
  721.         // at the top of this file
  722.         if (gPrefService.getPrefType("spui.debug") && gPrefService.getBoolPref("spui.debug")) {
  723.             if (!this.logger) {
  724.                 this.logger = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
  725.             }
  726.             dump('SPUI: '+msg+'\n');
  727.             this.logger.logStringMessage("SPUI: " + msg.replace(/\n/g, " -- "));
  728.         }
  729.     },
  730.  
  731.     /*
  732.  
  733.  
  734.     */
  735.     addLivemark : function(baseURL, feedURL, title ) {
  736.         // JMC: Which toolbar to add to?
  737.         var toolbar = document.getElementById('PersonalToolbar');
  738.         var newButton = toolbar.insertItem('spui:newsticker', null, null, null);
  739.         var componentId = newButton.id.substring(newButton.id.indexOf("|") + 1, newButton.id.length);
  740.         // JMC: ugly, should be wrapped up somewhere else
  741.  
  742.         gPrefService.setCharPref('spui.' + componentId + '.newsticker.feed', 'custom');
  743.         gPrefService.setCharPref('spui.' + componentId + '.newsticker.customfeed', feedURL);
  744.         gPrefService.setCharPref('spui.' + componentId + '.newsticker.customref', baseURL);
  745.         this.debug("live bookmark id " + componentId);
  746.         this.RedrawComponents();
  747.     }
  748. };
  749.  
  750.  
  751. /**
  752. * TODO: this should actually be a listener on the iframe contentDocument, instead
  753. * of polling.
  754. **/
  755. function establishRemoteSPUILink(componentId, accumulator) {
  756.     if (!accumulator) accumulator = 0;
  757.     // spui.debug('establishRemoteSPUILink('+componentId+','+accumulator+')');
  758.     if (accumulator >= 30000) return; // timeout after 30 secs
  759.     var iframe = document.getElementById(componentId+'-iframe');
  760.     var wait = 0;
  761.     do { // Check for starting conditions
  762.         if (!iframe) {
  763.             spui.debug('WARNING: component does not have iframe: '+componentId);
  764.             wait = 2500;
  765.             break;
  766.         }
  767.         var contentDoc = iframe.contentDocument;
  768.         if (!contentDoc) {
  769.             spui.debug('WARNING: component does not have contentDocument: '+componentId);
  770.             wait = 500;
  771.             break;
  772.         }
  773.         var docURL = contentDoc.location;
  774.         if (!docURL) {
  775.             spui.debug('WARNING: component does not have contentDocument.location: '
  776.             +componentId);
  777.             wait = 500;
  778.             break;
  779.         }
  780.         else if (docURL == 'about:blank') {
  781.             spui.debug('WARNING: component URL is [about:blank]: '+componentId);
  782.             wait = 500;
  783.             break;
  784.         }
  785.         else if(String(contentDoc.documentElement).indexOf("XULElement") < 0) {
  786.             spui.debug('WARNING: ' + contentDoc.URL + ' is not xul - '+contentDoc.documentElement);
  787.             wait = 500;
  788.             break;
  789.         }        
  790.     } while (false);
  791.             
  792.     if (wait) {
  793.         accumulator += wait;
  794.         setTimeout("establishRemoteSPUILink('"+componentId+"',"
  795.         +accumulator+");",wait); // Try again later
  796.         return;
  797.     }
  798.  
  799.  
  800.     var iframestyle = String(iframe.getAttribute('style'));
  801.     var indhi = iframestyle.indexOf("hidden;");    
  802.     if(indhi >= 0) {
  803.         iframe.setAttribute('style', iframestyle.substring(0,indhi) + "visible;" +iframestyle.substring(indhi + "hidden;".length));
  804.     }    
  805.     
  806.     if (!('spui' in contentDoc))
  807.     {
  808.         // Here is where we make some special browser functions available to the
  809.         // remote document
  810.         contentDoc.spui = new Object();
  811.  
  812.         // JMC: Pass the id in to the component here
  813.         contentDoc.spui.componentId = componentId.substring(componentId.indexOf("|")+1,componentId.length);
  814.  
  815.         // JMC: Save pointer to iframe parent, for resizing, etc
  816.         contentDoc.spui.iframe = iframe;
  817.  
  818.         // JMC: Todo - Push modification time of local supported.rdf into variable for tool tip
  819.  
  820.         // loadURI(uri) - loads URI in the main content window
  821.         contentDoc.spui.loadURI = function(uri) {
  822.             if (gPrefService.getCharPref("browser.tabs.personaltoolbarbutton.open") == 'overwrite') {
  823.                 loadURI(uri);
  824.             } else {
  825.                 this.loadURIInTab(uri);
  826.             }
  827.         };
  828.  
  829.         // loadURIInTab(uri) - loads URI in a new tab
  830.         contentDoc.spui.loadURIInTab = function(uri) {
  831.             var theTab = gBrowser.addTabAt(uri);
  832.             if (!gPrefService.getBoolPref("browser.tabs.loadInBackground"))
  833.             gBrowser.selectedTab = theTab;
  834.         };
  835.  
  836.         // JMC - Support for favicon locating for newsticker icons, etc
  837.         contentDoc.spui.getFaviconURI = function(fullurl) {
  838.             var ios = Components.classes["@mozilla.org/network/io-service;1"]
  839.             .getService(Components.interfaces.nsIIOService);
  840.             var aURI = ios.newURI(fullurl, null, null);
  841.             return gBrowser.buildFavIconString(aURI);
  842.         };
  843.  
  844.         // debug(text) - debug output
  845.         contentDoc.spui.debug = function(text) {
  846.             spui.debug(componentId+': '+text.replace(/\n/, " -- "));
  847.         };
  848.  
  849.         contentDoc.spui.trackData = function(commandObject) {
  850.             perfmon.trackData(commandObject);
  851.         };
  852.  
  853.         contentDoc.spui.resizeComponent = function(newWidth) {
  854.             contentDoc.spui.iframe.setAttribute('style', 'width: ' + newWidth);
  855.             // JMC: Change size of preview and draggable as well
  856.             var parentComponent = document.getElementById(contentDoc.spui.iframe.id.substring(0,contentDoc.spui.iframe.id.length - 7));
  857.             var parentStack = parentComponent.firstChild;
  858.             for (var i =0; i < parentStack.childNodes.length; i++) {
  859.                 var thisChild = parentStack.childNodes[i];
  860.                 if (thisChild.localName == "toolbarbutton") { // Preview and Draggable Boxes
  861.                     thisChild.setAttribute('style', 'width: ' + newWidth);
  862.                 }
  863.             }
  864.             contentDoc.spui.iframe.setAttribute('style', 'width: ' + newWidth);
  865.             reshuffleToolbars(true);
  866.         };
  867.  
  868.         // allow getting of preferences that start with "spui."
  869.         contentDoc.spui.getPref = function(prefName) {
  870.             //contentDoc.spui.debug("getPref called with: " + prefName);
  871.             var prefService = Components.classes["@mozilla.org/preferences-service;1"]
  872.             .getService(Components.interfaces.nsIPrefService);
  873.             var thesePrefs = prefService.getBranch("spui.");
  874.             var prefType = thesePrefs.getPrefType(prefName);
  875.             var userPrefValue = "";
  876.             switch (prefType) {
  877.                 case thesePrefs.PREF_STRING:
  878.                 userPrefValue = thesePrefs.getCharPref(prefName);
  879.                 break;
  880.                 case thesePrefs.PREF_INT:
  881.                 userPrefValue = thesePrefs.getIntPref(prefName);
  882.                 break;
  883.                 case thesePrefs.PREF_BOOL:
  884.                 userPrefValue = thesePrefs.getBoolPref(prefName);
  885.                 break;
  886.             }
  887.             
  888.             return userPrefValue;
  889.         };
  890.  
  891.         // Wrapper for getting localized prefs (per button by componentId)
  892.         contentDoc.spui.getLocalPref = function (prefName) {
  893.             var userPrefValue = contentDoc.spui.getPref(contentDoc.spui.componentId + "." + prefName);
  894.             if (!userPrefValue) {
  895.                 userPrefValue = contentDoc.spui.getPref(prefName);
  896.             }
  897.             return userPrefValue;
  898.         };
  899.  
  900.         // Wrapper for setting localized prefs (per button by componentId)
  901.         contentDoc.spui.setLocalPref = function (prefName, prefValue, prefType) {
  902.             return contentDoc.spui.setPref(contentDoc.spui.componentId + "." + prefName, prefValue, prefType);
  903.         };
  904.  
  905.         contentDoc.spui.clearLocalPref = function (prefName) {
  906.             var branch = "spui." + contentDoc.spui.componentId + "."
  907.             if(prefName && prefName.length > 0) {
  908.                 branch += prefName + ".";
  909.             }
  910.             var prefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
  911.             var thesePrefs = prefService.getBranch(branch);
  912.             thesePrefs.deleteBranch("");
  913.         };
  914.         
  915.         // allow setting of preferences that start with "spui."
  916.         contentDoc.spui.setPref = function(prefName, prefValue, prefType) {
  917.             //contentDoc.spui.debug("setPref called with: " + prefName +", " + prefValue);
  918.             var prefService = Components.classes["@mozilla.org/preferences-service;1"]
  919.             .getService(Components.interfaces.nsIPrefService);
  920.             var thesePrefs = prefService.getBranch("spui.");
  921.             switch (prefType) {
  922.                 case "STRING":
  923.                 thesePrefs.setCharPref(prefName, prefValue);
  924.                 break;
  925.                 case "INT":
  926.                 thesePrefs.setIntPref(prefName, prefValue);
  927.                 break;
  928.                 case "BOOL":
  929.                 thesePrefs.setBoolPref(prefName, prefValue);
  930.                 break;
  931.             }
  932.         };
  933.  
  934.  
  935.         contentDoc.spui.setHomePage = function(aUrl, bAppend) {
  936.             var prefService = Components.classes["@mozilla.org/preferences-service;1"]
  937.             .getService(Components.interfaces.nsIPrefService);
  938.  
  939.             if (bAppend) {
  940.                 var homePage = prefService.getComplexValue("browser.startup.homepage", Components.interfaces.nsIPrefLocalizedString).data;
  941.                 if(homePage) {
  942.                     newHomePage = homePage + "|" + aUrl;
  943.                 } else {
  944.                     newHomePage = aUrl;
  945.                 }
  946.                 prefService.setCharPref("browser.startup.homepage", newHomePage);
  947.             } else {
  948.                 prefService.setCharPref("browser.startup.homepage", aUrl);
  949.             }
  950.  
  951.         };
  952.  
  953.         contentDoc.spui.getHomePage = function() {
  954.             var prefService = Components.classes["@mozilla.org/preferences-service;1"]
  955.             .getService(Components.interfaces.nsIPrefService);
  956.             return prefService.getComplexValue("browser.startup.homepage", Components.interfaces.nsIPrefLocalizedString).data;
  957.         };
  958.  
  959.         // loadRDF(rdf, observer) - returns a datasource
  960.         contentDoc.spui.loadRDF = function(rdf, observer) {
  961.             var RDFService = Components.classes["@mozilla.org/rdf/rdf-service;1"]
  962.             .getService(Components.interfaces.nsIRDFService);
  963.             var ds = RDFService.GetDataSource(rdf);
  964.             ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
  965.             ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
  966.             ds.addXMLSinkObserver(observer);
  967.             return ds;
  968.         };
  969.  
  970.         contentDoc.spui.httpRequest = null;
  971.         contentDoc.spui.lastRequestURL = null;
  972.         
  973.         contentDoc.spui.idleTimerId=null;
  974.  
  975.         /* contentDoc.spui.requestServerData
  976.          * Makes an XMLHttp Request to the server for data.
  977.          */
  978.         contentDoc.spui.requestServerData = function(requestURL, callbackFunc) {            
  979.  
  980. // JMC: Finding memleak
  981. /*
  982.             if (contentDoc.spui.httpRequest){
  983.                 spui.debug("contentDoc.spui.httpRequest = null");
  984.                 contentDoc.spui.httpRequest = null;
  985.             }
  986.  
  987.             contentDoc.spui.httpRequest = new XMLHttpRequest();
  988.             contentDoc.spui.httpRequest.onload = callbackFunc;
  989. */
  990.             contentDoc.spui.debug("contentDoc.spui.requestServerData : requestURL = " + requestURL + "\n");
  991.             var requestAnswered;
  992.             if(!contentDoc.spui.getPref("isIdleAble") || !contentDoc.spui.lastRequestURL || iframe.contentWindow.screenX > 0 - 5000 && iframe.contentWindow.screenY > 0 - 2000 && iframe.getAttribute('isActive') == 'true') {                            
  993.                 var httpRequest = new XMLHttpRequest();                
  994.                 httpRequest.onload = callbackFunc;
  995.     
  996.                 //Make the connection and send our data
  997.                 try {
  998.                 //    contentDoc.spui.httpRequest.open("GET", requestURL, true, null, null);
  999.                 //    contentDoc.spui.httpRequest.send('');
  1000.                     contentDoc.spui.lastRequestURL = requestURL;                
  1001.                     httpRequest.open("GET", requestURL, true, null, null);
  1002.                     httpRequest.send('');
  1003.                     contentDoc.spui.debug("query done\n");
  1004.                     requestAnswered = true;
  1005.                 }
  1006.                 catch (e){
  1007.                     dump('An error has occured calling the external site: '+e);
  1008.                     requestAnswered = false;
  1009.                     httpRequest=null;  // Clean up the httpRequest
  1010.                 }
  1011.             }
  1012.             else {
  1013.                     contentDoc.spui.debug(" isActive=" + iframe.getAttribute('isActive') + " screenY=" + iframe.contentWindow.screenY + " screenX=" + iframe.contentWindow.screenX + "\n");
  1014.                 requestAnswered = false;
  1015.             }
  1016.             contentDoc.spui.debug("contentDoc.spui.requestServerData : requestAnswered = " + requestAnswered + "\n");
  1017.                     
  1018.             // Check to see if the contentDoc.spui.idleTimerId is aready set,
  1019.             // if it is, clear it for the restart.
  1020.             if(!requestAnswered) {
  1021.                 contentDoc.spui.debug("Idle Request");
  1022.                 if(contentDoc.spui.idleTimerId){
  1023.                     contentDoc.spui.debug("Clearing contentDoc.spui.idleTimerId");
  1024.                     clearTimeout(contentDoc.spui.idleTimerId);
  1025.                     contentDoc.spui.idleTimerId=null;
  1026.                 }
  1027.                 // try to get data from server in every 5 seconds if the previous request was not completed
  1028.                 contentDoc.spui.idleTimerId = setTimeout(function() { contentDoc.spui.requestServerData(requestURL, callbackFunc); }, spui.k_idleTimer); 
  1029.                 contentDoc.spui.debug("contentDoc.spui.idleTimerId = setTimeout\n");
  1030.             }
  1031.             
  1032.             return true;
  1033.         };
  1034.  
  1035.         contentDoc.spui.phpRequestExecute = contentDoc.spui.requestServerData;
  1036.         
  1037.         contentDoc.spui.getBrowserVersion = function () {
  1038.             return spui.SPUI_BROWSER_VERSION;
  1039.         };
  1040.         
  1041.         contentDoc.spui.getBrowserTheme = function () {
  1042.             return spui.SPUI_BROWSER_THEME;
  1043.         };
  1044.         
  1045.         contentDoc.spui.getBrowserLocale = function () {
  1046.             return spui.SPUI_BROWSER_LOCALE;
  1047.         };
  1048.         
  1049.         // wrapper for window.openDialog
  1050.         contentDoc.spui.openDialog = function(contentURL, opener, title, width, height) {
  1051.             var SPUI_DIALOG = "chrome://browser/content/spuiDialog.xul";
  1052.             contentDoc.spui.debug('openDialog('+SPUI_DIALOG+': '+contentURL+');');
  1053.             var args = new Object();
  1054.             args.contentURL = contentURL;
  1055.             args.opener = opener;
  1056.             if (!title) title = 'SPUI Dialog';
  1057.             args.title = title;
  1058.             if (!width) width = 300;
  1059.             if (width < 100) width = 200;
  1060.             if (width > 500) width = 500;
  1061.             if (!height) height = 300;
  1062.             if (height < 100) height = 200;
  1063.             if (height > 500) height = 500;
  1064.             var dialog = window.openDialog(SPUI_DIALOG, 'spuiDialog',
  1065.             'chrome,modal=yes,resizable=no,centerscreen,'
  1066.             +'width='+width+',height='+height+','
  1067.             +'toolbars=no,menus=no',
  1068.             args);
  1069.         };
  1070.  
  1071.         contentDoc.spui.openSidebar = function(SideBarName) {
  1072.             RevealPanel(SideBarName);
  1073.         };
  1074.  
  1075.         // refreshDatasource(containerId, dsName) - refreshes a remote RDF datasource
  1076.         contentDoc.spui.refreshDataSource = function(containerId, dsName, callbackFunc) {
  1077.             contentDoc.spui.debug('refreshDataSource('+containerId+', '+dsName+')');
  1078.             var container = contentDoc.getElementById(containerId);    
  1079.       
  1080.             if (!container) {
  1081.                 contentDoc.spui.debug(' container element not found: '+containerId);
  1082.                 return;
  1083.             }
  1084.             // We don't refresh when the menupopup is open, since this can cause crashes
  1085.             else if (container.localName == 'menupopup' && 
  1086.              ('open' in container) && container.open) {
  1087.                     contentDoc.spui.debug(' Skipped refresh since menupopup open.');
  1088.                     return;
  1089.             }
  1090.             // Do not refresh if tray is not shown
  1091.             else if(container.localName == 'vbox' && contentDoc.spui.iframe.getAttribute('isActive') != 'true') {
  1092.                 contentDoc.spui.debug(containerId + ' is not active ');
  1093.                 return;
  1094.             }
  1095.             else if(iframe.contentWindow.screenX < 0 - 5000 || iframe.contentWindow.screenY < 0 - 2000) {
  1096.                 contentDoc.spui.debug(' browser is off screen ' + " screenY " + iframe.contentWindow.screenY + " screenX " + iframe.contentWindow.screenX + "\n");                
  1097.                 return;
  1098.             }
  1099.             // Get datasources
  1100.             else if (!container.database) {
  1101.                 contentDoc.spui.debug(' container element "'+containerId+'" has no database');
  1102.                 return;
  1103.             }
  1104.             var sources = container.database.GetDataSources();
  1105.             var count = 0;
  1106.             while (sources.hasMoreElements()) {
  1107.                 // TODO: check the dsName and only refresh the appropriate ds
  1108.                 var ds = sources.getNext();
  1109.                 ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
  1110.                 ds.Refresh(false);
  1111.                 ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
  1112.                 if (('loadObserver' in container) && (container.loadObserver)) {
  1113.                     ds.removeXMLSinkObserver(container.loadObserver);
  1114.                     container.loadObserver = 0;
  1115.                 }
  1116.                 container.loadObserver = {
  1117.                     onBeginLoad : function(sink){},
  1118.                     onInterrupt : function(sink){},
  1119.                     onResume : function(sink){},
  1120.                     onError : function(sink,status,msg){},
  1121.                     onEndLoad : function(sink) {
  1122.                         // this.debug('refresh observer onEndLoad()!');
  1123.                         // rebuild() will crash browser if menupopup is open!!!
  1124.                         if ((container.localName == 'menupopup') && container.open) return;
  1125.                         // this.debug(' rebuilding '+container.localName+'...');
  1126.                         try {
  1127.                             this.container.builder.rebuild();
  1128.                         } catch (ex) {
  1129.                             this.debug('  exeption: '+ex);
  1130.                             // No point in continuing to observe the datasource if there
  1131.                             // is no builder.  (This probably means the remote XUL document
  1132.                             // has been reloaded.)
  1133.                             this.ds.removeXMLSinkObserver(this);
  1134.                         }
  1135.                         if (callbackFunc && callbackFunc in this.iframeWindow) {
  1136.                             this.iframeWindow[callbackFunc]();
  1137.                             this.debug ( "Making the callback to " + callbackFunc);
  1138.                         }
  1139.  
  1140.                     },
  1141.                     debug : function(msg) {
  1142.                         this.parent.debug('loadObserver: '+msg);
  1143.                     }
  1144.                 };
  1145.                 container.loadObserver.parent = contentDoc.spui;
  1146.                 container.loadObserver.iframeWindow = iframe.contentWindow;
  1147.                 container.loadObserver.container = container;
  1148.                 container.loadObserver.ds = ds;
  1149.                 ds.addXMLSinkObserver(container.loadObserver);
  1150.                 count++;
  1151.             }
  1152.             // contentDoc.spui.debug(' Initiated asynchronous refresh for '+count+' datasource(s)');
  1153.         };
  1154.  
  1155.         contentDoc.spui.getGlobal = function (name) {
  1156.             return spui.GLOBALS[name];
  1157.         };
  1158.         
  1159.         contentDoc.spui.setGlobal = function (name, obj) {
  1160.             spui.GLOBALS[name] = obj;
  1161.         };       
  1162.         
  1163.         // spui.debug('Established link with SPUI component: '+componentId);
  1164.     }
  1165.  
  1166.     if ('spuiInit' in iframe.contentWindow) {
  1167.         spui.debug("calling spuiInit() " + componentId);
  1168.         iframe.contentWindow.spuiInit();
  1169.         /*
  1170.         if ('initBackground' in iframe.contentWindow) {
  1171.             iframe.contentWindow.initBackground(iframe.boxObject.x, 0);
  1172.         }
  1173.         */
  1174.         reshuffleToolbars(true);
  1175.     } else { // Check back for init after javascript loads in
  1176.         wait = 1000;
  1177.         accumulator += wait;
  1178.         setTimeout("establishRemoteSPUILink('"+componentId+"',"    +accumulator+");",wait); // Try again later
  1179.  
  1180.     }
  1181. }
  1182.