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