835c6c2001-06-17Martin Nilsson // This file is part of Roxen WebServer. // Copyright © 2000 - 2001, Roxen IS. // // RXML Help by Martin Nilsson
cface32000-01-10Martin Nilsson //
2feec42000-01-24Martin Nilsson #ifdef RXMLHELP_DEBUG
91d3c32001-03-12Martin Nilsson # define RXMLHELP_WERR(X) report_debug("RXML help: %s\n", X);
2feec42000-01-24Martin Nilsson #else # define RXMLHELP_WERR(X) #endif
a104662000-01-25Martin Nilsson // --------------------- Layout help functions --------------------
e8ae642000-03-16Martin Nilsson #define TDBG "#d9dee7"
a104662000-01-25Martin Nilsson string mktable(array table) { string ret="<table boder=\"0\" cellpadding=\"0\" border=\"0\"><tr><td bgcolor=\"#000000\">\n" "<table border=\"0\" cellspacing=\"1\" cellpadding=\"5\">\n"; foreach(table, array row)
e8ae642000-03-16Martin Nilsson  ret+="<tr valign=\"top\"><td bgcolor=\""+TDBG+"\"><font color=\"#000000\">"+ row*("</font></td><td bgcolor=\""+TDBG+"\"><font color=\"#000000\">")+"</font></td></tr>\n";
a104662000-01-25Martin Nilsson  ret+="</table></tr></td></table>"; return ret; } string available_languages(object id) {
e40bf72000-01-28Martin Nilsson  string pl;
78be972001-04-23Martin Nilsson  if(id && id->misc->pref_languages && (pl=id->misc->pref_languages->get_language()))
b09a282000-03-21Martin Nilsson  if(!has_value(roxen->list_languages(),pl)) pl="en";
e40bf72000-01-28Martin Nilsson  else pl="en";
b09a282000-03-21Martin Nilsson  mapping languages=roxen->language_low(pl)->list_languages();
b0e8f92000-03-22Martin Nilsson  return mktable( map(sort(indices(languages) & roxen->list_languages()), lambda(string code) { return ({ code, languages[code] }); } ));
a104662000-01-25Martin Nilsson } // --------------------- Help layout functions --------------------
cface32000-01-10Martin Nilsson 
5673a32000-07-23Martin Nilsson static string desc_cont(string t, mapping m, string c, string rt)
cface32000-01-10Martin Nilsson { string dt=rt; m->type=m->type||""; if(m->tag) dt=sprintf("&lt;%s/&gt;", rt); if(m->cont) dt=(m->tag?dt+" and ":"")+sprintf("&lt;%s&gt;&lt;/%s&gt;", rt, rt);
49ee2d2000-03-07Martin Nilsson  if(m->plugin) { sscanf(dt,"%*s#%s",dt); dt="plugin "+dt; }
39e0362000-08-30Martin Nilsson  if(m->ent) dt=rt; if(m->scope) dt=rt[..sizeof(rt)-2]+" ... ;"; if(m->pi) dt=rt+" ... ?&gt;";
cface32000-01-10Martin Nilsson  return sprintf("<h2>%s</h2><p>%s</p>",dt,c); }
5673a32000-07-23Martin Nilsson static string attr_cont(string t, mapping m, string c)
cface32000-01-10Martin Nilsson { string p=""; if(!m->name) m->name="(Not entered)";
ec8b312000-03-30Martin Nilsson  if(m->value) p=sprintf("<i>%s=%s</i>%s<br />", m->name, attr_vals(m->value), m->default?" ("+m->default+")":"" ); if(m->required) p+="<i>This attribute is required.</i><br />";
9a669a2000-09-19Per Hedbor  return sprintf("<p><dl><dt><b>%s</b></dt><dd>%s%s</p></dl>",m->name,p,c);
cface32000-01-10Martin Nilsson }
5673a32000-07-23Martin Nilsson static string attr_vals(string v)
cface32000-01-10Martin Nilsson {
b09a282000-03-21Martin Nilsson  if(has_value(v,"|")) return "{"+(v/"|")*", "+"}"; // FIXME Use real config url // if(v=="langcodes") return "<a href=\"/help/langcodes.pike\">language code</a>";
cface32000-01-10Martin Nilsson  return v; }
5673a32000-07-23Martin Nilsson static string noex_cont(string t, mapping m, string c) {
4a45f12001-03-13Martin Nilsson  return Parser.HTML()->add_container("ex","")-> add_quote_tag("!--","","--")->feed(c)->read();
b0e8f92000-03-22Martin Nilsson }
4acd362001-05-18Martin Nilsson static string ex_quote(string in) { return "<pre>"+replace(in, ({"<",">","&"}), ({"&lt;","&gt;","&amp;"}) )+"</pre>"; }
5673a32000-07-23Martin Nilsson static string ex_cont(string t, mapping m, string c, string rt, void|object id)
9dcf432000-01-23Martin Nilsson {
a790402000-07-29Martin Nilsson  c=Parser.HTML()->add_container("ent", lambda(string t, mapping m, string c) {
c7da172001-01-29Per Hedbor  return "&amp;"+c+";";
4a45f12001-03-13Martin Nilsson  } )-> add_quote_tag("!--","","--")->feed(c)->read();
4acd362001-05-18Martin Nilsson  string quoted = ex_quote(c);
69f7112000-05-30Martin Nilsson  if(m->type=="box")
0d1bb22000-05-30Martin Nilsson  return "<br />"+mktable( ({ ({ quoted }) }) );
69f7112000-05-30Martin Nilsson 
9dcf432000-01-23Martin Nilsson  if(!id) return "";
69f7112000-05-30Martin Nilsson 
e8ae642000-03-16Martin Nilsson  string parsed= id->conf->parse_rxml(m->type!="hr"? "<colorscope bgcolor="+TDBG+">"+c+"</colorscope>": c, id);
9dcf432000-01-23Martin Nilsson  switch(m->type) { case "hr":
0d1bb22000-05-30Martin Nilsson  return quoted+"<hr />"+parsed;
4acd362001-05-18Martin Nilsson  case "svert": return "<br />" + mktable( ({ ({ quoted }), ({ ex_quote(parsed) }) }) ); case "shor": return "<br />" + mktable( ({ ({ quoted, ex_quote(parsed) }) }) );
9dcf432000-01-23Martin Nilsson  case "vert":
0d1bb22000-05-30Martin Nilsson  return "<br />"+mktable( ({ ({ quoted }), ({ parsed }) }) );
9dcf432000-01-23Martin Nilsson  case "hor": default:
0d1bb22000-05-30Martin Nilsson  return "<br />"+mktable( ({ ({ quoted, parsed }) }) );
9dcf432000-01-23Martin Nilsson  } }
9a669a2000-09-19Per Hedbor static string list_cont( string t, mapping m, string c ) { if( m->type == "ol" ) return "<ol>"+replace( c, ({"<item>","</item>", "<item/>"}), ({"<li>","","<li>"}) )+"</ol>"; return "<ul>"+replace( c, ({"<item>","</item>", "<item/>"}), ({"<li>","","<li>"}) )+"</ul>"; } static string xtable_cont( mixed a, mixed b, string c ) { return "<table>"+c+"</table>"; } static string module_cont( mixed a, mixed b, string c ) { return "<i>"+c+"</i>"; } static string xtable_row_cont( mixed a, mixed b, string c ) { return "<tr>"+c+"</tr>"; } static string xtable_c_cont( mixed a, mixed b, string c ) { return "<td>"+c+"</td>"; } static string help_tag( mixed a, mapping m, string c ) { if( m["for"] ) return find_tag_doc( m["for"] ); return 0; // keep. } static string format_doc(string|mapping doc, string name, void|object id) {
9dcf432000-01-23Martin Nilsson  if(mappingp(doc)) {
a104662000-01-25Martin Nilsson  if(id && id->misc->pref_languages) {
9a669a2000-09-19Per Hedbor  foreach(id->misc->pref_languages->get_languages()+({"en"}), string code) {
e3b9b92000-02-23Martin Nilsson  object lang=roxen->language_low(code);
e40bf72000-01-28Martin Nilsson  if(lang) { array lang_id=lang->id(); if(doc[lang_id[2]]) { doc=doc[lang_id[2]]; break; } if(doc[lang_id[1]]) { doc=doc[lang_id[1]]; break; } }
dfe0642000-01-26Martin Nilsson  }
9dcf432000-01-23Martin Nilsson  } else doc=doc->standard; }
e40bf72000-01-28Martin Nilsson 
c7da172001-01-29Per Hedbor  name=replace(name, ({ "<", ">", "&" }), ({ "&lt;", "&gt;", "&amp;" }) );
b2401f2000-08-31Martin Nilsson 
3cf4892000-06-01Martin Nilsson  return Parser.HTML()->
9a669a2000-09-19Per Hedbor  add_tag( "lang",lambda() { return available_languages(id); } )-> add_tag( "help", help_tag )-> add_containers( ([ "list":list_cont, "xtable":xtable_cont, "row":xtable_row_cont, "c":xtable_c_cont, "module":module_cont, "desc":desc_cont, "attr":attr_cont, "ex":ex_cont, "noex":noex_cont, "tag":lambda(string tag, mapping m, string c) { return "&lt;"+c+"&gt;"; }, "ref":lambda(string tag, mapping m, string c) { return c; }, "short":lambda(string tag, mapping m, string c) { return m->hide?"":c; }, ]) )->
4a45f12001-03-13Martin Nilsson  add_quote_tag("!--","","--")-> set_extra(name, id)->feed(doc)->read();
cface32000-01-10Martin Nilsson }
c284a02000-01-21Martin Nilsson 
cface32000-01-10Martin Nilsson // ------------------ Parse docs in mappings --------------
5673a32000-07-23Martin Nilsson static string parse_doc(string|mapping|array doc, string name, void|object id) {
c284a02000-01-21Martin Nilsson  if(arrayp(doc))
9dcf432000-01-23Martin Nilsson  return format_doc(doc[0], name, id)+ "<dl><dd>"+parse_mapping(doc[1], id)+"</dd></dl>"; return format_doc(doc, name, id);
c284a02000-01-21Martin Nilsson }
5673a32000-07-23Martin Nilsson static string parse_mapping(mapping doc, void|object id) {
cface32000-01-10Martin Nilsson  string ret=""; if(!mappingp(doc)) return "";
e3b9b92000-02-23Martin Nilsson  foreach(sort(indices(doc)), string tmp) {
9dcf432000-01-23Martin Nilsson  ret+=parse_doc(doc[tmp], tmp, id);
cface32000-01-10Martin Nilsson  } return ret; }
6afce22001-01-16Martin Nilsson string parse_all_doc(RoxenModule o, void|RequestID id) { mapping doc = call_tagdocumentation(o); if(!doc) return 0; string ret = ""; foreach(sort(indices(doc)), string tagname) ret += parse_doc(doc[tagname], tagname, id); return ret; }
c284a02000-01-21Martin Nilsson 
cface32000-01-10Martin Nilsson // --------------------- Find documentation --------------
c284a02000-01-21Martin Nilsson mapping call_tagdocumentation(RoxenModule o) {
c8a9d12000-03-30Martin Nilsson  if(!o->tagdocumentation) return 0;
78be972001-04-23Martin Nilsson  string name = o->register_module()[1];
d95f6f2000-01-26Martin Nilsson 
c8a9d12000-03-30Martin Nilsson  mapping doc; if(!zero_type(doc=cache_lookup("tagdoc", name)))
d95f6f2000-01-26Martin Nilsson  return doc;
2feec42000-01-24Martin Nilsson  doc=o->tagdocumentation(); RXMLHELP_WERR(sprintf("tagdocumentation() returned %t.",doc));
d95f6f2000-01-26Martin Nilsson  if(!doc || !mappingp(doc)) {
c8a9d12000-03-30Martin Nilsson  cache_set("tagdoc", name, 0);
d95f6f2000-01-26Martin Nilsson  return 0; }
39e0362000-08-30Martin Nilsson  RXMLHELP_WERR("("+String.implode_nicely(indices(doc))+")");
c8a9d12000-03-30Martin Nilsson  cache_set("tagdoc", name, doc);
c284a02000-01-21Martin Nilsson  return doc; }
dbbfdf2000-01-12Martin Nilsson 
5673a32000-07-23Martin Nilsson static int generation;
9dcf432000-01-23Martin Nilsson multiset undocumented_tags=(<>); string find_tag_doc(string name, void|object id) {
124c202000-01-24Martin Nilsson  RXMLHELP_WERR("Help for tag "+name+" requested.");
c284a02000-01-21Martin Nilsson  RXML.TagSet tag_set=RXML.get_context()->tag_set; string doc; int new_gen=tag_set->generation; if(generation!=new_gen) {
9dcf432000-01-23Martin Nilsson  undocumented_tags=(<>);
c284a02000-01-21Martin Nilsson  generation=new_gen; }
39e0362000-08-30Martin Nilsson  array tags; if(name[..1]=="<?") { RXMLHELP_WERR(name+"?> is a processing instruction."); object tmp=tag_set->get_tag(name[2..], 1); if(tmp) tags=({ tmp }); else tags=({}); } else tags=tag_set->get_overridden_tags(name);
49ee2d2000-03-07Martin Nilsson  if(!sizeof(tags)) return "<h4>That tag ("+name+") is not defined</h4>"; string plugindoc="";
c284a02000-01-21Martin Nilsson  foreach(tags, array|object|function tag) { if(objectp(tag)) { // FIXME: New style tag. Check for internal documentation.
49ee2d2000-03-07Martin Nilsson  mapping(string:RXML.Tag) plugins=tag_set->get_plugins(name); if(sizeof(plugins)) { plugindoc="<hr /><dl><dd>"; foreach(sort(indices(plugins)), string plugin) plugindoc+=find_tag_doc(name+"#"+plugin, id); plugindoc+="</dd></dl>"; }
5e71002000-12-19Anders Johansson  if(tag->is_compat_tag) { RXMLHELP_WERR(sprintf("CompatTag %O", tag)); tag=tag->fn; } else if(tag->is_generic_tag) { RXMLHELP_WERR(sprintf("GenericTag %O", tag));
e8ae642000-03-16Martin Nilsson  tag=tag->_do_return;
5e71002000-12-19Anders Johansson  } else { RXMLHELP_WERR(sprintf("NormalTag %O", tag));
e8ae642000-03-16Martin Nilsson  tag=object_program(tag);
5e71002000-12-19Anders Johansson  }
c284a02000-01-21Martin Nilsson  }
e8ae642000-03-16Martin Nilsson  else if(arrayp(tag)) {
c284a02000-01-21Martin Nilsson  if(tag[0]) tag=tag[0][1]; else if(tag[1]) tag=tag[1][1]; }
e8ae642000-03-16Martin Nilsson  else continue;
b0e8f92000-03-22Martin Nilsson  if(!functionp(tag)) continue;
c284a02000-01-21Martin Nilsson  tag=function_object(tag); if(!objectp(tag)) continue;
2feec42000-01-24Martin Nilsson  RXMLHELP_WERR(sprintf("Tag defined in module %O", tag));
c284a02000-01-21Martin Nilsson  mapping tagdoc=call_tagdocumentation(tag); if(!tagdoc || !tagdoc[name]) continue;
49ee2d2000-03-07Martin Nilsson  return parse_doc(tagdoc[name], name, id)+plugindoc;
c284a02000-01-21Martin Nilsson  }
9dcf432000-01-23Martin Nilsson  undocumented_tags[name]=1;
49ee2d2000-03-07Martin Nilsson  if(has_value(name,"#")) { sscanf(name,"%*s#%s", name); name="plugin "+name; }
cface32000-01-10Martin Nilsson  return "<h4>No documentation available for \""+name+"\".</h4>\n"; }
2feec42000-01-24Martin Nilsson string find_module_doc( string cn, string mn, RequestID id )
cface32000-01-10Martin Nilsson {
124c202000-01-24Martin Nilsson  RXMLHELP_WERR("Help for module "+mn+" requested.");
cface32000-01-10Martin Nilsson  object c = roxen.find_configuration( cn );
2feec42000-01-24Martin Nilsson  if(!c) return "";
cface32000-01-10Martin Nilsson 
2feec42000-01-24Martin Nilsson  RoxenModule o = c->find_module( replace(mn,"!","#") );
124c202000-01-24Martin Nilsson  if(!o) return "";
cface32000-01-10Martin Nilsson 
2feec42000-01-24Martin Nilsson  return parse_mapping(o->tagdocumentation());
cface32000-01-10Martin Nilsson }