html.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:65k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: html.cpp,v $
  4.  * PRODUCTION Revision 1000.4  2004/06/01 19:15:26  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.103
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: html.cpp,v 1000.4 2004/06/01 19:15:26 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Lewis Geer
  35.  *
  36.  */
  37. #include <ncbi_pch.hpp>
  38. #include <html/html.hpp>
  39. #include <html/htmlhelper.hpp>
  40. #include <html/indentstream.hpp>
  41. #include <html/html_exception.hpp>
  42. #include <errno.h>
  43. #include <string.h>
  44. BEGIN_NCBI_SCOPE
  45. /// Tag delimiters
  46. const char* kTagStart    = "<@";   ///< Tag start.
  47. const char* kTagEnd      = "@>";   ///< Tag end.
  48. const char* kTagStartEnd = "</@";  ///< Tag start in the end of
  49.                                    ///< block definition.
  50. #define CHECK_STREAM_WRITE(out)                                               
  51.     if ( !out ) {                                                             
  52.         int x_errno = errno;                                                  
  53.         string x_err("write to stream failed");                               
  54.         if (x_errno != 0) {                                                   
  55.             const char* x_strerror = strerror(x_errno);                       
  56.             if ( !x_strerror ) {                                              
  57.                 x_strerror = "Error code is out of range";                    
  58.             }                                                                 
  59.             string x_strerrno = NStr::IntToString(x_errno);                   
  60.             x_err += " {errno=" + x_strerrno + ',' + x_strerror + '}';        
  61.         }                                                                     
  62.         NCBI_THROW(CHTMLException, eWrite, x_err);                            
  63.     }
  64. static string s_GenerateNodeInternalName(const string& basename,
  65.                                          const string& v1,
  66.                                          const string& v2 = kEmptyStr)
  67. {
  68.     string name(basename);
  69.     if ( !v1.empty() ) {
  70.         name += "("" + v1.substr(0,10) + """;
  71.         if ( !v2.empty() ) {
  72.             name += "|"" + v2.substr(0,10) + """;
  73.         }
  74.         name += ")";
  75.     }
  76.     return name;
  77. }
  78. // CHTMLNode
  79. CHTMLNode::~CHTMLNode(void)
  80. {
  81.     return;
  82. }
  83. CHTMLNode* CHTMLNode::SetClass(const string& class_name)
  84. {
  85.     SetOptionalAttribute("class", class_name);
  86.     return this;
  87. }
  88. CHTMLNode* CHTMLNode::SetId(const string& class_name)
  89. {
  90.     SetOptionalAttribute("id", class_name);
  91.     return this;
  92. }
  93. CHTMLNode* CHTMLNode::SetWidth(int width)
  94. {
  95.     SetAttribute("width", width);
  96.     return this;
  97. }
  98. CHTMLNode* CHTMLNode::SetHeight(int height)
  99. {
  100.     SetAttribute("height", height);
  101.     return this;
  102. }
  103. CHTMLNode* CHTMLNode::SetWidth(const string& width)
  104. {
  105.     SetOptionalAttribute("width", width);
  106.     return this;
  107. }
  108. CHTMLNode* CHTMLNode::SetHeight(const string& height)
  109. {
  110.     SetOptionalAttribute("height", height);
  111.     return this;
  112. }
  113. CHTMLNode* CHTMLNode::SetSize(int size)
  114. {
  115.     SetAttribute("size", size);
  116.     return this;
  117. }
  118. CHTMLNode* CHTMLNode::SetAlign(const string& align)
  119. {
  120.     SetOptionalAttribute("align", align);
  121.     return this;
  122. }
  123. CHTMLNode* CHTMLNode::SetVAlign(const string& align)
  124. {
  125.     SetOptionalAttribute("valign", align);
  126.     return this;
  127. }
  128. CHTMLNode* CHTMLNode::SetColor(const string& color)
  129. {
  130.     SetOptionalAttribute("color", color);
  131.     return this;
  132. }
  133. CHTMLNode* CHTMLNode::SetBgColor(const string& color)
  134. {
  135.     SetOptionalAttribute("bgcolor", color);
  136.     return this;
  137. }
  138. CHTMLNode* CHTMLNode::SetNameAttribute(const string& name)
  139. {
  140.     SetAttribute("name", name);
  141.     return this;
  142. }
  143. const string& CHTMLNode::GetNameAttribute(void) const
  144. {
  145.     return GetAttribute("name");
  146. }
  147. CHTMLNode* CHTMLNode::SetAccessKey(char key)
  148. {
  149.     SetAttribute("accesskey", string(1, key));
  150.     return this;
  151. }
  152. CHTMLNode* CHTMLNode::SetTitle(const string& title)
  153. {
  154.     SetAttribute("title", title);
  155.     return this;
  156. }
  157. CHTMLNode* CHTMLNode::SetStyle(const string& style)
  158. {
  159.     SetAttribute("style", style);
  160.     return this;
  161. }
  162. void CHTMLNode::AppendPlainText(const string& appendstring, bool noEncode)
  163. {
  164.     if ( !appendstring.empty() ) {
  165.         AppendChild(new CHTMLPlainText(appendstring, noEncode));
  166.     }
  167. }
  168. void CHTMLNode::AppendPlainText(const char* appendstring, bool noEncode)
  169. {
  170.     if ( appendstring && *appendstring ) {
  171.         AppendChild(new CHTMLPlainText(appendstring, noEncode));
  172.     }
  173. }
  174. void CHTMLNode::AppendHTMLText(const string& appendstring)
  175. {
  176.     if ( !appendstring.empty() ) {
  177.         AppendChild(new CHTMLText(appendstring));
  178.     }
  179. }
  180. void CHTMLNode::AppendHTMLText(const char* appendstring)
  181. {
  182.     if ( appendstring && *appendstring ) {
  183.         AppendChild(new CHTMLText(appendstring));
  184.     }
  185. }
  186. string CHTMLNode::GetEventHandlerName(const EHTML_EH_Attribute name) const
  187. {
  188.     switch (name) {
  189.     case eHTML_EH_Blur:
  190.         return "onBlur";
  191.     case eHTML_EH_Change:
  192.         return "onChange";
  193.     case eHTML_EH_Click:
  194.         return "onClick";
  195.     case eHTML_EH_DblClick:
  196.         return "onDblClick";
  197.     case eHTML_EH_Focus:
  198.         return "onFocus";
  199.     case eHTML_EH_Load:
  200.         return "onLoad";
  201.     case eHTML_EH_Unload:
  202.         return "onUnload";
  203.     case eHTML_EH_MouseDown:
  204.         return "onMouseDown";
  205.     case eHTML_EH_MouseUp:
  206.         return "onMouseUp";
  207.     case eHTML_EH_MouseMove:
  208.         return "onMouseMove";
  209.     case eHTML_EH_MouseOver:
  210.         return "onMouseOver";
  211.     case eHTML_EH_MouseOut:
  212.         return "onMouseOut";
  213.     case eHTML_EH_Select:
  214.         return "onSelect";
  215.     case eHTML_EH_Submit:
  216.         return "onSubmit";
  217.     case eHTML_EH_KeyDown:
  218.         return "onKeyDown";
  219.     case eHTML_EH_KeyPress:
  220.         return "onKeyPress";
  221.     case eHTML_EH_KeyUp:
  222.         return "onKeyUp";
  223.     }
  224.     _TROUBLE;
  225.     return kEmptyStr;
  226. }
  227. void CHTMLNode::SetEventHandler(const EHTML_EH_Attribute event,
  228.                                 const string& value)
  229. {
  230.     if ( value.empty() ) {
  231.         return;
  232.     }
  233.     SetAttribute(GetEventHandlerName(event), value);
  234. }
  235. void CHTMLNode::AttachPopupMenu(const CHTMLPopupMenu* menu,
  236.                                 EHTML_EH_Attribute    event)
  237. {
  238.     if ( !menu ) {
  239.         return;
  240.     }
  241.     const string kStopEvent = " return false;";
  242.     switch (menu->GetType()) {
  243.     case CHTMLPopupMenu::eSmith: 
  244.         SetEventHandler(event, menu->ShowMenu() + kStopEvent);
  245.         return;
  246.     case CHTMLPopupMenu::eKurdin: 
  247.     case CHTMLPopupMenu::eKurdinConf: 
  248.         SetEventHandler(event, menu->ShowMenu() + kStopEvent);
  249.         SetEventHandler(eHTML_EH_MouseOut, menu->HideMenu());
  250.         return;
  251.     case CHTMLPopupMenu::eKurdinSide:
  252.         AppendHTMLText(menu->ShowMenu());
  253.         return;
  254.     }
  255.     _TROUBLE;
  256. }
  257. // <@XXX@> mapping tag node
  258. CHTMLTagNode::CHTMLTagNode(const char* name)
  259.     : CParent(name)
  260. {
  261.     return;
  262. }
  263. CHTMLTagNode::CHTMLTagNode(const string& name)
  264.     : CParent(name)
  265. {
  266.     return;
  267. }
  268. CHTMLTagNode::~CHTMLTagNode(void)
  269. {
  270.     return;
  271. }
  272. CNcbiOstream& CHTMLTagNode::PrintChildren(CNcbiOstream& out, TMode mode)
  273. {
  274.     CNodeRef node = MapTagAll(GetName(), mode);
  275.     if ( node ) {
  276.         node->Print(out, mode);
  277.     }
  278.     return out;
  279. }
  280. // Dual text node.
  281. CHTMLDualNode::CHTMLDualNode(const char* html, const char* plain)
  282.     : CParent(s_GenerateNodeInternalName("dualnode", html, plain))
  283. {
  284.     AppendChild(new CHTMLText(html));
  285.     m_Plain = plain;
  286. }
  287. CHTMLDualNode::CHTMLDualNode(CNCBINode* child, const char* plain)
  288.     : CParent(s_GenerateNodeInternalName("dualnode", "[node]", plain))
  289. {
  290.     AppendChild(child);
  291.     m_Plain = plain;
  292. }
  293. CHTMLDualNode::~CHTMLDualNode(void)
  294. {
  295.     return;
  296. }
  297. CNcbiOstream& CHTMLDualNode::PrintChildren(CNcbiOstream& out, TMode mode)
  298. {
  299.     if ( mode == ePlainText ) {
  300.         out << m_Plain;
  301.         CHECK_STREAM_WRITE(out);
  302.         return out;
  303.     } else {
  304.         return CParent::PrintChildren(out, mode);
  305.     }
  306. }
  307. // plain text node
  308. CHTMLPlainText::CHTMLPlainText(const char* text, bool noEncode)
  309.     : CNCBINode(s_GenerateNodeInternalName("plaintext", text)),
  310.       m_NoEncode(noEncode), m_Text(text)
  311. {
  312.     return;
  313. }
  314. CHTMLPlainText::CHTMLPlainText(const string& text, bool noEncode)
  315.     : CNCBINode(s_GenerateNodeInternalName("plaintext", text)),
  316.       m_NoEncode(noEncode), m_Text(text)
  317. {
  318.     return;
  319. }
  320. CHTMLPlainText::~CHTMLPlainText(void)
  321. {
  322.     return;
  323. }
  324. CNcbiOstream& CHTMLPlainText::PrintBegin(CNcbiOstream& out, TMode mode)
  325. {
  326.     if (mode == ePlainText  ||  NoEncode()) {
  327.         out << GetText();
  328.     }
  329.     else {
  330.         out << CHTMLHelper::HTMLEncode(GetText());
  331.     }
  332.     CHECK_STREAM_WRITE(out);
  333.     return out;
  334. }
  335. // text node
  336. CHTMLText::CHTMLText(const string& text)
  337.     : CParent(s_GenerateNodeInternalName("htmltext", text)),
  338.       m_Text(text)
  339. {
  340.     return;
  341. }
  342. CHTMLText::CHTMLText(const char* text)
  343.     : CParent(s_GenerateNodeInternalName("htmltext", text)),
  344.       m_Text(text)
  345. {
  346.     return;
  347. }
  348. CHTMLText::~CHTMLText(void)
  349. {
  350.     return;
  351. }
  352. static SIZE_TYPE s_Find(const string& s, const char* target,
  353.                         SIZE_TYPE start = 0)
  354. {
  355.     // Return s.find(target);
  356.     // Some implementations of string::find call memcmp at every
  357.     // possible position, which is way too slow.
  358.     if ( start >= s.size() ) {
  359.         return NPOS;
  360.     }
  361.     const char* cstr = s.c_str();
  362.     const char* p    = strstr(cstr + start, target);
  363.     return p ? p - cstr : NPOS;
  364. }
  365. CNcbiOstream& CHTMLText::x_PrintBegin(CNcbiOstream& out, TMode mode,
  366.                                       const string& s) const
  367. {
  368.     if ( mode == ePlainText ) {
  369.         out << CHTMLHelper::StripHTML(s);
  370.     } else {
  371.         out << s;
  372.     }
  373.     CHECK_STREAM_WRITE(out);
  374.     return out;
  375. }
  376. CNcbiOstream& CHTMLText::PrintBegin(CNcbiOstream& out, TMode mode)
  377. {
  378.     const string& text = GetText();
  379.     SIZE_TYPE tagStart = s_Find(text, kTagStart);
  380.     if ( tagStart == NPOS ) {
  381.         return x_PrintBegin(out, mode, text);
  382.     }
  383.     SIZE_TYPE tag_start_size = strlen(kTagStart);
  384.     SIZE_TYPE tag_end_size   = strlen(kTagEnd);
  385.     x_PrintBegin(out, mode, text.substr(0, tagStart));
  386.     SIZE_TYPE last = tagStart;
  387.     do {
  388.         SIZE_TYPE tagNameStart = tagStart + tag_start_size;
  389.         SIZE_TYPE tagNameEnd = s_Find(text, kTagEnd, tagNameStart);
  390.         if ( tagNameEnd == NPOS ) {
  391.             // tag not closed
  392.             NCBI_THROW(CHTMLException, eTextUnclosedTag, "tag not closed");
  393.         }
  394.         else {
  395.             // tag found
  396.             if ( last != tagStart ) {
  397.                 x_PrintBegin(out, mode, text.substr(last, tagStart - last));
  398.             }
  399.             string name = text.substr(tagNameStart,tagNameEnd-tagNameStart);
  400.             // Resolve and repeat tag
  401.             for (;;) {
  402.                 CNodeRef tag = MapTagAll(name, mode);
  403.                 if ( tag ) {
  404.                     tag->Print(out, mode);
  405.                     if ( tag->NeedRepeatTag() ) {
  406.                         RepeatTag(false);
  407.                         continue;
  408.                     }
  409.                 }
  410.                 break;
  411.             }
  412.             last = tagNameEnd + tag_end_size;
  413.             tagStart = s_Find(text, kTagStart, last);
  414.         }
  415.     } while ( tagStart != NPOS );
  416.     if ( last != text.size() ) {
  417.         x_PrintBegin(out, mode, text.substr(last));
  418.     }
  419.     return out;
  420. }
  421. CHTMLOpenElement::~CHTMLOpenElement(void)
  422. {
  423.     return;
  424. }
  425. CNcbiOstream& CHTMLOpenElement::PrintBegin(CNcbiOstream& out, TMode mode)
  426. {
  427.     if ( mode != ePlainText ) {
  428.         out << '<' << m_Name;
  429.         if ( HaveAttributes() ) {
  430.             for ( TAttributes::const_iterator i = Attributes().begin();
  431.                   i != Attributes().end(); ++i ) {
  432.                 out << ' ' << i->first;
  433.                 CHECK_STREAM_WRITE(out);
  434.                 if ( !i->second.IsOptional() ||
  435.                      !i->second.GetValue().empty() ) {
  436.                     out << "="" << i->second.GetValue() << '"';
  437.                 }
  438.             }
  439.         }
  440.         if ( m_NoWrap ) {
  441.             out << " nowrap";
  442.         }
  443.         out << '>';
  444.         CHECK_STREAM_WRITE(out);
  445.     }
  446.     return out;
  447. }
  448. CHTMLInlineElement::~CHTMLInlineElement(void)
  449. {
  450.     return;
  451. }
  452. CNcbiOstream& CHTMLInlineElement::PrintEnd(CNcbiOstream& out, TMode mode)
  453. {
  454.     if ( mode != ePlainText ) {
  455.         out << "</" << m_Name << '>';
  456.         CHECK_STREAM_WRITE(out);
  457.     }
  458.     return out;
  459. }
  460. CHTMLElement::~CHTMLElement(void)
  461. {
  462.     return;
  463. }
  464. CNcbiOstream& CHTMLElement::PrintEnd(CNcbiOstream& out, TMode mode)
  465. {
  466.     CParent::PrintEnd(out, mode);
  467.     if ( mode != ePlainText ) {
  468.         const TMode* previous = mode.GetPreviousContext();
  469.         if ( previous ) {
  470.             CNCBINode* parent = previous->GetNode();
  471.             if ( parent && parent->HaveChildren() &&
  472.                  parent->Children().size() > 1 )
  473.                 out << 'n'; // separate child nodes by newline
  474.         } else {
  475.             out << 'n';
  476.         }
  477.     }
  478.     CHECK_STREAM_WRITE(out);
  479.     return out;
  480. }
  481. CHTMLBlockElement::~CHTMLBlockElement(void)
  482. {
  483.     return;
  484. }
  485. CNcbiOstream& CHTMLBlockElement::PrintEnd(CNcbiOstream& out, TMode mode)
  486. {
  487.     CParent::PrintEnd(out, mode);
  488.     if ( mode == ePlainText ) {
  489.         // Add a newline iff no node on the path to the last descendant
  490.         // is also a block element. We only need one break.
  491.         CNCBINode* node = this;
  492.         while (node->HaveChildren()) {
  493.             node = node->Children().back();
  494.             if (dynamic_cast<CHTMLBlockElement*>(node)) {
  495.                 return out;
  496.             }
  497.         }
  498.         out << 'n';
  499.         CHECK_STREAM_WRITE(out);
  500.     }
  501.     return out;
  502. }
  503. // HTML comment.
  504. const char CHTMLComment::sm_TagName[] = "comment";
  505. CHTMLComment::~CHTMLComment(void)
  506. {
  507.     return;
  508. }
  509. CNcbiOstream& CHTMLComment::Print(CNcbiOstream& out, TMode mode)
  510. {
  511.     if (mode == ePlainText) {
  512.         return out;
  513.     }
  514.     return CParent::Print(out, mode);
  515. }
  516. CNcbiOstream& CHTMLComment::PrintBegin(CNcbiOstream& out, TMode mode)
  517. {
  518.     if (mode == eHTML) {
  519.         out << "<!--";
  520.         CHECK_STREAM_WRITE(out);
  521.     }
  522.     return out;
  523. }
  524. CNcbiOstream& CHTMLComment::PrintEnd(CNcbiOstream& out, TMode mode)
  525. {
  526.     if (mode == eHTML) {
  527.         return out << "-->";
  528.     }
  529.     CHECK_STREAM_WRITE(out);
  530.     return out;
  531. }
  532. CHTMLListElement::~CHTMLListElement(void)
  533. {
  534.     return;
  535. }
  536. CHTMLListElement* CHTMLListElement::SetType(const char* type)
  537. {
  538.     SetAttribute("type", type);
  539.     return this;
  540. }
  541. CHTMLListElement* CHTMLListElement::SetType(const string& type)
  542. {
  543.     SetAttribute("type", type);
  544.     return this;
  545. }
  546. CHTMLListElement* CHTMLListElement::SetCompact(void)
  547. {
  548.     SetOptionalAttribute("compact", true);
  549.     return this;
  550. }
  551. CNcbiOstream& CHTMLListElement::PrintChildren(CNcbiOstream& out, TMode mode)
  552. {
  553.     if (mode == ePlainText) {
  554.         CIndentingOstream out2(out);
  555.         CHTMLElement::PrintChildren(out2, mode);
  556.     } else {
  557.         CHTMLElement::PrintChildren(out, mode);
  558.     }
  559.     return out;
  560. }
  561. // Special char.
  562. CHTMLSpecialChar::CHTMLSpecialChar(const char* html, const char* plain,
  563.                                    int count)
  564.     : CParent("", plain)
  565. {
  566.     m_Name  = s_GenerateNodeInternalName("specialchar", html);
  567.     m_Html  = html;
  568.     m_Count = count;
  569. }
  570. CHTMLSpecialChar::~CHTMLSpecialChar(void)
  571. {
  572.     return;
  573. }
  574. CNcbiOstream& CHTMLSpecialChar::PrintChildren(CNcbiOstream& out, TMode mode)
  575. {
  576.     if ( mode == ePlainText ) {
  577.         for ( int i = 0; i < m_Count; i++ ) {
  578.             out << m_Plain;
  579.             CHECK_STREAM_WRITE(out);
  580.         }
  581.     } else {
  582.         for ( int i = 0; i < m_Count; i++ ) {
  583.             out << "&" << m_Html << ";";
  584.             CHECK_STREAM_WRITE(out);
  585.         }
  586.     }
  587.     return out;
  588. }
  589. // <html> tag.
  590. const char CHTML_html::sm_TagName[] = "html";
  591. CHTML_html::~CHTML_html(void)
  592. {
  593.     return;
  594. }
  595. void CHTML_html::Init(void)
  596. {
  597.     return;
  598. }
  599. void CHTML_html::EnablePopupMenu(CHTMLPopupMenu::EType type,
  600.                                  const string& menu_script_url,
  601.                                  bool use_dynamic_menu)
  602. {
  603.     SPopupMenuInfo info(menu_script_url, use_dynamic_menu);
  604.     m_PopupMenus[type] = info;
  605. }
  606. static bool s_CheckUsePopupMenus(const CNCBINode* node, 
  607.                                  CHTMLPopupMenu::EType type)
  608. {
  609.     if ( !node  ||  !node->HaveChildren() ) {
  610.         return false;
  611.     }
  612.     ITERATE ( CNCBINode::TChildren, i, node->Children() ) {
  613.         const CNCBINode* cnode = node->Node(i);
  614.         if ( dynamic_cast<const CHTMLPopupMenu*>(cnode) ) {
  615.             const CHTMLPopupMenu* menu = 
  616.                 dynamic_cast<const CHTMLPopupMenu*>(cnode);
  617.             if ( menu->GetType() == type )
  618.                 return true;
  619.         }
  620.         if ( cnode->HaveChildren()  &&  s_CheckUsePopupMenus(cnode, type)) {
  621.             return true;
  622.         }
  623.     }
  624.     return false;
  625. }
  626. CNcbiOstream& CHTML_html::PrintChildren(CNcbiOstream& out, TMode mode)
  627. {
  628.     // Check mode
  629.     if ( mode != eHTML ) {
  630.         return CParent::PrintChildren(out, mode);
  631.     }
  632.     
  633.     // Check for use popup menus
  634.     bool use_popup_menus = false;
  635.     for (int t = CHTMLPopupMenu::ePMFirst; t <= CHTMLPopupMenu::ePMLast; t++ )    {
  636.         CHTMLPopupMenu::EType type = (CHTMLPopupMenu::EType)t;
  637.         if ( m_PopupMenus.find(type) == m_PopupMenus.end() ) {
  638.             if ( s_CheckUsePopupMenus(this, type) ) {
  639.                 EnablePopupMenu(type);
  640.                 use_popup_menus = true;
  641.             }
  642.         } else {
  643.             use_popup_menus = true;
  644.         }
  645.     }
  646.     if ( !use_popup_menus  ||  !HaveChildren() ) {
  647.         return CParent::PrintChildren(out, mode);
  648.     }
  649.     NON_CONST_ITERATE ( TChildren, i, Children() ) {
  650.         if ( dynamic_cast<CHTML_head*>(Node(i)) ) {
  651.             for (int t = CHTMLPopupMenu::ePMFirst;
  652.                  t <= CHTMLPopupMenu::ePMLast; t++ ) {
  653.                 CHTMLPopupMenu::EType type = (CHTMLPopupMenu::EType)t;
  654.                 TPopupMenus::const_iterator info = m_PopupMenus.find(type);
  655.                 if ( info != m_PopupMenus.end() ) {
  656.                     Node(i)->AppendChild(new CHTMLText(
  657.                         CHTMLPopupMenu::GetCodeHead(type,info->second.m_Url)));
  658.                 }
  659.             }
  660.         } else if ( dynamic_cast<CHTML_body*>(Node(i)) ) {
  661.             for (int t = CHTMLPopupMenu::ePMFirst;
  662.                  t <= CHTMLPopupMenu::ePMLast; t++ ) {
  663.                 CHTMLPopupMenu::EType type = (CHTMLPopupMenu::EType)t;
  664.                 TPopupMenus::const_iterator info = m_PopupMenus.find(type);
  665.                 if ( info != m_PopupMenus.end() ) {
  666.                     Node(i)->AppendChild(new CHTMLText(
  667.                         CHTMLPopupMenu::GetCodeBody(type, info->second.m_UseDynamicMenu)));
  668.                 }
  669.             }
  670.         }
  671.     }
  672.     return CParent::PrintChildren(out, mode);
  673. }
  674. // Table element.
  675. class CHTML_tc_Cache
  676. {
  677. public:
  678.     CHTML_tc_Cache(void)
  679.         : m_Used(false), m_Node(0)
  680.     {
  681.         return;
  682.     }
  683.     bool IsUsed(void) const
  684.     {
  685.         return m_Used;
  686.     }
  687.     bool IsNode(void) const
  688.     {
  689.         return m_Node != 0;
  690.     }
  691.     CHTML_tc* GetCellNode(void) const
  692.     {
  693.         return m_Node;
  694.     }
  695.     void SetUsed(void);
  696.     void SetCellNode(CHTML_tc* node);
  697. private:
  698.     bool m_Used;
  699.     CHTML_tc* m_Node;
  700. };
  701. class CHTML_tr_Cache
  702. {
  703. public:
  704.     typedef CHTML_table::TIndex TIndex;
  705.     CHTML_tr_Cache(void)
  706.         : m_Node(0),
  707.           m_CellCount(0), m_CellsSize(0), m_Cells(0), m_FilledCellCount(0)
  708.     {
  709.         return;
  710.     }
  711.     ~CHTML_tr_Cache(void)
  712.     {
  713.         delete[] m_Cells;
  714.     }
  715.     CHTML_tr* GetRowNode(void) const
  716.     {
  717.         return m_Node;
  718.     }
  719.     void SetRowNode(CHTML_tr* rowNode)
  720.     {
  721.         _ASSERT(!m_Node && rowNode);
  722.         m_Node = rowNode;
  723.     }
  724.     TIndex GetCellCount(void) const
  725.     {
  726.         return m_CellCount;
  727.     }
  728.     CHTML_tc_Cache& GetCellCache(TIndex col);
  729.     void AppendCell(CHTML_tr* rowNode, TIndex col,
  730.                     CHTML_tc* cellNode, TIndex colSpan);
  731.     void SetUsedCells(TIndex colBegin, TIndex colEnd);
  732.     void SetUsedCells(CHTML_tc* cellNode, TIndex colBegin, TIndex colEnd);
  733. private:
  734.     CHTML_tr_Cache(const CHTML_tr_Cache&);
  735.     CHTML_tr_Cache& operator=(const CHTML_tr_Cache&);
  736.     CHTML_tr* m_Node;
  737.     TIndex m_CellCount;
  738.     TIndex m_CellsSize;
  739.     CHTML_tc_Cache* m_Cells;
  740.     TIndex m_FilledCellCount;
  741. };
  742. class CHTML_table_Cache
  743. {
  744. public:
  745.     typedef CHTML_table::TIndex TIndex;
  746.     CHTML_table_Cache(CHTML_table* table);
  747.     ~CHTML_table_Cache(void);
  748.     TIndex GetRowCount(void) const
  749.     {
  750.         return m_RowCount;
  751.     }
  752.     CHTML_tr_Cache& GetRowCache(TIndex row);
  753.     CHTML_tr* GetRowNode(TIndex row);
  754.     CHTML_tc* GetCellNode(TIndex row, TIndex col,
  755.                           CHTML_table::ECellType type);
  756.     CHTML_tc* GetCellNode(TIndex row, TIndex col,
  757.                           CHTML_table::ECellType type,
  758.                           TIndex rowSpan, TIndex colSpan);
  759.     void InitRow(TIndex row, CHTML_tr* rowNode);
  760.     void SetUsedCells(TIndex rowBegin, TIndex rowEnd,
  761.                       TIndex colBegin, TIndex colEnd);
  762. private:
  763.     CHTML_table* m_Node;
  764.     TIndex m_RowCount;
  765.     TIndex m_RowsSize;
  766.     CHTML_tr_Cache** m_Rows;
  767.     TIndex m_FilledRowCount;
  768.     CHTML_table_Cache(const CHTML_table_Cache&);
  769.     CHTML_table_Cache& operator=(const CHTML_table_Cache&);
  770. };
  771. CHTML_tr::CHTML_tr(void)
  772.     : CParent("tr"), m_Parent(0)
  773. {
  774.     return;
  775. }
  776. CHTML_tr::CHTML_tr(CNCBINode* node)
  777.     : CParent("tr", node), m_Parent(0)
  778. {
  779.     return;
  780. }
  781. CHTML_tr::CHTML_tr(const string& text)
  782.     : CParent("tr", text), m_Parent(0)
  783. {
  784.     return;
  785. }
  786. void CHTML_tr::DoAppendChild(CNCBINode* node)
  787. {
  788.     CHTML_tc* cell = dynamic_cast<CHTML_tc*>(node);
  789.     if ( cell ) {
  790.         // Adding new cell
  791.         _ASSERT(!cell->m_Parent);
  792.         ResetTableCache();
  793.         cell->m_Parent = this;
  794.     }
  795.     CParent::DoAppendChild(node);
  796. }
  797. void CHTML_tr::AppendCell(CHTML_tc* cell)
  798. {
  799.     _ASSERT(!cell->m_Parent);
  800.     cell->m_Parent = this;
  801.     CParent::DoAppendChild(cell);
  802. }
  803. void CHTML_tr::ResetTableCache(void)
  804. {
  805.     if ( m_Parent )
  806.         m_Parent->ResetTableCache();
  807. }
  808. CNcbiOstream& CHTML_tr::PrintEnd(CNcbiOstream& out, TMode mode)
  809. {
  810.     CParent::PrintEnd(out, mode);
  811.     if ( mode == ePlainText ) {
  812.         out << CHTMLHelper::GetNL();
  813.         if (m_Parent->m_IsRowSep == CHTML_table::ePrintRowSep) {
  814.             out << string(GetTextLength(mode), m_Parent->m_RowSepChar)
  815.                 << CHTMLHelper::GetNL();
  816.         }
  817.         CHECK_STREAM_WRITE(out);
  818.     }
  819.     return out;
  820. }
  821. CNcbiOstream& CHTML_tr::PrintChildren(CNcbiOstream& out, TMode mode)
  822. {
  823.     if ( !HaveChildren() ) {
  824.         return out;
  825.     }
  826.     if ( mode != ePlainText ) {
  827.         return CParent::PrintChildren(out, mode);
  828.     }
  829.     out << m_Parent->m_ColSepL;
  830.     NON_CONST_ITERATE ( TChildren, i, Children() ) {
  831.         if ( i != Children().begin() ) {
  832.             out << m_Parent->m_ColSepM;
  833.             CHECK_STREAM_WRITE(out);
  834.         }
  835.         Node(i)->Print(out, mode);
  836.     }
  837.     out << m_Parent->m_ColSepR;
  838.     CHECK_STREAM_WRITE(out);
  839.     return out;
  840. }
  841. SIZE_TYPE CHTML_tr::GetTextLength(TMode mode)
  842. {
  843.     if ( !HaveChildren() ) {
  844.         return 0;
  845.     }
  846.     CNcbiOstrstream sout;
  847.     SIZE_TYPE cols = 0;
  848.     NON_CONST_ITERATE ( TChildren, i, Children() ) {
  849.         Node(i)->Print(sout, mode);
  850.         cols++;
  851.     }
  852.     sout.put('');
  853.     SIZE_TYPE textlen = strlen(sout.str());
  854.     if ( mode == ePlainText ) {
  855.         textlen += m_Parent->m_ColSepL.length() +
  856.             m_Parent->m_ColSepR.length();
  857.         if ( cols ) {
  858.             textlen += m_Parent->m_ColSepM.length() * (cols - 1);
  859.         }
  860.     }
  861.     return textlen;
  862. }
  863. CHTML_tc::~CHTML_tc(void)
  864. {
  865.     return;
  866. }
  867. CHTML_tc* CHTML_tc::SetRowSpan(TIndex span)
  868. {
  869.     SetAttribute("rowspan", span);
  870.     return this;
  871. }
  872. CHTML_tc* CHTML_tc::SetColSpan(TIndex span)
  873. {
  874.     SetAttribute("colspan", span);
  875.     return this;
  876. }
  877. static 
  878. CHTML_table::TIndex x_GetSpan(const CHTML_tc* node,
  879.                               const string& attributeName)
  880. {
  881.     if ( !node->HaveAttribute(attributeName) ) {
  882.         return 1;
  883.     }
  884.     const string& value = node->GetAttribute(attributeName);
  885.     try {
  886.         CHTML_table::TIndex span = NStr::StringToUInt(value);
  887.         if ( span > 0 ) {
  888.             return span;
  889.         }
  890.     }
  891.     catch ( exception& ) {
  892.         // Error will be posted later
  893.     }
  894.     ERR_POST("Bad attribute: " << attributeName << "="" << value << """);
  895.     return 1;
  896. }
  897. void CHTML_tc::DoSetAttribute(const string& name,
  898.                               const string& value, bool optional)
  899. {
  900.     if (name == "rowspan"  ||  name == "colspan") {
  901.         // Changing cell size
  902.         ResetTableCache();
  903.     }
  904.     CParent::DoSetAttribute(name, value, optional);
  905. }
  906. void CHTML_tc::ResetTableCache(void)
  907. {
  908.     if ( m_Parent ) {
  909.         m_Parent->ResetTableCache();
  910.     }
  911. }
  912. void CHTML_tc_Cache::SetUsed()
  913. {
  914.     if ( IsUsed() ) {
  915.         NCBI_THROW(CHTMLException, eTableCellUse, "overlapped table cells");
  916.     }
  917.     m_Used = true;
  918. }
  919. void CHTML_tc_Cache::SetCellNode(CHTML_tc* cellNode)
  920. {
  921.     SetUsed();
  922.     m_Node = cellNode;
  923. }
  924. static
  925. CHTML_table::TIndex x_NextSize(CHTML_table::TIndex size,
  926.                                CHTML_table::TIndex limit)
  927. {
  928.     do {
  929.         if ( size == 0 )
  930.             size = 2;
  931.         else
  932.             size *= 2;
  933.     } while ( size < limit );
  934.     return size;
  935. }
  936. CHTML_tc_Cache& CHTML_tr_Cache::GetCellCache(TIndex col)
  937. {
  938.     TIndex count = GetCellCount();
  939.     if ( col >= count ) {
  940.         TIndex newCount = col + 1;
  941.         TIndex size = m_CellsSize;
  942.         if ( newCount > size ) {
  943.             TIndex newSize = x_NextSize(size, newCount);
  944.             CHTML_tc_Cache* newCells = new CHTML_tc_Cache[newSize];
  945.             for ( TIndex i = 0; i < count; ++i )
  946.                 newCells[i] = m_Cells[i];
  947.             delete[] m_Cells;
  948.             m_Cells = newCells;
  949.             m_CellsSize = newSize;
  950.         }
  951.         m_CellCount = newCount;
  952.     }
  953.     return m_Cells[col];
  954. }
  955. void CHTML_tr_Cache::SetUsedCells(TIndex colBegin, TIndex colEnd)
  956. {
  957.     for ( TIndex col = colBegin; col < colEnd; ++col ) {
  958.         GetCellCache(col).SetUsed();
  959.     }
  960. }
  961. void CHTML_tr_Cache::AppendCell(CHTML_tr* rowNode, TIndex col,
  962.                                 CHTML_tc* cellNode, TIndex colSpan)
  963. {
  964.     _ASSERT(m_FilledCellCount <= col);
  965.     for ( TIndex i = m_FilledCellCount; i < col; ++i ) {
  966.         CHTML_tc_Cache& cellCache = GetCellCache(i);
  967.         if ( !cellCache.IsUsed() ) {
  968.             CHTML_tc* cell;
  969.             cell = new CHTML_td;
  970.             rowNode->AppendCell(cell);
  971.             cellCache.SetCellNode(cell);
  972.         }
  973.     }
  974.     CHTML_tc_Cache& cellCache = GetCellCache(col);
  975.     _ASSERT(!cellCache.IsUsed());
  976.     _ASSERT(x_GetSpan(cellNode, "colspan") == colSpan);
  977.     rowNode->AppendCell(cellNode);
  978.     cellCache.SetCellNode(cellNode);
  979.     if ( colSpan != 1 ) {
  980.         SetUsedCells(col + 1, col + colSpan);
  981.     }
  982.     m_FilledCellCount = col + colSpan;
  983. }
  984. void CHTML_tr_Cache::SetUsedCells(CHTML_tc* cellNode,
  985.                                   TIndex colBegin, TIndex colEnd)
  986. {
  987.     GetCellCache(colBegin).SetCellNode(cellNode);
  988.     SetUsedCells(colBegin + 1, colEnd);
  989.     m_FilledCellCount = colEnd;
  990. }
  991. CHTML_table_Cache::~CHTML_table_Cache(void)
  992. {
  993.     for ( TIndex i = 0; i < GetRowCount(); ++i ) {
  994.         delete m_Rows[i];
  995.     }
  996.     delete[] m_Rows;
  997. }
  998. CHTML_tr_Cache& CHTML_table_Cache::GetRowCache(TIndex row)
  999. {
  1000.     TIndex count = GetRowCount();
  1001.     if ( row >= count ) {
  1002.         TIndex newCount = row + 1;
  1003.         TIndex size = m_RowsSize;
  1004.         if ( newCount > size ) {
  1005.             TIndex newSize = x_NextSize(size, newCount);
  1006.             CHTML_tr_Cache** newRows = new CHTML_tr_Cache*[newSize];
  1007.             for ( TIndex i = 0; i < count; ++i )
  1008.                 newRows[i] = m_Rows[i];
  1009.             delete[] m_Rows;
  1010.             m_Rows = newRows;
  1011.             m_RowsSize = newSize;
  1012.         }
  1013.         for ( TIndex i = count; i < newCount; ++i )
  1014.             m_Rows[i] = new CHTML_tr_Cache;
  1015.         m_RowCount = newCount;
  1016.     }
  1017.     return *m_Rows[row];
  1018. }
  1019. void CHTML_table_Cache::InitRow(TIndex row, CHTML_tr* rowNode)
  1020. {
  1021.     CHTML_tr_Cache& rowCache = GetRowCache(row);
  1022.     m_Rows[row]->SetRowNode(rowNode);
  1023.     m_FilledRowCount = row + 1;
  1024.     // Scan all children (which should be <TH> or <TD> tags)
  1025.     if ( rowNode->HaveChildren() ) {
  1026.         // Beginning with column 0
  1027.         TIndex col = 0;
  1028.         for ( CNCBINode::TChildren::iterator iCol = rowNode->ChildBegin(),
  1029.               iColEnd = rowNode->ChildEnd();
  1030.               iCol != iColEnd; ++iCol ) {
  1031.             CHTML_tc* cellNode =
  1032.                 dynamic_cast<CHTML_tc*>(rowNode->Node(iCol));
  1033.             if ( !cellNode ) {
  1034.                 continue;
  1035.             }
  1036.             // Skip all used cells
  1037.             while ( rowCache.GetCellCache(col).IsUsed() ) {
  1038.                 ++col;
  1039.             }
  1040.             // Determine current cell size
  1041.             TIndex rowSpan = x_GetSpan(cellNode, "rowspan");
  1042.             TIndex colSpan = x_GetSpan(cellNode, "colspan");
  1043.             // End of new cell in columns
  1044.             rowCache.SetUsedCells(cellNode, col, col + colSpan);
  1045.             if ( rowSpan > 1 ) {
  1046.                 SetUsedCells(row + 1, row + rowSpan, col, col + colSpan);
  1047.             }
  1048.             // Skip this cell's columns
  1049.             col += colSpan;
  1050.         }
  1051.     }
  1052. }
  1053. CHTML_table_Cache::CHTML_table_Cache(CHTML_table* table)
  1054.     : m_Node(table),
  1055.       m_RowCount(0), m_RowsSize(0), m_Rows(0), m_FilledRowCount(0)
  1056. {
  1057.     // Scan all children (which should be <TR> tags)
  1058.     if ( table->HaveChildren() ) {
  1059.         // Beginning with row 0
  1060.         TIndex row = 0;
  1061.         for ( CNCBINode::TChildren::iterator iRow = table->ChildBegin(),
  1062.               iRowEnd = table->ChildEnd(); iRow != iRowEnd; ++iRow ) {
  1063.             CHTML_tr* rowNode = dynamic_cast<CHTML_tr*>(table->Node(iRow));
  1064.             if ( !rowNode ) {
  1065.                 continue;
  1066.             }
  1067.             InitRow(row, rowNode);
  1068.             ++row;
  1069.         }
  1070.     }
  1071. }
  1072. CHTML_tr* CHTML_table_Cache::GetRowNode(TIndex row)
  1073. {
  1074.     GetRowCache(row);
  1075.     while ( row >= m_FilledRowCount ) {
  1076.         CHTML_tr* rowNode = new CHTML_tr;
  1077.         m_Node->AppendRow(rowNode);
  1078.         m_Rows[m_FilledRowCount++]->SetRowNode(rowNode);
  1079.     }
  1080.     return m_Rows[row]->GetRowNode();
  1081. }
  1082. void CHTML_table_Cache::SetUsedCells(TIndex rowBegin, TIndex rowEnd,
  1083.                                      TIndex colBegin, TIndex colEnd)
  1084. {
  1085.     for ( TIndex row = rowBegin; row < rowEnd; ++row ) {
  1086.         GetRowCache(row).SetUsedCells(colBegin, colEnd);
  1087.     }
  1088. }
  1089. CHTML_tc* CHTML_table_Cache::GetCellNode(TIndex row, TIndex col,
  1090.                                          CHTML_table::ECellType type)
  1091. {
  1092.     CHTML_tr_Cache& rowCache = GetRowCache(row);
  1093.     if ( col < rowCache.GetCellCount() ) {
  1094.         CHTML_tc_Cache& cellCache = rowCache.GetCellCache(col);
  1095.         if ( cellCache.IsNode() ) {
  1096.             CHTML_tc* cell = cellCache.GetCellNode();
  1097.             switch ( type ) {
  1098.             case CHTML_table::eHeaderCell:
  1099.                 if ( !dynamic_cast<CHTML_th*>(cell) )
  1100.                     NCBI_THROW(CHTMLException, eTableCellType,
  1101.                                "wrong cell type: TH expected");
  1102.                 break;
  1103.             case CHTML_table::eDataCell:
  1104.                 if ( !dynamic_cast<CHTML_td*>(cell) )
  1105.                     NCBI_THROW(CHTMLException, eTableCellType,
  1106.                                "wrong cell type: TD expected");
  1107.                 break;
  1108.             default:
  1109.                 break;
  1110.             }
  1111.             return cell;
  1112.         }
  1113.         if ( cellCache.IsUsed() )
  1114.             NCBI_THROW(CHTMLException, eTableCellUse,
  1115.                        "invalid use of big table cell");
  1116.     }
  1117.     CHTML_tc* cell;
  1118.     if ( type == CHTML_table::eHeaderCell ) {
  1119.         cell = new CHTML_th;
  1120.     } else {
  1121.         cell = new CHTML_td;
  1122.     }
  1123.     rowCache.AppendCell(GetRowNode(row), col, cell, 1);
  1124.     return cell;
  1125. }
  1126. CHTML_tc* CHTML_table_Cache::GetCellNode(TIndex row, TIndex col,
  1127.                                          CHTML_table::ECellType type,
  1128.                                          TIndex rowSpan, TIndex colSpan)
  1129. {
  1130.     CHTML_tr_Cache& rowCache = GetRowCache(row);
  1131.     if ( col < rowCache.GetCellCount() ) {
  1132.         CHTML_tc_Cache& cellCache = rowCache.GetCellCache(col);
  1133.         if ( cellCache.IsNode() ) {
  1134.             CHTML_tc* cell = cellCache.GetCellNode();
  1135.             switch ( type ) {
  1136.             case CHTML_table::eHeaderCell:
  1137.                 if ( !dynamic_cast<CHTML_th*>(cell) )
  1138.                     NCBI_THROW(CHTMLException, eTableCellType,
  1139.                                "wrong cell type: TH expected");
  1140.                 break;
  1141.             case CHTML_table::eDataCell:
  1142.                 if ( !dynamic_cast<CHTML_td*>(cell) )
  1143.                     NCBI_THROW(CHTMLException, eTableCellType,
  1144.                                "wrong cell type: TD expected");
  1145.                 break;
  1146.             default:
  1147.                 break;
  1148.             }
  1149.             if ( x_GetSpan(cell, "rowspan") != rowSpan ||
  1150.                  x_GetSpan(cell, "colspan") != colSpan )
  1151.                 NCBI_THROW(CHTMLException, eTableCellUse,
  1152.                            "cannot change table cell size");
  1153.             return cell;
  1154.         }
  1155.         if ( cellCache.IsUsed() )
  1156.             NCBI_THROW(CHTMLException, eTableCellUse,
  1157.                        "invalid use of big table cell");
  1158.     }
  1159.     CHTML_tc* cell;
  1160.     if ( type == CHTML_table::eHeaderCell ) {
  1161.         cell = new CHTML_th;
  1162.     } else {
  1163.         cell = new CHTML_td;
  1164.     }
  1165.     if ( colSpan != 1 ) {
  1166.         cell->SetColSpan(colSpan);
  1167.     }
  1168.     if ( rowSpan != 1 ) {
  1169.         cell->SetRowSpan(rowSpan);
  1170.     }
  1171.     rowCache.AppendCell(GetRowNode(row), col, cell, colSpan);
  1172.     if ( rowSpan != 1 ) {
  1173.         SetUsedCells(row + 1, row + rowSpan, col, col + colSpan);
  1174.     }
  1175.     return cell;
  1176. }
  1177. CHTML_table::CHTML_table(void)
  1178.     : CParent("table"), m_CurrentRow(0), m_CurrentCol(TIndex(-1)),
  1179.       m_ColSepL(kEmptyStr), m_ColSepM(" "), m_ColSepR(kEmptyStr),
  1180.       m_RowSepChar('-'), m_IsRowSep(eSkipRowSep)
  1181. {
  1182.     return;
  1183. }
  1184. CHTML_table::~CHTML_table(void)
  1185. {
  1186.     return;
  1187. }
  1188. CHTML_table* CHTML_table::SetCellSpacing(int spacing)
  1189. {
  1190.     SetAttribute("cellspacing", spacing);
  1191.     return this;
  1192. }
  1193. CHTML_table* CHTML_table::SetCellPadding(int padding)
  1194. {
  1195.     SetAttribute("cellpadding", padding);
  1196.     return this;
  1197. }
  1198. void CHTML_table::ResetTableCache(void)
  1199. {
  1200.     m_Cache.reset(0);
  1201. }
  1202. CHTML_table_Cache& CHTML_table::GetCache(void) const
  1203. {
  1204.     CHTML_table_Cache* cache = m_Cache.get();
  1205.     if ( !cache ) {
  1206.         m_Cache.reset(cache =
  1207.                       new CHTML_table_Cache(const_cast<CHTML_table*>(this)));
  1208.     }
  1209.     return *cache;
  1210. }
  1211. void CHTML_table::DoAppendChild(CNCBINode* node)
  1212. {
  1213.     CHTML_tr* row = dynamic_cast<CHTML_tr*>(node);
  1214.     if ( row ) {
  1215.         // Adding new row
  1216.         _ASSERT(!row->m_Parent);
  1217.         ResetTableCache();
  1218.         row->m_Parent = this;
  1219.     }
  1220.     CParent::DoAppendChild(node);
  1221. }
  1222. void CHTML_table::AppendRow(CHTML_tr* row)
  1223. {
  1224.     _ASSERT(!row->m_Parent);
  1225.     row->m_Parent = this;
  1226.     CParent::DoAppendChild(row);
  1227. }
  1228. CHTML_tr* CHTML_table::Row(TIndex row)
  1229. {
  1230.     return GetCache().GetRowNode(row);
  1231. }
  1232. CHTML_tc* CHTML_table::Cell(TIndex row, TIndex col, ECellType type)
  1233. {
  1234.     return GetCache().GetCellNode(m_CurrentRow = row, m_CurrentCol = col,
  1235.                                   type);
  1236. }
  1237. CHTML_tc* CHTML_table::Cell(TIndex row, TIndex col, ECellType type,
  1238.                             TIndex rowSpan, TIndex colSpan)
  1239. {
  1240.     return GetCache().GetCellNode(m_CurrentRow = row, m_CurrentCol = col,
  1241.                                   type, rowSpan, colSpan);
  1242. }
  1243. void CHTML_table::CheckTable(void) const
  1244. {
  1245.     GetCache();
  1246. }
  1247. CHTML_table::TIndex CHTML_table::CalculateNumberOfColumns(void) const
  1248. {
  1249.     CHTML_table_Cache& cache = GetCache();
  1250.     TIndex columns = 0;
  1251.     for ( TIndex i = 0; i < cache.GetRowCount(); ++i ) {
  1252.         columns = max(columns, cache.GetRowCache(i).GetCellCount());
  1253.     }
  1254.     return columns;
  1255. }
  1256. CHTML_table::TIndex CHTML_table::CalculateNumberOfRows(void) const
  1257. {
  1258.     return GetCache().GetRowCount();
  1259. }
  1260. CNcbiOstream& CHTML_table::PrintBegin(CNcbiOstream& out, TMode mode)
  1261. {
  1262.     if ( mode == ePlainText ) {
  1263.         out << CHTMLHelper::GetNL();
  1264.         CHECK_STREAM_WRITE(out);
  1265.         if ( m_IsRowSep == ePrintRowSep ) {
  1266.             SIZE_TYPE seplen = 0;
  1267.             // Find length of first non-empty row
  1268.             NON_CONST_ITERATE ( TChildren, i, Children() ) {
  1269.                 if ( (seplen =
  1270.                       dynamic_cast<CHTML_tr*>(&**i)->GetTextLength(mode)) >0) {
  1271.                     break;
  1272.                 }
  1273.             }
  1274.             if ( !seplen ) {
  1275.                 seplen = 1;
  1276.             }
  1277.             out << string(seplen, m_RowSepChar) << CHTMLHelper::GetNL();
  1278.             CHECK_STREAM_WRITE(out);
  1279.         }
  1280.     }
  1281.     return CParent::PrintBegin(out, mode);
  1282. }
  1283. void CHTML_table::SetPlainSeparators(const string& col_left,
  1284.                                      const string& col_middle,
  1285.                                      const string& col_right,
  1286.                                      const char    row_sep_char,
  1287.                                      ERowPlainSep  is_row_sep)
  1288. {
  1289.     m_ColSepL    = col_left;
  1290.     m_ColSepM    = col_middle;
  1291.     m_ColSepR    = col_right;
  1292.     m_RowSepChar = row_sep_char;
  1293.     m_IsRowSep   = is_row_sep;
  1294. }
  1295. // <form> tag.
  1296. CHTML_form::CHTML_form(void)
  1297.     : CParent("form")
  1298. {
  1299.     return;
  1300. }
  1301. CHTML_form::CHTML_form(const string& url, EMethod method)
  1302.     : CParent("form")
  1303. {
  1304.     Init(url, method);
  1305. }
  1306. CHTML_form::CHTML_form(const string& url, CNCBINode* node, EMethod method)
  1307.     : CParent("form", node)
  1308. {
  1309.     Init(url, method);
  1310. }
  1311. CHTML_form::~CHTML_form(void)
  1312. {
  1313.     return;
  1314. }
  1315. void CHTML_form::Init(const string& url, EMethod method)
  1316. {
  1317.     SetOptionalAttribute("action", url);
  1318.     switch ( method ) {
  1319.     case eGet:
  1320.         SetAttribute("method", "GET");
  1321.         break;
  1322.     case ePost:
  1323.         SetAttribute("enctype",
  1324.                      "application/x-www-form-urlencoded");
  1325.         SetAttribute("method", "POST");
  1326.         break;
  1327.     case ePostData:
  1328.         SetAttribute("enctype",
  1329.                      "multipart/form-data");
  1330.         SetAttribute("method", "POST");
  1331.         break;
  1332.     }
  1333. }
  1334. void CHTML_form::AddHidden(const string& name, const string& value)
  1335. {
  1336.     AppendChild(new CHTML_hidden(name, value));
  1337. }
  1338. void CHTML_form::AddHidden(const string& name, int value)
  1339. {
  1340.     AppendChild(new CHTML_hidden(name, value));
  1341. }
  1342. // <legend> tag.
  1343. CHTML_legend::CHTML_legend(const string& legend)
  1344.     : CParent("legend", legend)
  1345. {
  1346.     return;
  1347. }
  1348. CHTML_legend::CHTML_legend(CHTMLNode* legend)
  1349.     : CParent("legend", legend)
  1350. {
  1351.     return;
  1352. }
  1353. CHTML_legend::~CHTML_legend(void)
  1354. {
  1355.     return;
  1356. }
  1357. // <fieldset> tag.
  1358. CHTML_fieldset::CHTML_fieldset(void)
  1359.     : CParent("fieldset")
  1360. {
  1361.     return;
  1362. }
  1363. CHTML_fieldset::CHTML_fieldset(const string& legend)
  1364.     : CParent("fieldset", new CHTML_legend(legend))
  1365. {
  1366.     return;
  1367. }
  1368. CHTML_fieldset::CHTML_fieldset(CHTML_legend* legend)
  1369.     : CParent("fieldset", legend)
  1370. {
  1371.     return;
  1372. }
  1373. CHTML_fieldset::~CHTML_fieldset(void)
  1374. {
  1375.     return;
  1376. }
  1377. // <label> tag.
  1378. CHTML_label::CHTML_label(const string& text)
  1379.     : CParent("label", text)
  1380. {
  1381.     return;
  1382. }
  1383. CHTML_label::CHTML_label(const string& text, const string& idRef)
  1384.     : CParent("label", text)
  1385. {
  1386.     SetFor(idRef);
  1387. }
  1388. CHTML_label::~CHTML_label(void)
  1389. {
  1390.     return;
  1391. }
  1392. void CHTML_label::SetFor(const string& idRef)
  1393. {
  1394.     SetAttribute("for", idRef);
  1395. }
  1396. // <textarea> tag.
  1397. CHTML_textarea::CHTML_textarea(const string& name, int cols, int rows)
  1398.     : CParent("textarea")
  1399. {
  1400.     SetNameAttribute(name);
  1401.     SetAttribute("cols", cols);
  1402.     SetAttribute("rows", rows);
  1403. }
  1404. CHTML_textarea::CHTML_textarea(const string& name, int cols, int rows,
  1405.                                const string& value)
  1406.     : CParent("textarea", value)
  1407. {
  1408.     SetNameAttribute(name);
  1409.     SetAttribute("cols", cols);
  1410.     SetAttribute("rows", rows);
  1411. }
  1412. CHTML_textarea::~CHTML_textarea(void)
  1413. {
  1414.     return;
  1415. }
  1416. // <input> tag.
  1417. CHTML_input::CHTML_input(const char* type, const string& name)
  1418.     : CParent("input")
  1419. {
  1420.     SetAttribute("type", type);
  1421.     SetNameAttribute(name);
  1422. }
  1423. CHTML_input::~CHTML_input(void)
  1424. {
  1425.     return;
  1426. }
  1427. // <checkbox> tag.
  1428. const char CHTML_checkbox::sm_InputType[] = "checkbox";
  1429. CHTML_checkbox::CHTML_checkbox(const string& name)
  1430.     : CParent(sm_InputType, name)
  1431. {
  1432.     return;
  1433. }
  1434. CHTML_checkbox::CHTML_checkbox(const string& name, const string& value)
  1435.     : CParent(sm_InputType, name)
  1436. {
  1437.     SetOptionalAttribute("value", value);
  1438. }
  1439. CHTML_checkbox::CHTML_checkbox(const string& name, bool checked,
  1440.                                const string& description)
  1441.     : CParent(sm_InputType, name)
  1442. {
  1443.     SetOptionalAttribute("checked", checked);
  1444.     // Add the description at the end
  1445.     AppendPlainText(description);
  1446. }
  1447. CHTML_checkbox::CHTML_checkbox(const string& name, const string& value,
  1448.                                bool checked, const string& description)
  1449.     : CParent(sm_InputType, name)
  1450. {
  1451.     SetOptionalAttribute("value", value);
  1452.     SetOptionalAttribute("checked", checked);
  1453.     // Add the description at the end
  1454.     AppendPlainText(description);  
  1455. }
  1456. CHTML_checkbox::~CHTML_checkbox(void)
  1457. {
  1458.     return;
  1459. }
  1460. // <image> tag.
  1461. const char CHTML_image::sm_InputType[] = "image";
  1462. CHTML_image::CHTML_image(const string& name, const string& src,
  1463.                          const string& alt)
  1464.     : CParent(sm_InputType, name)
  1465. {
  1466.     SetAttribute("src", src);
  1467.     SetOptionalAttribute("alt", alt);
  1468. }
  1469. CHTML_image::CHTML_image(const string& name, const string& src, int border,
  1470.                          const string& alt)
  1471.     : CParent(sm_InputType, name)
  1472. {
  1473.     SetAttribute("src", src);
  1474.     SetAttribute("border", border);
  1475.     SetOptionalAttribute("alt", alt);
  1476. }
  1477. CHTML_image::~CHTML_image(void)
  1478. {
  1479.     return;
  1480. }
  1481. // <radio> tag.
  1482. const char CHTML_radio::sm_InputType[] = "radio";
  1483. CHTML_radio::CHTML_radio(const string& name, const string& value)
  1484.     : CParent(sm_InputType, name)
  1485. {
  1486.     SetAttribute("value", value);
  1487. }
  1488. CHTML_radio::CHTML_radio(const string& name, const string& value,
  1489.                          bool checked, const string& description)
  1490.     : CParent(sm_InputType, name)
  1491. {
  1492.     SetAttribute("value", value);
  1493.     SetOptionalAttribute("checked", checked);
  1494.     AppendPlainText(description);  // adds the description at the end
  1495. }
  1496. CHTML_radio::~CHTML_radio(void)
  1497. {
  1498.     return;
  1499. }
  1500. // <hidden> tag.
  1501. const char CHTML_hidden::sm_InputType[] = "hidden";
  1502. CHTML_hidden::CHTML_hidden(const string& name, const string& value)
  1503.     : CParent(sm_InputType, name)
  1504. {
  1505.     SetAttribute("value", value);
  1506. }
  1507. CHTML_hidden::CHTML_hidden(const string& name, int value)
  1508.     : CParent(sm_InputType, name)
  1509. {
  1510.     SetAttribute("value", value);
  1511. }
  1512. CHTML_hidden::~CHTML_hidden(void)
  1513. {
  1514.     return;
  1515. }
  1516. // <submit> tag.
  1517. const char CHTML_submit::sm_InputType[] = "submit";
  1518. CHTML_submit::CHTML_submit(const string& name)
  1519.     : CParent(sm_InputType, NcbiEmptyString)
  1520. {
  1521.     SetOptionalAttribute("value", name);
  1522. }
  1523. CHTML_submit::CHTML_submit(const string& name, const string& label)
  1524.     : CParent(sm_InputType, name)
  1525. {
  1526.     SetOptionalAttribute("value", label);
  1527. }
  1528. CHTML_submit::~CHTML_submit(void)
  1529. {
  1530.     return;
  1531. }
  1532. // <reset> tag.
  1533. const char CHTML_reset::sm_InputType[] = "reset";
  1534. CHTML_reset::CHTML_reset(const string& label)
  1535.     : CParent(sm_InputType, NcbiEmptyString)
  1536. {
  1537.     SetOptionalAttribute("value", label);
  1538. }
  1539. CHTML_reset::~CHTML_reset(void)
  1540. {
  1541.     return;
  1542. }
  1543. // button tag
  1544. /*
  1545.   commented out because it's not supported in most browsers
  1546.   CHTML_button::CHTML_button(const string& text, EButtonType type)
  1547.   : CParent("button", text)
  1548.   {
  1549.   SetType(type);
  1550.   }
  1551.   CHTML_button::CHTML_button(CNCBINode* contents, EButtonType type)
  1552.   : CParent("button", contents)
  1553.   {
  1554.   SetType(type);
  1555.   }
  1556.   CHTML_button::CHTML_button(const string& text, const string& name,
  1557.   const string& value)
  1558.   : CParent("button", text)
  1559.   {
  1560.   SetSubmit(name, value);
  1561.   }
  1562.   CHTML_button::CHTML_button(CNCBINode* contents, const string& name,
  1563.   const string& value)
  1564.   : CParent("button", contents)
  1565.   {
  1566.   SetSubmit(name, value);
  1567.   }
  1568.   CHTML_button* CHTML_button::SetType(EButtonType type)
  1569.   {
  1570.   switch ( type ) {
  1571.   case eSubmit:
  1572.   SetAttribute("type", "submit");
  1573.   break;
  1574.   case eReset:
  1575.   SetAttribute("type", "reset");
  1576.   break;
  1577.   case eButton:
  1578.   SetAttribute("type", "button");
  1579.   break;
  1580.   }
  1581.   return this;
  1582.   }
  1583.   CHTML_button* CHTML_button::SetSubmit(const string& name,
  1584.   const string& value)
  1585.   {
  1586.   SetNameAttribute(name);
  1587.   SetOptionalAttribute("value", value);
  1588.   return this;
  1589.   }
  1590.   CHTML_button::~CHTML_button(void)
  1591.   {
  1592.   }
  1593. */
  1594. // <text> tag.
  1595. const char CHTML_text::sm_InputType[] = "text";
  1596. CHTML_text::CHTML_text(const string& name, const string& value)
  1597.     : CParent(sm_InputType, name)
  1598. {
  1599.     SetOptionalAttribute("value", value);
  1600. }
  1601. CHTML_text::CHTML_text(const string& name, int size, const string& value)
  1602.     : CParent(sm_InputType, name)
  1603. {
  1604.     SetSize(size);
  1605.     SetOptionalAttribute("value", value);
  1606. }
  1607. CHTML_text::CHTML_text(const string& name, int size, int maxlength,
  1608.                        const string& value)
  1609.     : CParent(sm_InputType, name)
  1610. {
  1611.     SetSize(size);
  1612.     SetAttribute("maxlength", maxlength);
  1613.     SetOptionalAttribute("value", value);
  1614. }
  1615. CHTML_text::~CHTML_text(void)
  1616. {
  1617.     return;
  1618. }
  1619. // <file> tag.
  1620. const char CHTML_file::sm_InputType[] = "file";
  1621. CHTML_file::CHTML_file(const string& name, const string& value)
  1622.     : CParent(sm_InputType, name)
  1623. {
  1624.     SetOptionalAttribute("value", value);
  1625. }
  1626. CHTML_file::~CHTML_file(void)
  1627. {
  1628.     return;
  1629. }
  1630. // <select> tag.
  1631. const char CHTML_select::sm_TagName[] = "select";
  1632. CHTML_select::~CHTML_select(void)
  1633. {
  1634.     return;
  1635. }
  1636. CHTML_select* CHTML_select::SetMultiple(void)
  1637. {
  1638.     SetAttribute("multiple");
  1639.     return this;
  1640. }
  1641. // <option> tag.
  1642. const char CHTML_option::sm_TagName[] = "option";
  1643. CHTML_option::~CHTML_option(void)
  1644. {
  1645.     return;
  1646. }
  1647. CHTML_option* CHTML_option::SetValue(const string& value)
  1648. {
  1649.     SetAttribute("value", value);
  1650.     return this;
  1651. }
  1652. CHTML_option* CHTML_option::SetSelected(void)
  1653. {
  1654.     SetAttribute("selected");
  1655.     return this;
  1656. }
  1657. // <a> tag.
  1658. const char CHTML_a::sm_TagName[] = "a";
  1659. CHTML_a::~CHTML_a(void)
  1660. {
  1661.     return;
  1662. }
  1663. CHTML_a* CHTML_a::SetHref(const string& href)
  1664. {
  1665.     SetAttribute("href", href);
  1666.     return this;
  1667. }
  1668. // <br> tag.
  1669. const char CHTML_br::sm_TagName[] = "br";
  1670. CHTML_br::CHTML_br(int count)
  1671.     : CParent(sm_TagName)
  1672. {
  1673.     for ( int i = 1; i < count; ++i ) {
  1674.         AppendChild(new CHTML_br());
  1675.     }
  1676. }
  1677. CHTML_br::~CHTML_br(void)
  1678. {
  1679.     return;
  1680. }
  1681. CNcbiOstream& CHTML_br::PrintBegin(CNcbiOstream& out, TMode mode)
  1682. {
  1683.     if ( mode == ePlainText ) {
  1684.         out << CHTMLHelper::GetNL();
  1685.         CHECK_STREAM_WRITE(out);
  1686.     }
  1687.     else {
  1688.         CParent::PrintBegin(out, mode);
  1689.     }
  1690.     return out;
  1691. }
  1692. // <img> tag.
  1693. CHTML_img::CHTML_img(const string& url, const string& alt)
  1694.     : CParent("img")
  1695. {
  1696.     SetAttribute("src", url);
  1697.     SetOptionalAttribute("alt", alt);
  1698. }
  1699. CHTML_img::CHTML_img(const string& url, int width, int height,
  1700.                      const string& alt)
  1701.     : CParent("img")
  1702. {
  1703.     SetAttribute("src", url);
  1704.     SetOptionalAttribute("alt", alt);
  1705.     SetWidth(width);
  1706.     SetHeight(height);
  1707. }
  1708. CHTML_img::~CHTML_img(void)
  1709. {
  1710.     return;
  1711. }
  1712. // <dl> tag.
  1713. const char CHTML_dl::sm_TagName[] = "dl";
  1714. CHTML_dl::~CHTML_dl(void)
  1715. {
  1716.     return;
  1717. }
  1718. CHTML_dl* CHTML_dl::AppendTerm(const string& term, const string& definition)
  1719. {
  1720.     AppendChild(new CHTML_dt(term));
  1721.     if ( !definition.empty() )
  1722.         AppendChild(new CHTML_dd(definition));
  1723.     return this;
  1724. }
  1725. CHTML_dl* CHTML_dl::AppendTerm(const string& term, CNCBINode* definition)
  1726. {
  1727.     AppendChild(new CHTML_dt(term));
  1728.     if ( definition )
  1729.         AppendChild(new CHTML_dd(definition));
  1730.     return this;
  1731. }
  1732. CHTML_dl* CHTML_dl::AppendTerm(CNCBINode* term, const string& definition)
  1733. {
  1734.     AppendChild(new CHTML_dt(term));
  1735.     if ( !definition.empty() ) {
  1736.         AppendChild(new CHTML_dd(definition));
  1737.     }
  1738.     return this;
  1739. }
  1740. CHTML_dl* CHTML_dl::AppendTerm(CNCBINode* term, CNCBINode* definition)
  1741. {
  1742.     AppendChild(new CHTML_dt(term));
  1743.     if ( definition )
  1744.         AppendChild(new CHTML_dd(definition));
  1745.     return this;
  1746. }
  1747. CHTML_dl* CHTML_dl::SetCompact(void)
  1748. {
  1749.     SetAttribute("compact");
  1750.     return this;
  1751. }
  1752. // <ol> tag.
  1753. const char CHTML_ol::sm_TagName[] = "ol";
  1754. CHTML_ol::~CHTML_ol(void)
  1755. {
  1756. }
  1757. CHTML_ol* CHTML_ol::SetStart(int start)
  1758. {
  1759.     SetAttribute("start", start);
  1760.     return this;
  1761. }
  1762. // <ul> tag.
  1763. const char CHTML_ul::sm_TagName[] = "ul";
  1764. CHTML_ul::~CHTML_ul(void)
  1765. {
  1766.     return;
  1767. }
  1768. // <dir> tag.
  1769. const char CHTML_dir::sm_TagName[] = "dir";
  1770. CHTML_dir::~CHTML_dir(void)
  1771. {
  1772.     return;
  1773. }
  1774. // <menu> tag.
  1775. const char CHTML_menu::sm_TagName[] = "menu";
  1776. CHTML_menu::~CHTML_menu(void)
  1777. {
  1778.     return;
  1779. }
  1780. const char CHTML_font::sm_TagName[] = "font";
  1781. CHTML_font::~CHTML_font(void)
  1782. {
  1783.     return;
  1784. }
  1785. // <font> tag.
  1786. CHTML_font* CHTML_font::SetTypeFace(const string& typeface)
  1787. {
  1788.     SetAttribute("face", typeface);
  1789.     return this;
  1790. }
  1791. CHTML_font* CHTML_font::SetRelativeSize(int size)
  1792. {
  1793.     if ( size != 0 )
  1794.         SetAttribute("size", NStr::IntToString(size, true));
  1795.     return this;
  1796. }
  1797. const char CHTML_basefont::sm_TagName[] = "basefont";
  1798. CHTML_basefont::~CHTML_basefont(void)
  1799. {
  1800.     return;
  1801. }
  1802. CHTML_basefont* CHTML_basefont::SetTypeFace(const string& typeface)
  1803. {
  1804.     SetAttribute("typeface", typeface);
  1805.     return this;
  1806. }
  1807. CHTML_color::~CHTML_color(void)
  1808. {
  1809.     return;
  1810. }
  1811. // <hr> tag.
  1812. const char CHTML_hr::sm_TagName[] = "hr";
  1813. CHTML_hr::~CHTML_hr(void)
  1814. {
  1815.     return;
  1816. }
  1817. CHTML_hr* CHTML_hr::SetNoShade(void)
  1818. {
  1819.     SetAttribute("noshade");
  1820.     return this;
  1821. }
  1822. CNcbiOstream& CHTML_hr::PrintBegin(CNcbiOstream& out, TMode mode)
  1823. {
  1824.     if ( mode == ePlainText ) {
  1825.         out << CHTMLHelper::GetNL() << CHTMLHelper::GetNL();
  1826.         CHECK_STREAM_WRITE(out);
  1827.     }
  1828.     else {
  1829.         CParent::PrintBegin(out, mode);
  1830.     }
  1831.     return out;
  1832. }
  1833. // <meta> tag.
  1834. const char CHTML_meta::sm_TagName[] = "meta";
  1835. CHTML_meta::CHTML_meta(EType mtype, const string& var, const string& content)
  1836.     : CParent(sm_TagName)
  1837. {
  1838.     SetAttribute(( mtype == eName ) ? "name" : "http-equiv", var);
  1839.     SetAttribute("content", content);
  1840. }
  1841. CHTML_meta::~CHTML_meta(void)
  1842. {
  1843.     return;
  1844. }
  1845. // <script> tag.
  1846. const char CHTML_script::sm_TagName[] = "script";
  1847. CHTML_script::CHTML_script(const string& stype)
  1848.     : CParent(sm_TagName)
  1849. {
  1850.     SetAttribute("type", stype);
  1851. }
  1852. CHTML_script::CHTML_script(const string& stype, const string& url)
  1853.     : CParent(sm_TagName)
  1854. {
  1855.     SetAttribute("type", stype);
  1856.     SetAttribute("src", url);
  1857. }
  1858. CHTML_script::~CHTML_script(void)
  1859. {
  1860.     return;
  1861. }
  1862. CHTML_script* CHTML_script::AppendScript(const string& script)
  1863. {
  1864.     AppendChild(new CHTMLPlainText("n<!--n" + script + "-->n", true));
  1865.     return this;
  1866. }
  1867. // Other tags.
  1868. #define DEFINE_HTML_ELEMENT(Tag) 
  1869. CHTML_NAME(Tag)::~CHTML_NAME(Tag)(void) 
  1870. const char CHTML_NAME(Tag)::sm_TagName[] = #Tag
  1871. DEFINE_HTML_ELEMENT(head);
  1872. DEFINE_HTML_ELEMENT(body);
  1873. DEFINE_HTML_ELEMENT(base);
  1874. DEFINE_HTML_ELEMENT(isindex);
  1875. DEFINE_HTML_ELEMENT(link);
  1876. DEFINE_HTML_ELEMENT(noscript);
  1877. DEFINE_HTML_ELEMENT(object);
  1878. DEFINE_HTML_ELEMENT(style);
  1879. DEFINE_HTML_ELEMENT(title);
  1880. DEFINE_HTML_ELEMENT(address);
  1881. DEFINE_HTML_ELEMENT(blockquote);
  1882. DEFINE_HTML_ELEMENT(center);
  1883. DEFINE_HTML_ELEMENT(div);
  1884. DEFINE_HTML_ELEMENT(h1);
  1885. DEFINE_HTML_ELEMENT(h2);
  1886. DEFINE_HTML_ELEMENT(h3);
  1887. DEFINE_HTML_ELEMENT(h4);
  1888. DEFINE_HTML_ELEMENT(h5);
  1889. DEFINE_HTML_ELEMENT(h6);
  1890. DEFINE_HTML_ELEMENT(p);
  1891. DEFINE_HTML_ELEMENT(pnop);
  1892. DEFINE_HTML_ELEMENT(pre);
  1893. DEFINE_HTML_ELEMENT(dt);
  1894. DEFINE_HTML_ELEMENT(dd);
  1895. DEFINE_HTML_ELEMENT(li);
  1896. DEFINE_HTML_ELEMENT(caption);
  1897. DEFINE_HTML_ELEMENT(col);
  1898. DEFINE_HTML_ELEMENT(colgroup);
  1899. DEFINE_HTML_ELEMENT(thead);
  1900. DEFINE_HTML_ELEMENT(tbody);
  1901. DEFINE_HTML_ELEMENT(tfoot);
  1902. DEFINE_HTML_ELEMENT(th);
  1903. DEFINE_HTML_ELEMENT(td);
  1904. DEFINE_HTML_ELEMENT(applet);
  1905. DEFINE_HTML_ELEMENT(param);
  1906. DEFINE_HTML_ELEMENT(cite);
  1907. DEFINE_HTML_ELEMENT(code);
  1908. DEFINE_HTML_ELEMENT(dfn);
  1909. DEFINE_HTML_ELEMENT(em);
  1910. DEFINE_HTML_ELEMENT(kbd);
  1911. DEFINE_HTML_ELEMENT(samp);
  1912. DEFINE_HTML_ELEMENT(strike);
  1913. DEFINE_HTML_ELEMENT(strong);
  1914. DEFINE_HTML_ELEMENT(var);
  1915. DEFINE_HTML_ELEMENT(b);
  1916. DEFINE_HTML_ELEMENT(big);
  1917. DEFINE_HTML_ELEMENT(i);
  1918. DEFINE_HTML_ELEMENT(s);
  1919. DEFINE_HTML_ELEMENT(small);
  1920. DEFINE_HTML_ELEMENT(sub);
  1921. DEFINE_HTML_ELEMENT(sup);
  1922. DEFINE_HTML_ELEMENT(tt);
  1923. DEFINE_HTML_ELEMENT(u);
  1924. DEFINE_HTML_ELEMENT(blink);
  1925. DEFINE_HTML_ELEMENT(span);
  1926. DEFINE_HTML_ELEMENT(map);
  1927. DEFINE_HTML_ELEMENT(area);
  1928. END_NCBI_SCOPE
  1929. /*
  1930.  * ===========================================================================
  1931.  * $Log: html.cpp,v $
  1932.  * Revision 1000.4  2004/06/01 19:15:26  gouriano
  1933.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.103
  1934.  *
  1935.  * Revision 1.103  2004/05/17 20:59:50  gorelenk
  1936.  * Added include of PCH ncbi_pch.hpp
  1937.  *
  1938.  * Revision 1.102  2004/04/05 16:19:57  ivanov
  1939.  * Added support for Sergey Kurdin's popup menu with configurations
  1940.  *
  1941.  * Revision 1.101  2004/03/10 20:11:35  ivanov
  1942.  * Changed message text
  1943.  *
  1944.  * Revision 1.100  2004/02/04 17:20:10  ivanov
  1945.  * Added s_GenerateNodeInternalName() function.
  1946.  * Use it insteed dummy names in the meta-tags node classes.
  1947.  *
  1948.  * Revision 1.99  2004/02/04 12:43:47  ivanov
  1949.  * Fixed CHTMLText::SetText() -- do not use m_Name for store HTML code.
  1950.  * Bind internal name for objects of the CHTMLSpecialChar class.
  1951.  *
  1952.  * Revision 1.98  2004/02/03 19:45:13  ivanov
  1953.  * Binded dummy names for the unnamed nodes
  1954.  *
  1955.  * Revision 1.97  2004/02/02 15:48:16  ivanov
  1956.  * CHTMLText::x_PrintBegin: using CHTMLHelper::StripHTML insteed StripTags
  1957.  *
  1958.  * Revision 1.96  2004/02/02 14:30:24  ivanov
  1959.  * CHTMLText::PrintBegin - added repeat tag support. Some cosmetic changes.
  1960.  *
  1961.  * Revision 1.95  2004/01/30 14:03:50  lavr
  1962.  * Print last errno along with "write failure" message
  1963.  *
  1964.  * Revision 1.94  2004/01/26 16:26:47  ivanov
  1965.  * Added NOWRAP attribute support
  1966.  *
  1967.  * Revision 1.93  2003/12/18 20:15:42  golikov
  1968.  * use HideMenu() call, CHTMLComment::PrintBegin fix
  1969.  *
  1970.  * Revision 1.92  2003/12/16 19:08:49  ivanov
  1971.  * CHTML_font::SetTypeFace: replaced attribute name "typeface" to "face".
  1972.  *
  1973.  * Revision 1.91  2003/12/10 19:15:14  ivanov
  1974.  * Move adding a string "return false;" to menues JS code call from ShowMenu()
  1975.  * to AttachPopupMenu()
  1976.  *
  1977.  * Revision 1.90  2003/12/02 14:25:58  ivanov
  1978.  * Removed obsolete functions GetCodeBodyTag[Handler|Action]().
  1979.  * AttachPopupMenu(): use event parameter for eKurdin menu also.
  1980.  *
  1981.  * Revision 1.89  2003/11/03 17:03:08  ivanov
  1982.  * Some formal code rearrangement. Move log to end.
  1983.  *
  1984.  * Revision 1.88  2003/11/03 14:49:16  ivanov
  1985.  * Always check if the write was successful, throw otherwise
  1986.  *
  1987.  * Revision 1.87  2003/10/01 15:57:13  ivanov
  1988.  * Added support for Sergey Kurdin's side menu
  1989.  *
  1990.  * Revision 1.86  2003/07/08 17:13:53  gouriano
  1991.  * changed thrown exceptions to CException-derived ones
  1992.  *
  1993.  * Revision 1.85  2003/05/30 18:39:33  lavr
  1994.  * Replace endl's with explicit 'n' to avoid premature flushing
  1995.  *
  1996.  * Revision 1.84  2003/05/15 12:33:54  ucko
  1997.  * s_Find: drop assertion, and just return NPOS at/past the end of s.
  1998.  *
  1999.  * Revision 1.83  2003/05/14 21:55:40  ucko
  2000.  * CHTMLText::PrintBegin: Use strstr() instead of string::find() when
  2001.  * looking for tags to replace, as the latter is much slower on some
  2002.  * systems.
  2003.  *
  2004.  * Revision 1.82  2003/04/22 15:04:05  ivanov
  2005.  * Removed HTMLEncode() for tags attributes in CHTMLOpenElement::PrintBegin()
  2006.  *
  2007.  * Revision 1.81  2003/03/11 15:28:57  kuznets
  2008.  * iterate -> ITERATE
  2009.  *
  2010.  * Revision 1.80  2003/02/14 16:19:32  ucko
  2011.  * Indent the children of CHTMLListElement in plain-text mode.
  2012.  * Avoid redundant newlines in CHTMLBlockElement::PrintEnd.
  2013.  *
  2014.  * Revision 1.79  2002/12/24 14:56:03  ivanov
  2015.  * Fix for R1.76:  HTML classes for tags <h1-6>, <p>, <div>. <pre>, <blockquote>
  2016.  * now inherits from CHTMLBlockElement (not CHTMElement as before)
  2017.  *
  2018.  * Revision 1.78  2002/12/20 19:20:19  ivanov
  2019.  * Added SPAN tag support
  2020.  *
  2021.  * Revision 1.77  2002/12/18 19:46:18  ivanov
  2022.  * Added line break after elements of the class CHTMLElement in plain text mode
  2023.  *
  2024.  * Revision 1.76  2002/12/09 22:11:33  ivanov
  2025.  * Added support for Sergey Kurdin's popup menu.
  2026.  * Added CHTMLNode::AttachPopupMenu().
  2027.  *
  2028.  * Revision 1.75  2002/09/25 01:24:56  dicuccio
  2029.  * Added CHTMLHelper::StripTags() - strips HTML comments and tags from any
  2030.  * string.  Implemented CHTMLText::PrintBegin() for mode = ePlainText
  2031.  *
  2032.  * Revision 1.74  2002/02/13 20:16:44  ivanov
  2033.  * Added support of dynamic popup menus. Changed EnablePopupMenu().
  2034.  *
  2035.  * Revision 1.73  2002/01/30 19:54:51  ivanov
  2036.  * CHTML_table::PrintBegin - determination length of prior table's separator
  2037.  * as length of first none empty table's row. Added new line at printing
  2038.  * table in plain text mode.
  2039.  *
  2040.  * Revision 1.72  2002/01/29 20:01:46  ivanov
  2041.  * (plain text) CHTML_table:: set def. medium sep. to " " instead of "t"
  2042.  *
  2043.  * Revision 1.71  2002/01/29 19:25:55  ivanov
  2044.  * Typo fixed
  2045.  *
  2046.  * Revision 1.70  2002/01/29 19:20:47  ivanov
  2047.  * (plain text) CHTML_table:: set def. medium sep. to "" instead of "t".
  2048.  * Restored functionality of CHTML_tr::PrintEnd().
  2049.  * Fixed CHTML_tr::GetTextLength() -- ".put('')" instead of "<< ''".
  2050.  *
  2051.  * Revision 1.69  2002/01/28 17:54:50  vakatov
  2052.  * (plain text) CHTML_table:: set def. medium sep. to "t" instead of "t|t"
  2053.  *
  2054.  * Revision 1.68  2002/01/17 23:40:01  ivanov
  2055.  * Added means to print HTML tables in plain text mode
  2056.  *
  2057.  * Revision 1.67  2001/08/14 16:51:05  ivanov
  2058.  * Change means for init JavaScript popup menu & add it to HTML document.
  2059.  * Remove early redefined classes for tags HEAD and BODY.
  2060.  *
  2061.  * Revision 1.66  2001/07/16 13:54:09  ivanov
  2062.  * Added support JavaScript popups menu (jsmenu.[ch]pp)
  2063.  *
  2064.  * Revision 1.65  2001/06/08 19:00:22  ivanov
  2065.  * Added base classes: CHTMLDualNode, CHTMLSpecialChar
  2066.  *     (and based on it: CHTML_nbsp, _gt, _lt, _quot, _amp, _copy, _reg)
  2067.  * Added realization for tags <meta> (CHTML_meta) and <script> (CHTML_script)
  2068.  * Changed base class for tags LINK, PARAM, ISINDEX -> CHTMLOpenElement
  2069.  * Added tags: OBJECT, NOSCRIPT
  2070.  * Added attribute "alt" for CHTML_img
  2071.  * Added CHTMLComment::Print() for disable print html-comments in plaintext mode
  2072.  *
  2073.  * Revision 1.64  2001/06/05 15:35:48  ivanov
  2074.  * Added attribute "alt" to CHTML_image
  2075.  *
  2076.  * Revision 1.63  2001/05/17 15:05:42  lavr
  2077.  * Typos corrected
  2078.  *
  2079.  * Revision 1.62  2000/10/13 19:55:15  vasilche
  2080.  * Fixed error with static html node object.
  2081.  *
  2082.  * Revision 1.61  2000/09/27 14:11:17  vasilche
  2083.  * Newline 'n' will not be generated after tags LABEL, A, FONT, CITE, CODE, EM,
  2084.  * KBD, STRIKE STRONG, VAR, B, BIG, I, S, SMALL, SUB, SUP, TT, U and BLINK.
  2085.  *
  2086.  * Revision 1.60  2000/08/15 19:40:48  vasilche
  2087.  * Added CHTML_label::SetFor() method for setting HTML attribute FOR.
  2088.  *
  2089.  * Revision 1.59  2000/08/01 20:05:11  golikov
  2090.  * Removed _TRACE
  2091.  *
  2092.  * Revision 1.58  2000/07/25 15:27:38  vasilche
  2093.  * Added newline symbols before table and after each table row in text mode.
  2094.  *
  2095.  * Revision 1.57  2000/07/20 20:37:19  vasilche
  2096.  * Fixed null pointer dereference.
  2097.  *
  2098.  * Revision 1.56  2000/07/18 19:08:55  vasilche
  2099.  * Fixed uninitialized members.
  2100.  * Fixed NextCell to advance to next cell.
  2101.  *
  2102.  * Revision 1.55  2000/07/18 17:21:39  vasilche
  2103.  * Added possibility to force output of empty attribute value.
  2104.  * Added caching to CHTML_table, now large tables work much faster.
  2105.  * Changed algorithm of emitting EOL symbols in html output.
  2106.  *
  2107.  * Revision 1.54  2000/07/12 16:37:42  vasilche
  2108.  * Added new HTML4 tags: LABEL, BUTTON, FIELDSET, LEGEND.
  2109.  * Added methods for setting common attributes: STYLE, ID, TITLE, ACCESSKEY.
  2110.  *
  2111.  * Revision 1.53  2000/03/07 15:26:12  vasilche
  2112.  * Removed second definition of CRef.
  2113.  *
  2114.  * Revision 1.52  1999/12/28 21:01:08  vasilche
  2115.  * Fixed conflict on MS VC between bool and const string& arguments by
  2116.  * adding const char* argument.
  2117.  *
  2118.  * Revision 1.51  1999/12/28 18:55:45  vasilche
  2119.  * Reduced size of compiled object files:
  2120.  * 1. avoid inline or implicit virtual methods (especially destructors).
  2121.  * 2. avoid std::string's methods usage in inline methods.
  2122.  * 3. avoid string literals ("xxx") in inline methods.
  2123.  *
  2124.  * Revision 1.50  1999/10/28 13:40:35  vasilche
  2125.  * Added reference counters to CNCBINode.
  2126.  *
  2127.  * Revision 1.49  1999/08/20 16:14:54  golikov
  2128.  * 'non-<TR> tag' bug fixed
  2129.  *
  2130.  * Revision 1.48  1999/08/09 16:20:07  golikov
  2131.  * Table output in plaintext fixed
  2132.  *
  2133.  * Revision 1.47  1999/07/08 18:05:15  vakatov
  2134.  * Fixed compilation warnings
  2135.  *
  2136.  * Revision 1.46  1999/06/18 20:42:50  vakatov
  2137.  * Fixed tiny compilation warnings
  2138.  *
  2139.  * Revision 1.45  1999/06/11 20:30:29  vasilche
  2140.  * We should catch exception by reference, because catching by value
  2141.  * doesn't preserve comment string.
  2142.  *
  2143.  * Revision 1.44  1999/06/09 20:57:58  golikov
  2144.  * RowSpan fixed by Vasilche
  2145.  *
  2146.  * Revision 1.43  1999/06/07 15:21:05  vasilche
  2147.  * Fixed some warnings.
  2148.  *
  2149.  * Revision 1.42  1999/05/28 18:03:51  vakatov
  2150.  * CHTMLNode::  added attribute "CLASS"
  2151.  *
  2152.  * Revision 1.41  1999/05/27 21:43:02  vakatov
  2153.  * Get rid of some minor compiler warnings
  2154.  *
  2155.  * Revision 1.40  1999/05/24 13:57:55  pubmed
  2156.  * Save Command; MEDLINE, FASTA format changes
  2157.  *
  2158.  * Revision 1.39  1999/05/20 16:52:31  pubmed
  2159.  * SaveAsText action for query; minor changes in filters,labels, tabletemplate
  2160.  *
  2161.  * Revision 1.38  1999/05/17 20:09:58  vasilche
  2162.  * Removed generation of implicit table cells.
  2163.  *
  2164.  * Revision 1.37  1999/04/16 17:45:35  vakatov
  2165.  * [MSVC++] Replace the <windef.h>'s min/max macros by the hand-made templates.
  2166.  *
  2167.  * Revision 1.36  1999/04/15 22:09:26  vakatov
  2168.  * "max" --> "NcbiMax"
  2169.  *
  2170.  * Revision 1.35  1999/04/15 19:56:24  vasilche
  2171.  * More warnings fixed
  2172.  *
  2173.  * Revision 1.34  1999/04/15 19:48:23  vasilche
  2174.  * Fixed several warnings detected by GCC
  2175.  *
  2176.  * Revision 1.33  1999/04/08 19:00:31  vasilche
  2177.  * Added current cell pointer to CHTML_table
  2178.  *
  2179.  * Revision 1.32  1999/03/26 22:00:01  sandomir
  2180.  * checked option in Radio button fixed; minor fixes in Selection
  2181.  *
  2182.  * Revision 1.31  1999/03/01 21:03:09  vasilche
  2183.  * Added CHTML_file input element.
  2184.  * Changed CHTML_form constructors.
  2185.  *
  2186.  * Revision 1.30  1999/02/26 21:03:33  vasilche
  2187.  * CAsnWriteNode made simple node. Use CHTML_pre explicitly.
  2188.  * Fixed bug in CHTML_table::Row.
  2189.  * Added CHTML_table::HeaderCell & DataCell methods.
  2190.  *
  2191.  * Revision 1.29  1999/02/02 17:57:49  vasilche
  2192.  * Added CHTML_table::Row(int row).
  2193.  * Linkbar now have equal image spacing.
  2194.  *
  2195.  * Revision 1.28  1999/01/28 21:58:08  vasilche
  2196.  * QueryBox now inherits from CHTML_table (not CHTML_form as before).
  2197.  * Use 'new CHTML_form("url", queryBox)' as replacement of old QueryBox.
  2198.  *
  2199.  * Revision 1.27  1999/01/28 16:59:01  vasilche
  2200.  * Added several constructors for CHTML_hr.
  2201.  * Added CHTMLNode::SetSize method.
  2202.  *
  2203.  * Revision 1.26  1999/01/25 19:34:18  vasilche
  2204.  * String arguments which are added as HTML text now treated as plain text.
  2205.  *
  2206.  * Revision 1.25  1999/01/21 21:12:59  vasilche
  2207.  * Added/used descriptions for HTML submit/select/text.
  2208.  * Fixed some bugs in paging.
  2209.  *
  2210.  * Revision 1.24  1999/01/21 16:18:05  sandomir
  2211.  * minor changes due to NStr namespace to contain string utility functions
  2212.  *
  2213.  * Revision 1.23  1999/01/14 21:25:20  vasilche
  2214.  * Changed CPageList to work via form image input elements.
  2215.  *
  2216.  * Revision 1.22  1999/01/11 22:05:52  vasilche
  2217.  * Fixed CHTML_font size.
  2218.  * Added CHTML_image input element.
  2219.  *
  2220.  * Revision 1.21  1999/01/11 15:13:35  vasilche
  2221.  * Fixed CHTML_font size.
  2222.  * CHTMLHelper extracted to separate file.
  2223.  *
  2224.  * Revision 1.20  1999/01/07 16:41:56  vasilche
  2225.  * CHTMLHelper moved to separate file.
  2226.  * TagNames of CHTML classes ara available via s_GetTagName() static
  2227.  * method.
  2228.  * Input tag types ara available via s_GetInputType() static method.
  2229.  * Initial selected database added to CQueryBox.
  2230.  * Background colors added to CPagerBax & CSmallPagerBox.
  2231.  *
  2232.  * Revision 1.19  1999/01/05 20:23:29  vasilche
  2233.  * Fixed HTMLEncode.
  2234.  *
  2235.  * Revision 1.18  1999/01/04 20:06:14  vasilche
  2236.  * Redesigned CHTML_table.
  2237.  * Added selection support to HTML forms (via hidden values).
  2238.  *
  2239.  * Revision 1.16  1998/12/28 21:48:16  vasilche
  2240.  * Made Lewis's 'tool' compilable
  2241.  *
  2242.  * Revision 1.15  1998/12/28 16:48:09  vasilche
  2243.  * Removed creation of QueryBox in CHTMLPage::CreateView()
  2244.  * CQueryBox extends from CHTML_form
  2245.  * CButtonList, CPageList, CPagerBox, CSmallPagerBox extend from CNCBINode.
  2246.  *
  2247.  * Revision 1.14  1998/12/24 16:15:41  vasilche
  2248.  * Added CHTMLComment class.
  2249.  * Added TagMappers from static functions.
  2250.  *
  2251.  * Revision 1.13  1998/12/23 21:51:44  vasilche
  2252.  * Added missing constructors to checkbox.
  2253.  *
  2254.  * Revision 1.12  1998/12/23 21:21:03  vasilche
  2255.  * Added more HTML tags (almost all).
  2256.  * Importent ones: all lists (OL, UL, DIR, MENU), fonts (FONT, BASEFONT).
  2257.  *
  2258.  * Revision 1.11  1998/12/23 14:28:10  vasilche
  2259.  * Most of closed HTML tags made via template.
  2260.  *
  2261.  * Revision 1.10  1998/12/21 22:25:03  vasilche
  2262.  * A lot of cleaning.
  2263.  *
  2264.  * Revision 1.9  1998/12/10 19:21:51  lewisg
  2265.  * correct error handling in InsertInTable
  2266.  *
  2267.  * Revision 1.8  1998/12/10 00:17:27  lewisg
  2268.  * fix index in InsertInTable
  2269.  *
  2270.  * Revision 1.7  1998/12/09 23:00:54  lewisg
  2271.  * use new cgiapp class
  2272.  *
  2273.  * Revision 1.6  1998/12/08 00:33:43  lewisg
  2274.  * cleanup
  2275.  *
  2276.  * Revision 1.5  1998/12/03 22:48:00  lewisg
  2277.  * added HTMLEncode() and CHTML_img
  2278.  *
  2279.  * Revision 1.4  1998/12/01 19:10:38  lewisg
  2280.  * uses CCgiApplication and new page factory
  2281.  *
  2282.  * Revision 1.3  1998/11/23 23:42:17  lewisg
  2283.  * *** empty log message ***
  2284.  *
  2285.  * Revision 1.2  1998/10/29 16:13:06  lewisg
  2286.  * version 2
  2287.  *
  2288.  * Revision 1.1  1998/10/06 20:36:05  lewisg
  2289.  * new html lib and test program
  2290.  *
  2291.  * ===========================================================================
  2292.  */