home *** CD-ROM | disk | FTP | other *** search
/ PC World 2006 December / PCWorld_2006-12_cd.bin / komunikace / netscape / nsb-install-8-1-2.exe / chrome / browser.jar / content / browser / spui.js < prev    next >
Text File  |  2006-01-06  |  43KB  |  1,257 lines

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