home *** CD-ROM | disk | FTP | other *** search
/ Netscape Navigator 4.0.4 / netscape-navigator-4.0.4.iso / SETUP / NAV40L.Z / System.js < prev    next >
Text File  |  1997-10-22  |  24KB  |  800 lines

  1. /* ==================================================================
  2. FILE:   System.js
  3. DESCR:  System class for Netscape Help implementation.
  4. NOTES:  
  5. ================================================================== */
  6. // Dev. switches.
  7. var TRACE           = false
  8. var ASSERT          = true
  9. var ERR_DLGS        = true
  10. var ERRS_TO_CONSOLE = false
  11.  
  12. // "Constants."
  13. var VERSION         = "2.0-970514"
  14. var LAYERED_TOPICS  = false
  15. var JAVA_DEPENDENT  = false
  16. var STAMP_CONSOLE   = false
  17. var OK_NAV_VERSIONS = ".4."
  18. var CHECK_HREFS     = false
  19. var CONTENTS        = "CntTool.htm"
  20. var INDEX           = "IdxTool.htm"
  21. var SEARCH          = "SrhTool.htm"
  22. var NAVUI           = "NavUI.htm"
  23. var TOOLUI          = "ToolUI.htm"
  24. var STATUS          = "Status.htm"
  25. var MESSAGE_BGCOLOR = "#fafad2"
  26. var TOOL_BGCOLOR    = "#99ccff"
  27.  
  28. //trace( "System.js" )
  29.  
  30. // Runtime error handling.
  31. // window.onerror = errHandler
  32.  
  33. // Version stamp.
  34. if ( STAMP_CONSOLE && navigator.javaEnabled() ) {
  35.    java.lang.System.out.println( "System.js, version " + VERSION )
  36.    java.lang.System.out.println( "Client: " + navigator.appVersion )
  37. }
  38.  
  39. /*
  40. DESCR:   Handles the onhelp event.
  41. PARAMS:  URL  The URL to load.
  42. RETURNS: 
  43. NOTES:   
  44. */
  45. function onHelpHandler( URL )
  46. {
  47.    //trace( "onHelpHandler(" + URL + ")" )
  48.    //alert( "onHelpHandler(" + URL + ")" )
  49.  
  50.    systemObj.loadTopic( URL, false )
  51. }
  52.  
  53. /*
  54. DESCR:   Traces execution to the console.
  55. PARAMS:  msg  The trace text.
  56. RETURNS: 
  57. NOTES:   
  58. */
  59. function trace( msg )
  60. {
  61.    if ( TRACE ) java.lang.System.out.println( "System: " + msg )
  62. }
  63.  
  64. // Create system object.
  65. var systemObj = new system( JAVA_DEPENDENT, OK_NAV_VERSIONS )
  66. assert( ( typeof( systemObj ) == "object" ), SYS_CONSTRUCT )
  67.  
  68. /*
  69. DESCR:   Help implementation system class.
  70. PARAMS:  bJavaDependent  Pass true if the system is Java dependent,
  71.                          false if not.
  72.          OKNavVersions   String representing valid versions of Navigator.
  73. RETURNS: 
  74. NOTES:   
  75. */
  76. function system( bJavaDependent, OKNavVersions )
  77. {
  78.    //trace( "system constructor" )
  79.  
  80.    this.backStack    = new stack()
  81.    this.forwardStack = new stack()
  82.  
  83.    this.navVersion
  84.    this.topic
  85.    this.contents
  86.  
  87.    //this.aSysSecWnds = new Array()  // Sys-owned secondary windows.
  88.  
  89.    this.currentTool       = CONTENTS  // Set default tool.
  90.    this.bIdxTitlesPageUp  = false
  91.    this.currentSubsystem  = ""
  92.    this.visibleLayerIdx   = ""
  93.  
  94.    this.bToolUIloaded   = false
  95.    this.bNavUIloaded    = false
  96.    this.bContentsLoaded = false
  97.    this.bIndexLoaded    = false
  98.    this.bStarted        = false
  99.  
  100.    this.bNewSubsystem = false
  101.  
  102.    this.preproc           = preproc
  103.    this.componentCallback = componentCallback
  104.    this.idxTitlesUp       = idxTitlesUp
  105.    this.loadTopic         = loadTopic
  106.    this.newSubsystem      = newSubsystem
  107.    this.exit              = exit
  108.    this.print             = print
  109.    this.find              = find
  110.    this.back              = back
  111.    this.forward           = forward
  112.    //this.openSecWnd        = openSecWnd
  113.    this.loadTool          = loadTool
  114.    this.setToolButton     = setToolButton
  115.    this.msg               = msg
  116.    this.manageLayers      = manageLayers
  117.    this.badURLerror       = badURLerror
  118.  
  119.    this.componentsReadyEvt = componentsReadyEvt
  120.    this.loadEvt            = loadEvt
  121.    this.unloadEvt          = unloadEvt
  122.  
  123.    this.stashPersistentData  = stashPersistentData
  124.    this.snatchPersistentData = snatchPersistentData
  125.  
  126.    // Preprocessing.
  127.    if ( !this.preproc( bJavaDependent, OKNavVersions ) ) {
  128.       return
  129.    }
  130.  
  131.    // Load components.
  132.    top.StatusFrame.location.replace( STATUS )
  133.    top.ToolUIFrame.location.replace( TOOLUI )
  134.    top.NavFrame.location.replace( NAVUI )
  135.    top.ToolFrame.location.replace( this.currentTool )
  136. }
  137.  
  138.    /*
  139.    DESCR:   Pre-Help processing.
  140.    PARAMS:  bJavaDependent  Pass true if the system is Java dependent,
  141.                             false if not.
  142.             OKNavVersions   String representing valid versions of Navigator.
  143.    RETURNS: 
  144.    NOTES:   
  145.    */
  146.    function preproc( bJavaDependent, OKNavVersions )
  147.    {
  148.       //trace( "preproc()" )
  149.       
  150.       // Make sure Java is enabled if needed. Otherwise, abort.
  151.       if ( bJavaDependent && !navigator.javaEnabled() ) {
  152.          this.msg( NO_JAVA_ERR_MSG, "" )
  153.          return false
  154.       }
  155.  
  156.       // Validate version of navigator. Render in ".integer." form.
  157.       var version = navigator.appVersion
  158.       this.navVersion =
  159.          "." + version.substring( 0, ( version.indexOf( "." ) + 1 ) )
  160.       if ( OKNavVersions.indexOf( this.navVersion ) == -1 ) {
  161.          this.msg( WRONG_NAV_VER_ERR_MSG, "" )
  162.          return false
  163.       }
  164.  
  165.       return true
  166.    }
  167.  
  168.    /*
  169.    DESCR:   Tracks component loading.
  170.    PARAMS:  componentName  The document-name of the component.
  171.    RETURNS: 
  172.    NOTES:   Components call this method on load. Triggers ready
  173.             event when all loaded.
  174.    */
  175.    function componentCallback( componentName )
  176.    {
  177.       //trace( "componentCallback(" + componentName + ")" )
  178.       //alert( "componentCallback(" + componentName + ")" )
  179.  
  180.       // Track component loading.
  181.  
  182.       // Note: for some reason, can't write to status frame until Contents
  183.       // is loaded, so we do this later.
  184.       //if ( componentName == STATUS ) top.StatusFrame.setStatusWait()
  185.  
  186.       if ( componentName == TOOLUI ) this.bToolUIloaded = true
  187.  
  188.       if ( componentName == NAVUI ) this.bNavUIloaded = true
  189.  
  190.       if ( componentName == CONTENTS ) {
  191.  
  192.          // Keep house.
  193.          top.StatusFrame.setStatusWait()
  194.          top.ToolUIFrame.bDisableBtnBar = false
  195.          this.bContentsLoaded = true
  196.          this.bIndexLoaded = false
  197.  
  198.          // Create a Contents object.
  199.          this.contents = new top.ToolFrame.contents( TOOL_BGCOLOR )
  200.          assert( ( typeof( this.contents ) == "object" ), CNT_CONSTRUCT )
  201.  
  202.          // If this is not a system load and we're just changing to the
  203.          // Contents tool, set the Content's dataset and update. Otherwise,
  204.          // this will happen when a topic is loaded.
  205.          if ( this.bStarted ) {
  206.            this.contents.setDataset( this.currentSubsystem )
  207.            this.contents.updateTree( this.topic.URL )
  208.  
  209.            top.StatusFrame.setStatusClear()
  210.          }
  211.       }
  212.  
  213.       if ( componentName == INDEX ) {
  214.          top.ToolUIFrame.bDisableBtnBar = false
  215.          this.bIndexLoaded = true
  216.          this.bContentsLoaded = false
  217.  
  218.          if ( this.bStarted ) top.StatusFrame.setStatusClear()
  219.       }
  220.  
  221.       // Set the blender button down for the current tool.
  222.       if ( componentName == TOOLUI ) {
  223.          this.setToolButton( ( this.currentTool == CONTENTS ? 0 : 1 ), 1 )
  224.       }
  225.  
  226.       // Get moving if we're ready, but not already underway.
  227.       if ( !this.bStarted &&
  228.            this.bToolUIloaded && this.bNavUIloaded &&
  229.            ( this.bContentsLoaded || this.bIndexLoaded ) ) {
  230.          this.bStarted = true
  231.          this.componentsReadyEvt()   
  232.       }
  233.    }
  234.  
  235.    /*
  236.    DESCR:   Handles components ready "event."
  237.    PARAMS:  
  238.    RETURNS: 
  239.    NOTES:   
  240.    */
  241.    function componentsReadyEvt()
  242.    {
  243.       //trace( "componentsReadyEvt()" )
  244.  
  245.       // Set onhelp handler.
  246.       top.setOnhelpHandler( "onHelpHandler" )
  247.    }
  248.  
  249.    /*
  250.    DESCR:   Enables external state-setting of the tool UI button bar.
  251.    PARAMS:  buttonIdx  Identifies the button on the bar.
  252.             newState   The state to set.
  253.    RETURNS: 
  254.    NOTES:   
  255.    */
  256.    function setToolButton( buttonIdx, newState )
  257.    {
  258.       //trace( "setToolButton" )
  259.  
  260.       assert( defined( top.ToolUIFrame.btnBar ), TOOLUI )
  261.       if ( defined( top.ToolUIFrame.btnBar ) ) {
  262.  
  263.          // Set.
  264.          with ( top.ToolUIFrame.btnBar.aButtons[ buttonIdx ] ) {
  265.             setState( newState )
  266.             bOn = true
  267.          }
  268.       }
  269.    }
  270.  
  271.    /*
  272.    DESCR:   onload handler.
  273.    PARAMS:  
  274.    RETURNS: 
  275.    NOTES:   
  276.    */
  277.    function loadEvt()
  278.    {
  279.       //trace( "loadEvt()" )
  280.       //alert( "loadEvt()" )
  281.  
  282.       // Snatch important data for persistence on reload due to window resizing.
  283.       this.snatchPersistentData()
  284.    }
  285.  
  286.    /*
  287.    DESCR:   onunload handler.
  288.    PARAMS:  
  289.    RETURNS: 
  290.    NOTES:   
  291.    */
  292.    function unloadEvt()
  293.    {
  294.       //trace( "unloadEvt()" )
  295.       //alert( "unloadEvt()" )
  296.  
  297.       // Stash important data for persistence on reload due to window resizing.
  298.       this.stashPersistentData()
  299.  
  300.       // Clean up topic (topic-owned secondary windows, etc.).
  301.       if ( defined( this.topic ) ) this.topic.destruct()
  302.  
  303.       // Close any system-owned secondary windows.
  304.       //for ( var i = 0; i < this.aSysSecWnds.length; i++ ) {
  305.       //   if ( defined( this.aSysSecWnds[ i ] ) ) this.aSysSecWnds[ i ].close()
  306.       //}
  307.    }
  308.  
  309.    /*
  310.    DESCR:   Stores data needed to maintain state on reload due to resize.
  311.    PARAMS:  
  312.    RETURNS: 
  313.    NOTES:   
  314.    */
  315.    function stashPersistentData()
  316.    {
  317.       //trace( "stashPersistentData" )
  318.  
  319.       if ( defined( top.aPersistentData ) ) {
  320.          var i = 0
  321.          top.aPersistentData[ i++ ] = this.currentTool
  322.          top.aPersistentData[ i++ ] = this.forwardStack
  323.          top.aPersistentData[ i++ ] = this.backStack
  324.          //this.topic
  325.          //this.visibleLayerIdx
  326.       }
  327.    }
  328.  
  329.    /*
  330.    DESCR:   Retrieves data needed to maintain state on reload due to resize.
  331.    PARAMS:  
  332.    RETURNS: 
  333.    NOTES:   
  334.    */
  335.    function snatchPersistentData()
  336.    {
  337.       //trace( "snatchPersistentData" )
  338.  
  339.       if ( defined( top.aPersistentData[ 0 ] ) ) {
  340.          var i = 0
  341.          this.currentTool  = top.aPersistentData[ i++ ]
  342.          this.forwardStack = top.aPersistentData[ i++ ] 
  343.          this.backStack    = top.aPersistentData[ i++ ]
  344.       }
  345.    }
  346.  
  347.    /*
  348.    DESCR:   Loads the Contents, Index, or Find tool.
  349.    PARAMS:  toolName  The document-name of the tool.
  350.    RETURNS: 
  351.    NOTES:   
  352.    */
  353.    function loadTool( toolName )
  354.    {
  355.       //trace( "loadTool(" + toolName + ")" )
  356.  
  357.       assert( ( toolName == CONTENTS ||
  358.                 toolName == INDEX ||
  359.                 toolName == SEARCH ), TOOLNAME )
  360.  
  361.       this.currentTool = toolName
  362.  
  363.       // Contents tool.
  364.       if ( toolName == CONTENTS && !this.bContentsLoaded ) {
  365.  
  366.          // Keep house.
  367.          top.StatusFrame.setStatusWait()
  368.          top.ToolUIFrame.bDisableBtnBar = true
  369.  
  370.          top.ToolFrame.location.replace( toolName )
  371.       }
  372.  
  373.       // Index tool.
  374.       else if ( toolName == INDEX && !this.bIndexLoaded ) {
  375.  
  376.          // Keep house.
  377.          top.StatusFrame.setStatusWait()
  378.          top.ToolUIFrame.bDisableBtnBar = true
  379.  
  380.          top.ToolFrame.location.replace( toolName )
  381.       }
  382.  
  383.       // Search tool.
  384.       else if ( toolName == SEARCH ) {
  385.  
  386.          // We are using native find functionality in lieu of Search tool.
  387.          // Be sure to invoke Find against the topic frame.
  388.          top.TopicFrame.find()
  389.       }
  390.    }
  391.  
  392.    /*
  393.    DESCR:   Closes the Help window.
  394.    PARAMS:  
  395.    RETURNS: 
  396.    NOTES:   
  397.    */
  398.    function exit()
  399.    {
  400.       //trace( "exit()" )
  401.  
  402.       // Close frameset.
  403.       top.close()
  404.    }
  405.  
  406.    /*
  407.    DESCR:   Moves back in Help history.
  408.    PARAMS:  
  409.    RETURNS: 
  410.    NOTES:   Presumes button is disabled on empty stack.
  411.    */
  412.    function back()
  413.    {
  414.       //trace( "back()" )
  415.  
  416.       // Since the Index's titles page may be in the topic frame, but not
  417.       // part of history, we don't really wan't to go Back. Just restore
  418.       // the current topic without adding it to history.
  419.       if ( this.bIdxTitlesPageUp ) {
  420.          this.loadTopic( this.topic.URL, false )
  421.          return
  422.       }
  423.  
  424.       assert( !this.backStack.isEmpty(), BACK_STACK )
  425.       this.forwardStack.push( this.topic.URL )
  426.       this.loadTopic( this.backStack.pop(), true )
  427.    }
  428.  
  429.    /*
  430.    DESCR:   Moves forward in Help history.
  431.    PARAMS:  
  432.    RETURNS: 
  433.    NOTES:   Presumes button is disabled on empty stack.
  434.    */
  435.    function forward()
  436.    {
  437.       //trace( "forward()" )
  438.  
  439.       assert( !this.forwardStack.isEmpty(), FORWARD_STACK )
  440.       this.backStack.push( this.topic.URL )
  441.       this.loadTopic( this.forwardStack.pop(), true )
  442.    }
  443.  
  444.    /*
  445.    DESCR:   Tracks the Index's topic titles page in the topic window.
  446.    PARAMS:  
  447.    RETURNS: 
  448.    NOTES:   
  449.    */
  450.    function idxTitlesUp()
  451.    {
  452.       //trace ( "idxTitlesUp()" )
  453.       
  454.       this.bIdxTitlesPageUp = true
  455.  
  456.       // The Index titles page is not part of the topics history, so make
  457.       // sure that Forward is disabled and Back is enabled.
  458.       assert( defined( top.NavFrame.btnBar ), NAV_BAR )
  459.       if ( defined( top.NavFrame.btnBar ) ) {
  460.          top.NavFrame.btnBar.aButtons[ 0 ].enable( true )
  461.          top.NavFrame.btnBar.aButtons[ 1 ].enable( false )
  462.       }
  463.    }
  464.  
  465.    /*
  466.    DESCR:   Handles tasks when the Help subsystem changes.
  467.    PARAMS:  newSubsystem  A simple filename representing the subsystem
  468.                           (the topic filename).
  469.    RETURNS: 
  470.    NOTES:   
  471.    */
  472.    function newSubsystem( newSubsystem )
  473.    {
  474.       //trace( "newSubsystem('" + newSubsystem + "')" )
  475.       //alert( "newSubsystem('" + newSubsystem + "')" )
  476.  
  477.       assert( ( newSubsystem.toLowerCase().indexOf( ".htm" ) > -1 ),
  478.               SUBSYS_VALUE + newSubsystem )
  479.  
  480.       // Track the current subsystem.
  481.       this.currentSubsystem = newSubsystem
  482.  
  483.       // Reinitialize the visible layer index, since nothing is visible yet.
  484.       this.visibleLayerIdx = ""
  485.  
  486.       // Load the new header.
  487.       top.HeaderFrame.location.replace( this.topic.headerURL )
  488.  
  489.       // Set the Contents tool's dataset.
  490.       if ( this.currentTool == CONTENTS ) {
  491.          this.contents.setDataset( newSubsystem )
  492.       }
  493.    }
  494.  
  495.    /*
  496.    DESCR:   Loads a topic.
  497.    PARAMS:  URL           The non-nethelp version of the URL.
  498.             bHistoryLoad  true if this is a load due to Back or Forward;
  499.                           false, otherwise.
  500.    RETURNS: 
  501.    NOTES:   
  502.    */
  503.    function loadTopic( URL, bHistoryLoad )
  504.    {
  505.       //trace( "loadTopic(" + URL + ")" )
  506.  
  507.       assert( ( URL.toLowerCase().indexOf( ".htm" ) > -1 ), URL_VALUE + URL )
  508.  
  509.       // Update Index titles page flag. If we are loading a topic, it can't
  510.       // be the URL in the topic window.
  511.       this.bIdxTitlesPageUp = false
  512.  
  513.       // Keep house if there is an existing topic...
  514.       if ( defined( this.topic ) ) {
  515.  
  516.          // Track as history, if this is _not_ a history load, and if we are
  517.          // not reloading the same URL for some (good) reason. Note that
  518.          // forward stack should be cleared.
  519.          if ( !bHistoryLoad && ( this.topic.URL != URL ) ) {
  520.             this.backStack.push( this.topic.URL )
  521.             this.forwardStack.clear()
  522.          }
  523.  
  524.          // "Destruct" the current topic.
  525.          this.topic.destruct()
  526.       } 
  527.  
  528.       // See if we need to change subsystems.
  529.       var bNewSubsystem =
  530.          ( makeSimpleFilename( URL ) != this.currentSubsystem ? true : false )
  531.  
  532.       // If we're loading a new topic file, set the wait indicator.
  533.       if ( bNewSubsystem ) top.StatusFrame.setStatusWait()
  534.  
  535.       // Create new topic object. Must happen before updating subsystem.
  536.       this.topic = new helpTopic( URL )
  537.       assert( ( typeof( this.topic ) == "object" ), TOPIC_CONSTRUCT )
  538.  
  539.       // Update current subsystem. Must happen before updating Contents tree
  540.       // or managing layers.
  541.       if ( bNewSubsystem ) this.newSubsystem( makeSimpleFilename( URL ) )
  542.  
  543.       // Enable/disable history buttons.
  544.       assert( defined( top.NavFrame.btnBar ), NAV_BAR )
  545.       if ( defined( top.NavFrame.btnBar ) ) {
  546.          var bEnable
  547.          bEnable = ( this.backStack.isEmpty() ? false : true )
  548.          top.NavFrame.btnBar.aButtons[ 0 ].enable( bEnable )
  549.          bEnable = ( this.forwardStack.isEmpty() ? false : true )
  550.          top.NavFrame.btnBar.aButtons[ 1 ].enable( bEnable )
  551.       }
  552.  
  553.       // Update Contents tree.
  554.       if ( this.currentTool == CONTENTS ) this.contents.updateTree( URL )
  555.  
  556.       // Layers are managed on topic file load (to ensure the layers exist),
  557.       // but since an anchor "load" in the current URL generates no load
  558.       // event, we need to call manageLayers() here under such conditions.
  559.       if ( LAYERED_TOPICS && !this.bNewSubsystem ) this.manageLayers()
  560.    }
  561.  
  562.    /*
  563.    DESCR:   Manages layers if layered topics is turned on.
  564.    PARAMS:  
  565.    RETURNS: 
  566.    NOTES:   This is called from the topic onload handler, to be sure the
  567.             document is loaded, or it is called from loadTopic() if the
  568.             subsystem has not changed, since such a load is via a named
  569.             anchor and does not raise an onload event. 
  570.    */
  571.    function manageLayers()
  572.    {
  573.       //trace( "manageLayers()" )
  574.  
  575.       if ( !LAYERED_TOPICS ) return
  576.  
  577.       // Bail if there are no layered topics.
  578.       if ( !defined( top.TopicFrame.document.layers[ 0 ] ) ) return
  579.  
  580.       // Hide any currently visible topic.
  581.       if ( this.visibleLayerIdx != "" ) {
  582.          top.TopicFrame.document.layers[ this.visibleLayerIdx ].hidden = true
  583.       }
  584.  
  585.       // Unhide the topic layer.
  586.       top.TopicFrame.document.layers[ this.topic.fragmentSpec ].hidden = false
  587.  
  588.       // Stash this index.
  589.       this.visibleLayerIdx = this.topic.fragmentSpec
  590.    }
  591.  
  592.    /*
  593.    DESCR:   Creates an always-on-top message box with an OK button.
  594.    PARAMS:  msgText     The message text.
  595.             msgCaption  The window caption.
  596.    RETURNS: 
  597.    NOTES:   The message box is asynchronous, except that the OK button's
  598.             window.close() will not execute until the JS in the calling
  599.             window executes. Note that parser can't hack whitespace in
  600.             third parm of open().
  601.    */
  602.    function msg( msgText, msgCaption )
  603.    {
  604.       //trace( "msg(" + msgText + ")" )
  605.  
  606.       if ( msgCaption == "" ) msgCaption = DEFAULT_MESSAGE_CAPTION
  607.  
  608.       var msgDlg =
  609.          window.open( "", "",
  610.                       "SCROLLBARS=no,WIDTH=350,HEIGHT=200,SCROLLBARS=yes,ALWAYSRAISED=yes,DEPENDENT=yes,TITLEBAR=no,MENUBAR=no,HOTKEYS=no" )
  611.  
  612.       var html
  613.       html = "<HEAD><TITLE>" + msgCaption +
  614.              "</TITLE></HEAD><BODY BGCOLOR = " + MESSAGE_BGCOLOR + ">"
  615.       html += msgText
  616.       html += "<BR><BR><BR><BR>"
  617.       html += "<CENTER><FORM METHOD = POST>"
  618.       html += "<INPUT TYPE = button NAME = 'OK' VALUE = '   " +
  619.               OK_BTN_LABEL +
  620.               "   ' ONCLICK = 'window.close()'></FORM></CENTER></BODY>"
  621.  
  622.       msgDlg.document.write( html )
  623.       msgDlg.document.close()
  624.    }
  625.  
  626.    /*
  627.    DESCR:   Creates a secondary content window.
  628.    PARAMS:  URL         The content URL.
  629.             name        The window name.
  630.             features    The feature string.
  631.             bSystem     true if the window should be system-owned (i.e.,
  632.                         window will not be closed when parent topic
  633.                         closes, only when the system shuts down);
  634.                         false, if topic-owned.
  635.             bReturnObj  true if the window object should be returned.
  636.    RETURNS: Optionally, the window object.
  637.    NOTES:   
  638.    */
  639.    /*
  640.    function openSecWnd( URL, name, features, bSystem, bReturnObj )
  641.    {
  642.       //trace( "openSecWnd(" + URL + ")" )
  643.  
  644.       // Create a system- or topic-owned seconadary window.
  645.       var newWnd
  646.       var bAlreadyExists = false
  647.       if ( bSystem ) {
  648.          newWnd = window.open( URL, name, features )
  649.  
  650.          // Add window to list only if it is a new window (user may create
  651.          // a secondary more than once).
  652.          for ( var i = 0; i < this.aSysSecWnds.length; i++ ) {
  653.             if ( this.aSysSecWnds[ i ] == newWnd ) {
  654.                if ( bReturnObj ) return newWnd
  655.                else bAlreadyExists = true
  656.             }
  657.          }
  658.          if ( !bAlreadyExists ) { 
  659.             this.aSysSecWnds[ this.aSysSecWnds.length ] = newWnd
  660.             if ( bReturnObj ) return newWnd
  661.          }
  662.       }
  663.       else {
  664.          newWnd = this.topic.addSecondary( URL, name, features )
  665.          if ( bReturnObj ) return newWnd
  666.       }
  667.    }
  668.    */
  669.  
  670.    /*
  671.    DESCR:   Creates a bad URL type error.
  672.    PARAMS:  href  The offending href.
  673.    RETURNS: 
  674.    NOTES:   
  675.    */
  676.    function badURLerror( href )
  677.    {
  678.       this.msg( BAD_HREF_ERR_MSG + "<P>" + href, "" )
  679.    }
  680.  
  681.    /*
  682.    DESCR:   Prints the content in the topic frame.
  683.    PARAMS:  
  684.    RETURNS: 
  685.    NOTES:   
  686.    */
  687.    function print()
  688.    {
  689.       //trace( "print()" )
  690.  
  691.       top.TopicFrame.print()
  692.    }
  693.  
  694. // End class definition: system.
  695.  
  696. /*
  697. DESCR:   Help topic class.
  698. PARAMS:  URL  The non-nethelp form of the URL.
  699. RETURNS: 
  700. NOTES:   
  701. */
  702. function helpTopic( URL )
  703. {
  704.    //trace( "helpTopic constructor" )
  705.  
  706.    assert( ( URL.toLowerCase().indexOf( ".htm" ) > -1 ),
  707.            TOPIC_URL_VALUE + URL )
  708.  
  709.    this.headerURL
  710.  
  711.    this.URL = URL
  712.  
  713.    this.fragmentSpec = URL.substring( URL.lastIndexOf( "#" ) + 1 )
  714.    assert( this.fragmentSpec != "", FRAG_SPEC )
  715.  
  716.    //this.aSecWnds = new Array()  // Secondary windows.
  717.  
  718.    this.destruct         = destruct
  719.    //this.addSecondary     = addSecondary
  720.    //this.closeSecondaries = closeSecondaries
  721.  
  722.    // Determine header URL by naming convention.
  723.    var extPos
  724.    extentionPos = this.URL.indexOf( ".htm" )
  725.    if ( extentionPos == -1 ) extentionPos = this.URL.indexOf( ".HTM" )
  726.    assert( ( extentionPos != -1 ), TOPIC_FILENAME )
  727.    this.headerURL = this.URL.substring( 0, extentionPos ) + "Hdr.htm"
  728.  
  729.    // Load URL in the topic frame.
  730.    top.TopicFrame.location.replace( this.URL )
  731. }
  732.  
  733.    /*
  734.    DESCR:   Adds a secondary window.
  735.    PARAMS:  URL       The content URL.
  736.             name      The window name.
  737.             features  The feature string.
  738.    RETURNS: 
  739.    NOTES:   
  740.    */
  741.    /*
  742.    function addSecondary( URL, name, features )
  743.    {
  744.       //trace( "addSecondary()" )
  745.  
  746.       var newWnd = window.open( URL, name, features )
  747.       
  748.       // Add window to list only if it is a new window (user may
  749.       // create a secondary more than once).
  750.       for ( var i = 0; i < this.aSecWnds.length; i++ ) {
  751.          if ( this.aSecWnds[ i ] == newWnd ) return newWnd
  752.       }
  753.       this.aSecWnds[ this.aSecWnds.length ] = newWnd
  754.  
  755.       return newWnd
  756.    }
  757.    */
  758.  
  759.    /*
  760.    DESCR:   Closes all secondary windows.
  761.    PARAMS:  
  762.    RETURNS: 
  763.    NOTES:   
  764.    */
  765.    /*
  766.    function closeSecondaries()
  767.    {
  768.       //trace( "closeSecondaries()" )
  769.  
  770.       for ( var i = 0; i < this.aSecWnds.length; i++ ) {
  771.          if ( defined( this.aSecWnds[ i ] ) ) this.aSecWnds[ i ].close()
  772.       }
  773.    }
  774.    */
  775.    
  776.    /*
  777.    DESCR:   "Destructor."
  778.    PARAMS:  
  779.    RETURNS: 
  780.    NOTES:   
  781.    */
  782.    function destruct()
  783.    {
  784.       //trace( "helpTopic destruct()" )
  785.  
  786.       // Close any secondary windows owned by current topic.
  787.       //this.closeSecondaries()
  788.    }
  789.  
  790. // End class definition: helpTopic.
  791.  
  792. /*
  793. DESCR:   Popup class.
  794. PARAMS:  
  795. RETURNS: 
  796. NOTES:   
  797. */
  798.  
  799. // End class definition: popup.
  800.