home *** CD-ROM | disk | FTP | other *** search
/ PC Advisor 2005 August / PCADVD_121.iso / internet / nsb-setup.exe / chrome / inspector.jar / content / inspector / search / inSearchModule.js next >
Encoding:
JavaScript  |  2004-11-25  |  15.5 KB  |  532 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Netscape Public License
  5.  * Version 1.1 (the "License"); you may not use this file except in
  6.  * compliance with the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/NPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is mozilla.org code.
  15.  *
  16.  * The Initial Developer of the Original Code is 
  17.  * Netscape Communications Corporation.
  18.  * Portions created by the Initial Developer are Copyright (C) 2001
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *   Joe Hewitt <hewitt@netscape.com> (original author)
  23.  *
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the NPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the NPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. /***************************************************************
  40. * inSearchModule -----------------------------------------------
  41. *  Encapsulates an ISML module and exposes it to inSearchService.
  42. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
  43. * REQUIRED IMPORTS:
  44. *   chrome://inspector/content/jsutil/xpcom/XPCU.js
  45. *   chrome://inspector/content/jsutil/rdf/RDFU.js
  46. *   chrome://inspector/content/jsutil/rdf/RDFArray.js
  47. *   chrome://inspector/content/jsutil/xul/inFormManager.js
  48. *   chrome://inspector/content/search/xul/inSearchUtils.js
  49. ****************************************************************/
  50.  
  51. //////////// global variables /////////////////////
  52.  
  53. //////////// global constants ////////////////////
  54.  
  55. ////////////////////////////////////////////////////////////////////////////
  56. //// class inSearchModule
  57.  
  58. function inSearchModule(aBaseURL)
  59. {
  60.   this.mObservers = [];
  61.   this.mBaseURL = aBaseURL;
  62. }
  63.  
  64. inSearchModule.prototype = 
  65. {
  66.   mTitle: null,
  67.   mBaseURL: null,
  68.   mImpl: null,
  69.   mDialogElementIds: null,
  70.   mDialogURL: null,
  71.   mContextMenuItems: null,
  72.   mColumns: null,
  73.   mColDelimiter: null,
  74.   mNameSpace: null,
  75.   
  76.   mRDFArray: null,
  77.   mResult: null,
  78.   mObservers: null,
  79.  
  80.   mStartTime: null,
  81.   mElapsed: 0,
  82.   
  83.   //////////////////////////////////////////////////////////////////////////
  84.   //// Properties
  85.   
  86.   get searchService() { return this.mSearchService},
  87.   set searchService(aVal) { this.mSearchService = aVal },
  88.   
  89.   get title() { return this.mTitle },
  90.   get baseURL() { return this.mBaseURL },
  91.   get defaultIconURL() { return this.mDefaultIconURL },
  92.  
  93.   get datasource() { return this.mRDFArray.datasource },
  94.   get resultCount() { return this.mRDFArray.length },
  95.   get progressPercent() { return this.mImpl.progressPercent },
  96.   get progressText() { return this.mImp.progressText },
  97.   get isPastMilestone() { return this.mImpl.isPastMilestone },
  98.   get elapsed() { return this.mElapsed },
  99.   
  100.   //////////////////////////////////////////////////////////////////////////
  101.   //// Initialization
  102.   
  103.   initFromElement: function(aSearchEl)
  104.   {
  105.     this.parseSearch(aSearchEl);
  106.     
  107.     if (this.mImpl.constructor)
  108.       this.mImpl.constructor();
  109.   },
  110.   
  111.   //////////////////////////////////////////////////////////////////////////
  112.   //// Parser
  113.  
  114.   parseSearch: function(aSearchEl)
  115.   {
  116.     // get the title
  117.     this.mTitle = aSearchEl.getAttribute("title");
  118.     // get the default icon url
  119.     this.mDefaultIconURL = aSearchEl.getAttribute("defaultIcon");
  120.     // get the namespace
  121.     var ns = aSearchEl.getAttribute("namespace")
  122.     this.mNameSpace = ns ? ns : kInspectorNSURI;
  123.  
  124.     this.parseDialog(aSearchEl);
  125.     this.parseContextMenu(aSearchEl);
  126.     this.parseColumns(aSearchEl);
  127.     this.parseImplementation(aSearchEl);
  128.   },  
  129.  
  130.   parseDialog: function(aSearchEl)
  131.   {
  132.     var els = aSearchEl.getElementsByTagNameNS(kISMLNSURI, "dialog");
  133.     if (els.length > 0) {
  134.       var dialogEl = els[0];
  135.       
  136.       // get the array of dialog element ids
  137.       var ids = dialogEl.getAttribute("elements");
  138.       if (ids)
  139.         this.mDialogElementIds = ids.split(",");
  140.  
  141.       // get the dialog url
  142.       this.setDialogURL(dialogEl.getAttribute("href"));
  143.       // get the dialog parameters
  144.       this.mDialogResizable = (dialogEl.getAttribute("resizable") == "true") ? true : false;
  145.     }
  146.   },  
  147.   
  148.   parseContextMenu: function(aSearchEl)
  149.   {
  150.     var els = aSearchEl.getElementsByTagNameNS(kISMLNSURI, "contextmenu");
  151.     if (els.length > 0) {
  152.       var kids = els[0].childNodes;
  153.       this.mContextMenu = [];
  154.       for (var i = 0; i < kids.length; ++i) {
  155.         this.mContextMenu[i] = kids[i].cloneNode(true);
  156.       }      
  157.     }
  158.   },  
  159.  
  160.   parseColumns: function(aSearchEl)
  161.   {
  162.     // get the result columns
  163.     var els = aSearchEl.getElementsByTagNameNS(kISMLNSURI, "columns");
  164.     if (els.length > 0) {
  165.       this.mColumns = [];
  166.       var cols = els[0];
  167.       this.mColDelimiter = cols.getAttribute("delimiter");
  168.       
  169.       var kids = cols.childNodes;
  170.       var col, data;
  171.       for (var i= 0; i < kids.length; ++i) {
  172.         col = kids[i];
  173.         if (col.nodeType == Node.ELEMENT_NODE) { // ignore non-element nodes
  174.           data = { 
  175.             name: col.getAttribute("name"), 
  176.             title: col.getAttribute("title"), 
  177.             flex: col.getAttribute("flex"), 
  178.             className: col.getAttribute("class"),
  179.             copy: col.getAttribute("copy") == "true"
  180.           };
  181.           this.mColumns.push(data);
  182.         }
  183.       }
  184.     }
  185.   },  
  186.  
  187.   parseImplementation: function(aSearchEl)
  188.   {
  189.     this.mImpl = this.getDefaultImplementation();
  190.     
  191.     // get the implementation object
  192.     var els = aSearchEl.getElementsByTagNameNS(kISMLNSURI, "implementation");
  193.     if (els.length > 0) {
  194.       var kids = aSearchEl.getElementsByTagNameNS(kISMLNSURI, "*");
  195.       for (var i = 0; i < kids.length; i++) {
  196.         if (kids[i].localName == "property")
  197.           this.parseProperty(kids[i]);
  198.         if (kids[i].localName == "method")
  199.           this.parseMethod(kids[i]);
  200.       }
  201.     }
  202.   },
  203.   
  204.   parseProperty: function(aPropEl)
  205.   {
  206.     var name = aPropEl.getAttribute("name");
  207.     var fn = null;
  208.     
  209.     // look for a getter
  210.     try {
  211.       fn = this.getCodeTagFunction(aPropEl, "getter", null);
  212.       if (fn)
  213.         this.mImpl.__defineGetter__(name, fn);
  214.     } catch (ex) {
  215.       throw "### SYNTAX ERROR IN ISML GETTER \"" + name + "\" ###\n" + ex;
  216.     }
  217.  
  218.     // look for a setter
  219.     try {
  220.       fn = this.getCodeTagFunction(aPropEl, "setter", ["val"]);
  221.       if (fn)
  222.         this.mImpl.__defineSetter__(name, fn);
  223.     } catch (ex) {
  224.       throw "### SYNTAX ERROR IN ISML SETTER \"" + name + "\" ###\n" + ex;
  225.     }
  226.   },
  227.   
  228.   parseMethod: function(aMethodEl)
  229.   {
  230.     var name = aMethodEl.getAttribute("name");
  231.     var def = aMethodEl.getAttribute("defaultCommand") == "true";
  232.     
  233.     // get all the parameters
  234.     var els = aMethodEl.getElementsByTagNameNS(kISMLNSURI, "parameter");
  235.     var params = [];
  236.     for (var i = 0; i < els.length; i++) {
  237.       params[i] = els[i].getAttribute("name");
  238.     }
  239.     
  240.     // get the body javascript and create the function
  241.     try {
  242.       var fn = this.getCodeTagFunction(aMethodEl, "body", params);
  243.       this.mImpl[name] = fn;
  244.       if (def)
  245.         this.mImpl.__DefaultCmd__ = fn;
  246.     } catch (ex) {
  247.       throw "### SYNTAX ERROR IN ISML METHOD \"" + name + "\" ###\n" + ex;
  248.     }    
  249.   },
  250.   
  251.   getCodeTagFunction: function(aParent, aLocalName, aParams)
  252.   {
  253.     var els = aParent.getElementsByTagNameNS(kISMLNSURI, aLocalName);
  254.     if (els.length) {
  255.       var body = els[0];
  256.       // try to determine where the code is located 
  257.       var node = body.childNodes.length > 0 ? body.firstChild : body;
  258.       return this.getJSFunction(aParams, node.nodeValue);
  259.     }
  260.     
  261.     return null;
  262.   },  
  263.   
  264.   getJSFunction: function(aParams, aCode)
  265.   {
  266.     var params = "";
  267.     if (aParams) {
  268.       for (var i = 0; i < aParams.length; i++) {
  269.         params += aParams[i];
  270.         if (i < aParams.length-1) params += ",";
  271.       }
  272.     }
  273.    
  274.     var js = "function(" + params + ") " + 
  275.       "{" + 
  276.         (aCode ? aCode : "") + 
  277.       "}";
  278.     
  279.     var fn;
  280.     eval("fn = " + js);
  281.     return fn;
  282.   },
  283.   
  284.   getDefaultImplementation: function()
  285.   {
  286.     return { module: this };
  287.   },
  288.  
  289.   //////////////////////////////////////////////////////////////////////////
  290.   //// Dialog box 
  291.  
  292.   openDialog: function()
  293.   {
  294.     window.openDialog(this.mDialogURL, "inSearchModule_dialog", 
  295.       "chrome,modal,resizable="+this.mDialogResizable, this);
  296.   },
  297.   
  298.   processDialog: function(aWindow)
  299.   {
  300.     var map = inFormManager.readWindow(aWindow, this.mDialogElementIds);
  301.     this.implStartSearch(map);
  302.   },
  303.  
  304.   //////////////////////////////////////////////////////////////////////////
  305.   //// Searching
  306.  
  307.   startSearch: function()
  308.   {
  309.     if (this.mDialogURL) {
  310.       this.openDialog();
  311.     } else
  312.       this.implStartSearch(null);  
  313.   },
  314.   
  315.   implStartSearch: function(aMap)
  316.   {
  317.     this.mStartTime = new Date();
  318.     this.mElapsed = 0;
  319.     
  320.     this.notifySearchStart();
  321.     this.initDataSource();
  322.     this.prepareForResult();
  323.     this.mImpl.searchStart(aMap);    
  324.   },
  325.   
  326.   stopSearch: function()
  327.   {
  328.     this.searchEnd();
  329.   },
  330.   
  331.   //////////////////////////////////////////////////////////////////////////
  332.   //// Result Returns
  333.  
  334.   setResultProperty: function(aAttr, aValue)
  335.   {
  336.     this.mResult[aAttr] = aValue;
  337.   },
  338.   
  339.   searchResultReady: function()
  340.   {
  341.     this.mRDFArray.add(this.mResult);
  342.     this.notifySearchResult();
  343.     this.prepareForResult();
  344.   },
  345.   
  346.   searchError: function(aMsg)
  347.   {
  348.   },
  349.   
  350.   searchEnd: function()
  351.   {
  352.     this.mElapsed = new Date() - this.mStartTime;
  353.     this.notifySearchEnd();
  354.   },
  355.  
  356.   //////////////////////////////////////////////////////////////////////////
  357.   //// Columns
  358.  
  359.   get columnCount() { return this.mColumns.length },
  360.   
  361.   getColumn: function(aIndex) { return this.mColumns[aIndex] },
  362.   getColumnName: function(aIndex) { return this.mColumns[aIndex].name },
  363.   getColumnTitle: function(aIndex) { return this.mColumns[aIndex].title },
  364.   getColumnClassName: function(aIndex) { return this.mColumns[aIndex].className },
  365.   getColumnFlex: function(aIndex) { return this.mColumns[aIndex].flex },
  366.  
  367.   //////////////////////////////////////////////////////////////////////////
  368.   //// RDF Datasource
  369.  
  370.   initDataSource: function()
  371.   {
  372.     this.mRDFArray = new RDFArray(this.mNameSpace, "inspector:searchResults", "results");
  373.     this.mRDFArray.initialize();
  374.   },
  375.   
  376.   getResultPropertyAt: function(aIndex, aProp)
  377.   {
  378.     return this.mRDFArray.get(aIndex, aProp);
  379.   },
  380.   
  381.   getItemText: function(aIndex)
  382.   {
  383.     var cols = this.mColumns;
  384.     var text = [];
  385.     for (var i = 0; i < cols.length; ++i) {
  386.       if (cols[i].copy) {
  387.         text.push(this.getResultPropertyAt(aIndex, cols[i].name));
  388.       }
  389.     }
  390.     return text.join(this.mColDelimiter);
  391.   },
  392.  
  393.   //////////////////////////////////////////////////////////////////////////
  394.   //// Context Menu
  395.   
  396.   installContextMenu: function(aMenu, aInsertionPoint, aDir)
  397.   {
  398.     if (this.mContextMenu) {
  399.       aMenu._searchModule = this;
  400.       var item;
  401.       this.mMenuItems = [];
  402.       if (this.mContextMenu.length == 0)
  403.         aInsertionPoint.setAttribute("hide", "true");
  404.       for (var i = 0; i < this.mContextMenu.length; ++i) {
  405.         item = this.mContextMenu[i];
  406.         this.mMenuItems.push(item);
  407.         this.installSearchReference(item);
  408.         if (aDir == inSearchService.INSERT_BEFORE)
  409.           aMenu.insertBefore(item, aInsertionPoint);
  410.         else {
  411.          // NOT YET IMPLEMENTED
  412.         }
  413.       }
  414.     }
  415.   },
  416.   
  417.   uninstallContextMenu: function(aMenu, aInsertionPoint, aDir)
  418.   {
  419.     if (this.mContextMenu) {
  420.       if (this.mContextMenu.length == 0)
  421.         aInsertionPoint.removeAttribute("hide");
  422.       // remove the menu items
  423.       for (var i = 0; i < this.mContextMenu.length; ++i)
  424.         aMenu.removeChild(this.mMenuItems[i]);
  425.     }
  426.   },
  427.  
  428.   installSearchReference: function(aItem)
  429.   {
  430.     if (aItem.nodeType == Node.ELEMENT_NODE) {
  431.       if (aItem.localName == "menuitem") {
  432.         aItem.search = this.mImpl;
  433.         for (var i = 0; i < aItem.childNodes.length; ++i)
  434.           this.installSearchReference(aItem.childNodes[i]);
  435.       }
  436.     }
  437.   },
  438.   
  439.   //////////////////////////////////////////////////////////////////////////
  440.   //// Event Notification
  441.  
  442.   // NOTE TO SELF - this code could be cut down to nothing if you write a module
  443.   // called "ObserverManager" to do the work for you
  444.  
  445.   addSearchObserver: function(aObserver)
  446.   {
  447.     this.mObservers.push(aObserver);
  448.   },
  449.   
  450.   removeSearchObserver: function(aObserver)
  451.   {
  452.     var o;
  453.     var obs = this.mObservers;
  454.     for (var i = 0; i < obs.length; i++) {
  455.       o = obs[i];
  456.       if (o == aObserver) {
  457.         obs.splice(i, 1);
  458.         return;
  459.       }
  460.     }
  461.   },
  462.  
  463.   notifySearchStart: function()
  464.   {
  465.     var o = this.mObservers;
  466.     for (var i = 0; i < o.length; i++)
  467.       o[i].onSearchStart(this);
  468.   },
  469.   
  470.   notifySearchResult: function()
  471.   {
  472.     var o = this.mObservers;
  473.     for (var i = 0; i < o.length; i++)
  474.       o[i].onSearchResult(this);
  475.   },
  476.  
  477.   notifySearchEnd: function(aResult)
  478.   {
  479.     var o = this.mObservers;
  480.     for (var i = 0; i < o.length; i++)
  481.       o[i].onSearchEnd(this, aResult);
  482.   },
  483.  
  484.   notifySearchError: function(aMsg)
  485.   {
  486.     var o = this.mObservers;
  487.     for (var i = 0; i < o.length; i++)
  488.       o[i].onSearchError(this, aMsg);
  489.   },
  490.  
  491.   //////////////////////////////////////////////////////////////////////////
  492.   //// Uncategorized
  493.  
  494.   callDefaultCommand: function()
  495.   {
  496.     if (this.mImpl.__DefaultCmd__)
  497.       this.mImpl.__DefaultCmd__();
  498.   },
  499.   
  500.   prepareForResult: function()
  501.   {
  502.     this.mResult = { _icon: this.mDefaultIconURL };
  503.   },
  504.  
  505.   setDialogURL: function(aURL)
  506.   {
  507.     this.mDialogURL = aURL;
  508.     // This block below doesn't work for now because none of the local file implementations 
  509.     // implement SetURL.  So, for now, the url in the search file MUST be absolute :(
  510.     /* this.mDialogURL = aURL;
  511.     var baseFile = inSearchUtils.createLocalFile(this.mBaseURL);
  512.     try {
  513.       baseFile.append(aURL);
  514.     } catch (ex) {
  515.       basefile = inSearchUtils.createLocalFile(aURL);      
  516.     }
  517.  
  518.     var file = XPCU.QI(file, "nsIFile");
  519.  
  520.     var ioService = XPCU.getService("@mozilla.org/network/io-service;1", "nsIIOService");
  521.     var fileHandler = XPCU.QI(ioService.getProtocolHandler("file"), "nsIFileProtocolHandler");
  522.  
  523.     this.mDialogURL = fileHandler.getURLSpecFromFile(basefile);
  524.     */
  525.   }  
  526.  
  527. };
  528.  
  529. //////////////////////////////////////////////////////////////////////////
  530. //// Event Listeners
  531.  
  532.