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 -------------------- 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)
c49cd92000-02-15Martin Nilsson  ret+="<tr valign=\"top\"><td bgcolor=\"#d9dee7\">"+(row*"</td><td bgcolor=\"#d9dee7\">")+"</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()))
a104662000-01-25Martin Nilsson  if(!roxen->languages[pl]) pl="en";
e40bf72000-01-28Martin Nilsson  else pl="en";
a104662000-01-25Martin Nilsson  mapping languages=roxen->languages[pl]->languages;
7e596b2000-02-13Per Hedbor  return mktable( map(indices(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); 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)"; if(m->value) p=sprintf("<i>%s=%s</i><br>",m->name,attr_vals(m->value)); return sprintf("<p><b>%s</b><br>%s%s</p>",m->name,p,c); } private string attr_vals(string v) { if(search(v,",")!=-1) return "{"+(v/",")*", "+"}"; //FIXME Use real config url if(v=="langcodes") return "<a href=\"/help/langcodes.pike\">language code</a>"; return v; }
9dcf432000-01-23Martin Nilsson private string ex_cont(string t, mapping m, string c, string rt, void|object id) { if(!id) return ""; string parsed=id->conf->parse_rxml(c,id);
7fa01f2000-01-31Martin Nilsson  c="<pre>"+replace(c, ({"<",">","&"}), ({"&lt;","&gt;","&amp;"}) )+"</pre>";
9dcf432000-01-23Martin Nilsson  switch(m->type) {
d95f6f2000-01-26Martin Nilsson  case "box": return "<br>"+mktable( ({ ({ c }) }) );
9dcf432000-01-23Martin Nilsson  case "hr": return c+"<hr>"+parsed; case "vert":
a104662000-01-25Martin Nilsson  return "<br>"+mktable( ({ ({ c }), ({ parsed }) }) );
9dcf432000-01-23Martin Nilsson  case "hor": default:
a104662000-01-25Martin 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) { object lang=roxen->languages[code]; 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,
7fa01f2000-01-31Martin Nilsson  "tag":lambda(string tag, mapping m, string c) { return "&lt;"+c+"&gt;"; }, "ref":lambda(string tag, mapping m, string c) { return 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 ""; foreach(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) { mapping doc;
d95f6f2000-01-26Martin Nilsson  string name; if(o->is_configuration) name="RXML Core"; else name=o->register_module()[1]; if(doc=cache_lookup("tagdoc", name)) return doc;
2feec42000-01-24Martin Nilsson  doc=o->tagdocumentation(); RXMLHELP_WERR(sprintf("tagdocumentation() returned %t.",doc));
d95f6f2000-01-26Martin Nilsson  if(!doc || !mappingp(doc)) {
e9d0172000-02-08Martin Nilsson  cache_set("tagdoc", name, 0);
d95f6f2000-01-26Martin Nilsson  return 0; }
e9d0172000-02-08Martin 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  cache_expire("tagdoc"); generation=new_gen; } array tags=tag_set->get_overridden_tags(name); if(!sizeof(tags)) return "<h4>That tag is not defined</h4>"; foreach(tags, array|object|function tag) { if(objectp(tag)) { // FIXME: New style tag. Check for internal documentation. tag=object_program(tag); } if(arrayp(tag)) { if(tag[0]) tag=tag[0][1]; else if(tag[1]) tag=tag[1][1]; } 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;
97673e2000-01-26Martin Nilsson  return parse_doc(tagdoc[name], name, id);
c284a02000-01-21Martin Nilsson  }
9dcf432000-01-23Martin Nilsson  undocumented_tags[name]=1;
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 }