Import Miguel's DataConverter.cs to replace dbus-sharp's crappy versions.
[versaplex.git] / wvdotnet / wvhtml.cs
blob395455bf518a5bf4aa59ef483471564e0dc62866
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Text;
5 using System.Web;
6 using Wv;
7 using Wv.Extensions;
9 namespace Wv
11 public class WvHtml
13 public delegate object HtmlFunc();
14 //static WvLog log = new WvLog("WvHtml");
16 public class Attr
18 public string name, value;
20 public Attr(string name, string value)
22 wv.assert(name != null);
23 wv.assert(value != null);
24 this.name = name;
25 this.value = value;
28 public Attr()
30 this.name = "";
31 this.value = "";
34 public static readonly Attr noattr = null;
36 public class Verbatim
38 public string s;
40 public Verbatim(string s)
42 this.s = s;
46 string tagname;
47 List<object> content = new List<object>();
48 Stack<WvHtml> opens = new Stack<WvHtml>();
50 public WvHtml(string tagname, params object[] args)
52 //log.print("Creating '{0}'\n", tagname);
53 this.tagname = tagname; // may be null
54 add(args);
57 public WvHtml()
58 : this(null)
62 public string ToString(int indent)
64 //log.print("tostring: {0}\n", tagname);
66 var attrs = new Dictionary<string, string>();
67 StringBuilder ab = new StringBuilder();
68 StringBuilder cb = new StringBuilder();
70 while (opens.Count > 0)
71 pop();
73 if (tagname != null)
74 ab.Append(wv.fmt("<{0}", tagname));
76 foreach (object _o in content)
78 Action<object> handler;
80 // Okay, this is a little funny. The inner part of this loop
81 // can call itself recursively :) It's a nice way to handle
82 // things like IEnumerable.
83 handler = delegate(object o)
85 if (o == null)
86 return;
87 else if (o is HtmlFunc)
88 handler(((HtmlFunc)o)());
89 else if (o is string)
91 // Normal objects get automatically html-encoded. If
92 // you need to supply verbatim html, use v().
93 cb.Append(HttpUtility.HtmlEncode(o.ToString()));
95 else if (o is Attr)
97 // Collect all the attributes together to end up as
98 // part of our tag. If the same attribute name occurs
99 // more than once, concatenate all the values with
100 // spaces between. (This is useful for attributes like
101 // class="list blue")
102 wv.assert(tagname != null);
103 Attr a = (Attr)o;
104 string v = HttpUtility.HtmlAttributeEncode(a.value);
105 if (attrs.ContainsKey(a.name))
106 attrs[a.name] = attrs[a.name] + ' ' + v;
107 else
108 attrs.Add(a.name, v);
110 else if (o is Verbatim)
112 cb.Append(((Verbatim)o).s);
114 else if (o is WvHtml)
116 // WvHtml objects have already been html-encoded.
117 string s = ((WvHtml)o).ToString(indent+2);
118 cb.Append(wv.fmt("\n{0}", "".PadRight(indent+2)));
119 cb.Append(s);
120 if (s.Contains("\n"))
121 cb.Append(wv.fmt("\n{0}", "".PadRight(indent)));
123 else if (o is IEnumerable)
125 // CAREFUL! This branch catches all sorts of objects.
126 // For example, string is IEnumerable.
127 foreach (object oo in (IEnumerable)o)
128 handler(oo);
130 else
131 cb.Append(o.ToString());
134 handler(_o);
137 if (tagname != null)
139 foreach (string k in attrs.Keys)
140 ab.Append(wv.fmt(" {0}=\"{1}\"", k, attrs[k]));
142 string c = cb.ToString().TrimEnd();
143 /* if (c.Length == 0)
144 return ab.ToString() + " />";
145 else */ if (c.Contains("\n"))
146 return wv.fmt("{0}>{1}\n{2}</{3}>",
147 ab.ToString(), c, "".PadRight(indent),
148 tagname);
149 else
150 return wv.fmt("{0}>{1}</{2}>",
151 ab.ToString(), c, tagname);
153 else
154 return cb.ToString();
157 public override string ToString()
159 return ToString(0);
162 public WvHtml topmost()
164 if (opens.Count > 0)
165 return opens.Peek();
166 else
167 return this;
170 public void add(params object[] args)
172 if (opens.Count > 0)
173 opens.Peek().add(args);
174 else
176 foreach (object o in args)
178 if (o != null)
179 content.Add(o);
184 // Make subsequent add() calls add to an entirely different WvHtml
185 // object. You can call this, do a bunch of adds, and then
186 // take the return value of pop() and add it somewhere too.
187 public void push()
189 opens.Push(new WvHtml());
192 // The reverse of push(). Returns the finished WvHtml subtree,
193 // which you can then add().
194 public WvHtml pop()
196 return opens.Pop();
199 // WARNING MAGIC: use insert_contents_here as a marker in a
200 // deep hierarchy, then use twist() to make add() point at that
201 // part of the hierarchy, then use pop() to start adding back
202 // at the parent level. For example:
203 // add(html(body(div(insert_content_here),
204 // footer())));
205 // // add()s here come after the html() tag
206 // twist();
207 // // add()s here come inside the div()
208 // add(p("hello world")); // this gets inserted at the i_c_h
209 // pop();
210 // // subsequent add()s come after the html() tag.
211 public WvHtml insert_content_here {
212 get {
213 WvHtml h = new WvHtml();
214 wv.assert(ich == null,
215 "There was no twist() after the last i_c_h!");
216 ich = h;
217 return h;
221 // WARNING MAGIC:
222 WvHtml ich = null;
223 public void twist()
225 wv.assert(ich != null,
226 "twist() only works after insert_content_here");
227 opens.Push(ich);
228 ich = null;
231 // To make them stand out, we prefix all the attribute-adding functions
232 // with _.
233 public Attr _attr(string name, string value)
234 { return new Attr(name, value); }
235 public Attr _attr(string name, string fmt, params object[] args)
236 { return new Attr(name, wv.fmt(fmt, args)); }
237 public Attr _id(string value)
238 { return _attr("id", value); }
239 public Attr _class(string value)
240 { return _attr("class", value); }
241 public Attr _style(string value)
242 { return _attr("style", value); }
243 public Attr _name(string value)
244 { return _attr("name", value); }
245 public Attr _value(string value)
246 { return _attr("value", value); }
247 public Attr _type(string value)
248 { return _attr("type", value); }
249 public Attr _colspan(string value)
250 { return _attr("colspan", value); }
251 public Attr _rowspan(string value)
252 { return _attr("rowspan", value); }
253 public Attr _src(string value)
254 { return _attr("src", value); }
255 public Attr _align(string value)
256 { return _attr("align", value); }
257 public Attr _size(int size)
258 { return _attr("size", size.ToString()); }
259 public Attr _selected()
260 { return _attr("selected", "true"); }
261 public Attr _rows(int count)
262 { return _attr("rows", count.ToString()); }
263 public Attr _cols(int count)
264 { return _attr("cols", count.ToString()); }
266 // Helpers
267 public WvHtml v(params string[] args)
268 { return new WvHtml(null, args.map((s) => new Verbatim(s))); }
269 public WvHtml v(params object[] args)
270 { return new WvHtml(null, args); }
271 public WvHtml tag(string tagname, params object[] args)
272 { return new WvHtml(tagname, args); }
273 public WvHtml fmt(string f, params object[] args)
274 { return new WvHtml(null, wv.fmt(f, args)); }
275 public WvHtml func(Func<WvHtml> f)
276 { return new WvHtml(null, new HtmlFunc(f)); }
278 // Javascripty bits
279 public Attr _confirm(string msg)
281 return _attr("onclick",
282 wv.fmt("return confirm(\"{0}\");", msg));
285 // Toplevel
286 public WvHtml html(params object[] args)
288 return new WvHtml
289 (null,
290 v("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" "
291 + "\"http://www.w3.org/TR/html4/strict.dtd\">\n"),
292 tag("html", args));
295 // Header tags
296 public WvHtml head(params object[] args)
297 { return tag("head", args); }
298 public WvHtml title(params object[] args)
299 { return tag("title", args); }
300 public WvHtml meta(params object[] args)
301 { return tag("meta", args); }
302 public WvHtml link(params object[] args)
303 { return tag("link", args); }
305 // FIXME: script tags get confused by IE if you use <script... />
306 // syntax, so we have to force (badly!) <script>...</script> syntax
307 // here.
308 public WvHtml script(params object[] args)
309 { return tag("script", args); }
311 // Scripts
312 public WvHtml javascript_file(string src, params object[] args)
313 { return script(_attr("type", "text/javascript"),
314 _src(src),
315 args); }
316 public WvHtml js_file(string src, params object[] args)
317 { return javascript_file(src, args); }
319 // Stylesheets
320 public WvHtml css_file(string src, params object[] args)
321 { return link(_attr("rel", "stylesheet"),
322 _attr("href", src),
323 _attr("type", "text/css"),
324 args); }
326 // Body tags
327 public WvHtml body(params object[] args)
328 { return tag("body", args); }
330 // Images
331 public WvHtml img(string src, params object[] args)
332 { return tag("img", _src(src), args); }
334 // Anchors
335 public WvHtml a(params object[] args)
336 { return tag("a", args); }
337 public WvHtml ahref(string href, params object[] args)
338 { return a(_attr("href", href), args); }
340 // Sections
341 public WvHtml p(params object[] args)
342 { return tag("p", args); }
343 public WvHtml div(params object[] args)
344 { return tag("div", args); }
345 public WvHtml span(params object[] args)
346 { return tag("span", args); }
347 public WvHtml br {
348 // This looks weird, but works better with IE.
349 get { return new WvHtml(null, v("<br />")); }
352 // Text
353 public WvHtml b(params object[] args)
354 { return tag("b", args); }
355 public WvHtml i(params object[] args)
356 { return tag("i", args); }
357 public WvHtml sup(params object[] args)
358 { return tag("sup", args); }
359 public WvHtml nbsp {
360 get { return v("&nbsp;"); }
363 // Headings
364 public WvHtml h1(params object[] args)
365 { return tag("h1", args); }
366 public WvHtml h2(params object[] args)
367 { return tag("h2", args); }
368 public WvHtml h3(params object[] args)
369 { return tag("h3", args); }
370 public WvHtml h4(params object[] args)
371 { return tag("h4", args); }
372 public WvHtml h5(params object[] args)
373 { return tag("h5", args); }
374 public WvHtml h6(params object[] args)
375 { return tag("h6", args); }
377 // Lists
378 public WvHtml ol(params object[] args)
379 { return tag("ol", args); }
380 public WvHtml ul(params object[] args)
381 { return tag("ul", args); }
382 public WvHtml li(params object[] args)
383 { return tag("li", args); }
385 // Tables
386 public WvHtml table(params object[] args)
387 { return tag("table", args); }
388 public WvHtml tr(params object[] args)
389 { return tag("tr", args); }
390 public WvHtml tr_empty
391 { get { return tr(td(nbsp)); } }
392 public WvHtml td(params object[] args)
393 { return tag("td", args); }
394 public WvHtml th(params object[] args)
395 { return tag("th", args); }
397 // Forms
398 public WvHtml form(string method, string url,
399 params object[] args)
400 { return tag("form",
401 _attr("method", method),
402 _attr("action", url),
403 args); }
404 public WvHtml submit(string id, params object[] args)
405 { return tag("input", _attr("type", "submit"),
406 _id(id), _name(id),
407 _attr("value", id),
408 args); }
409 public WvHtml input(string id, int length, string defval,
410 params object[] args)
411 { return tag("input", _name(id), _size(length),
412 _value(defval), args); }
413 public WvHtml input(string id, int length)
414 { return input(id, length, ""); }
415 public WvHtml hidden(string id, object value)
416 { return tag("input", _type("hidden"),
417 _name(id), _value(value.ToString())); }
418 public WvHtml select(string id, params object[] args)
419 { return tag("select", _name(id), args); }
420 public WvHtml option(string name, string display,
421 params object[] args)
422 { return tag("option", _value(name), display, args,
423 nbsp, nbsp, nbsp); }
424 public WvHtml textarea(string name, params object[] args)
425 { return tag("textarea", _name(name), args); }
428 } // namespace