7e596b2000-02-13Per Hedbor // RXML Help
24c6c12000-02-20Martin Nilsson // Copyright © 2000, Roxen IS.
cface32000-01-10Martin Nilsson // Martin Nilsson //
2feec42000-01-24Martin Nilsson //#define RXMLHELP_DEBUG #ifdef RXMLHELP_DEBUG # define RXMLHELP_WERR(X) werror("RXML help: %s\n", X); #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; if(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  private string desc_cont(string t, mapping m, string c, string rt) { 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; }
cface32000-01-10Martin Nilsson  return sprintf("<h2>%s</h2><p>%s</p>",dt,c); } private string attr_cont(string t, mapping m, string c) { 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 />";
76a6912000-03-07Martin Nilsson  return sprintf("<p><b>%s</b><br />%s%s</p>",m->name,p,c);
cface32000-01-10Martin Nilsson } private string attr_vals(string v) {
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; }
b0e8f92000-03-22Martin Nilsson private string noex_cont(string t, mapping m, string c) { return parse_html(c, ([]), (["ex":""])); }
9dcf432000-01-23Martin Nilsson private string ex_cont(string t, mapping m, string c, string rt, void|object id) {
4d5e2e2000-05-30Martin Nilsson  c="<pre>"+replace(c, ({"<",">","&"}), ({"&lt;","&gt;","&amp;"}) )+"</pre>"; if(m->type=="box") return "<br />"+mktable( ({ ({ c }) }) );
9dcf432000-01-23Martin Nilsson  if(!id) return "";
4d5e2e2000-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":
76a6912000-03-07Martin Nilsson  return c+"<hr />"+parsed;
9dcf432000-01-23Martin Nilsson  case "vert":
76a6912000-03-07Martin Nilsson  return "<br />"+mktable( ({ ({ c }), ({ parsed }) }) );
9dcf432000-01-23Martin Nilsson  case "hor": default:
76a6912000-03-07Martin Nilsson  return "<br />"+mktable( ({ ({ c, parsed }) }) );
9dcf432000-01-23Martin Nilsson  } } private string format_doc(string|mapping doc, string name, void|object id) { if(mappingp(doc)) {
a104662000-01-25Martin Nilsson  if(id && id->misc->pref_languages) {
e40bf72000-01-28Martin Nilsson  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 
7fa01f2000-01-31Martin Nilsson  return parse_html(doc, (["lang":lambda() { return available_languages(id); } ]), ([
cface32000-01-10Martin Nilsson  "desc":desc_cont,
9dcf432000-01-23Martin Nilsson  "attr":attr_cont,
a104662000-01-25Martin Nilsson  "ex":ex_cont,
b0e8f92000-03-22Martin Nilsson  "noex":noex_cont,
7fa01f2000-01-31Martin Nilsson  "tag":lambda(string tag, mapping m, string c) { return "&lt;"+c+"&gt;"; },
b0dcf72000-02-20Martin Nilsson  "ref":lambda(string tag, mapping m, string c) { return c; }, "short":lambda(string tag, mapping m, string c) { m->hide?"":c; }
9dcf432000-01-23Martin Nilsson  ]), name, id);
cface32000-01-10Martin Nilsson }
c284a02000-01-21Martin Nilsson 
cface32000-01-10Martin Nilsson // ------------------ Parse docs in mappings --------------
9dcf432000-01-23Martin Nilsson private 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 }
9dcf432000-01-23Martin Nilsson private 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; }
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;
d95f6f2000-01-26Martin Nilsson  string name; if(o->is_configuration) name="RXML Core"; else name=o->register_module()[1];
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; }
c8a9d12000-03-30Martin Nilsson  cache_set("tagdoc", name, doc);
c284a02000-01-21Martin Nilsson  return doc; }
dbbfdf2000-01-12Martin Nilsson 
9dcf432000-01-23Martin Nilsson private int generation; 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; } array 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>"; }
e8ae642000-03-16Martin Nilsson  if(tag->is_generic_tag) tag=tag->_do_return; else tag=object_program(tag);
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 }