Allow schema files that are missing checksums on the !!SCHEMAMATIC line.
[versaplex.git] / wvdotnet / wvhtml.cs
blob76e5ef79bd7e69baf941cfc2cb2896443e04a01f
1 /*
2 * Versaplex:
3 * Copyright (C)2007-2008 Versabanq Innovations Inc. and contributors.
4 * See the included file named LICENSE for license information.
5 */
6 using System;
7 using System.Collections;
8 using System.Collections.Generic;
9 using System.Text;
10 using System.Web;
11 using Wv;
12 using Wv.Extensions;
14 namespace Wv
16 public class WvHtml
18 public delegate object HtmlFunc();
19 //static WvLog log = new WvLog("WvHtml");
21 public class Attr
23 public string name, value;
25 public Attr(string name, string value)
27 wv.assert(name != null);
28 wv.assert(value != null);
29 this.name = name;
30 this.value = value;
33 public Attr()
35 this.name = "";
36 this.value = "";
39 public static readonly Attr noattr = null;
41 public class Verbatim
43 public string s;
45 public Verbatim(string s)
47 this.s = s;
51 string tagname;
52 List<object> content = new List<object>();
53 Stack<WvHtml> opens = new Stack<WvHtml>();
55 public WvHtml(string tagname, params object[] args)
57 //log.print("Creating '{0}'\n", tagname);
58 this.tagname = tagname; // may be null
59 add(args);
62 public WvHtml()
63 : this(null)
67 public string ToString(int indent)
69 //log.print("tostring: {0}\n", tagname);
71 var attrs = new Dictionary<string, string>();
72 StringBuilder ab = new StringBuilder();
73 StringBuilder cb = new StringBuilder();
75 while (opens.Count > 0)
76 pop();
78 if (tagname != null)
79 ab.Append(wv.fmt("<{0}", tagname));
81 foreach (object _o in content)
83 Action<object> handler;
85 // Okay, this is a little funny. The inner part of this loop
86 // can call itself recursively :) It's a nice way to handle
87 // things like IEnumerable.
88 handler = delegate(object o)
90 if (o == null)
91 return;
92 else if (o is HtmlFunc)
93 handler(((HtmlFunc)o)());
94 else if (o is string)
96 // Normal objects get automatically html-encoded. If
97 // you need to supply verbatim html, use v().
98 cb.Append(HttpUtility.HtmlEncode(o.ToString()));
100 else if (o is Attr)
102 // Collect all the attributes together to end up as
103 // part of our tag. If the same attribute name occurs
104 // more than once, concatenate all the values with
105 // spaces between. (This is useful for attributes like
106 // class="list blue")
107 wv.assert(tagname != null);
108 Attr a = (Attr)o;
109 string v = HttpUtility.HtmlAttributeEncode(a.value);
110 if (attrs.ContainsKey(a.name))
111 attrs[a.name] = attrs[a.name] + ' ' + v;
112 else
113 attrs.Add(a.name, v);
115 else if (o is Verbatim)
117 cb.Append(((Verbatim)o).s);
119 else if (o is WvHtml)
121 // WvHtml objects have already been html-encoded.
122 string s = ((WvHtml)o).ToString(indent+2);
123 cb.Append(wv.fmt("\n{0}", "".PadRight(indent+2)));
124 cb.Append(s);
125 if (s.Contains("\n"))
126 cb.Append(wv.fmt("\n{0}", "".PadRight(indent)));
128 else if (o is IEnumerable)
130 // CAREFUL! This branch catches all sorts of objects.
131 // For example, string is IEnumerable.
132 foreach (object oo in (IEnumerable)o)
133 handler(oo);
135 else
136 cb.Append(o.ToString());
139 handler(_o);
142 if (tagname != null)
144 foreach (string k in attrs.Keys)
145 ab.Append(wv.fmt(" {0}=\"{1}\"", k, attrs[k]));
147 string c = cb.ToString().TrimEnd();
148 /* if (c.Length == 0)
149 return ab.ToString() + " />";
150 else */ if (c.Contains("\n"))
151 return wv.fmt("{0}>{1}\n{2}</{3}>",
152 ab.ToString(), c, "".PadRight(indent),
153 tagname);
154 else
155 return wv.fmt("{0}>{1}</{2}>",
156 ab.ToString(), c, tagname);
158 else
159 return cb.ToString();
162 public override string ToString()
164 return ToString(0);
167 public WvHtml topmost()
169 if (opens.Count > 0)
170 return opens.Peek();
171 else
172 return this;
175 public void add(params object[] args)
177 if (opens.Count > 0)
178 opens.Peek().add(args);
179 else
181 foreach (object o in args)
183 if (o != null)
184 content.Add(o);
189 // Make subsequent add() calls add to an entirely different WvHtml
190 // object. You can call this, do a bunch of adds, and then
191 // take the return value of pop() and add it somewhere too.
192 public void push()
194 opens.Push(new WvHtml());
197 // The reverse of push(). Returns the finished WvHtml subtree,
198 // which you can then add().
199 public WvHtml pop()
201 return opens.Pop();
204 // WARNING MAGIC: use insert_contents_here as a marker in a
205 // deep hierarchy, then use twist() to make add() point at that
206 // part of the hierarchy, then use pop() to start adding back
207 // at the parent level. For example:
208 // add(html(body(div(insert_content_here),
209 // footer())));
210 // // add()s here come after the html() tag
211 // twist();
212 // // add()s here come inside the div()
213 // add(p("hello world")); // this gets inserted at the i_c_h
214 // pop();
215 // // subsequent add()s come after the html() tag.
216 public WvHtml insert_content_here {
217 get {
218 WvHtml h = new WvHtml();
219 wv.assert(ich == null,
220 "There was no twist() after the last i_c_h!");
221 ich = h;
222 return h;
226 // WARNING MAGIC:
227 WvHtml ich = null;
228 public void twist()
230 wv.assert(ich != null,
231 "twist() only works after insert_content_here");
232 opens.Push(ich);
233 ich = null;
236 // To make them stand out, we prefix all the attribute-adding functions
237 // with _.
238 public Attr _attr(string name, string value)
239 { return new Attr(name, value); }
240 public Attr _attr(string name, string fmt, params object[] args)
241 { return new Attr(name, wv.fmt(fmt, args)); }
242 public Attr _id(string value)
243 { return _attr("id", value); }
244 public Attr _class(string value)
245 { return _attr("class", value); }
246 public Attr _style(string value)
247 { return _attr("style", value); }
248 public Attr _name(string value)
249 { return _attr("name", value); }
250 public Attr _value(string value)
251 { return _attr("value", value); }
252 public Attr _type(string value)
253 { return _attr("type", value); }
254 public Attr _colspan(string value)
255 { return _attr("colspan", value); }
256 public Attr _rowspan(string value)
257 { return _attr("rowspan", value); }
258 public Attr _src(string value)
259 { return _attr("src", value); }
260 public Attr _align(string value)
261 { return _attr("align", value); }
262 public Attr _size(int size)
263 { return _attr("size", size.ToString()); }
264 public Attr _selected()
265 { return _attr("selected", "true"); }
266 public Attr _rows(int count)
267 { return _attr("rows", count.ToString()); }
268 public Attr _cols(int count)
269 { return _attr("cols", count.ToString()); }
271 // Helpers
272 public WvHtml v(params string[] args)
273 { return new WvHtml(null, args.map((s) => new Verbatim(s))); }
274 public WvHtml v(params object[] args)
275 { return new WvHtml(null, args); }
276 public WvHtml tag(string tagname, params object[] args)
277 { return new WvHtml(tagname, args); }
278 public WvHtml fmt(string f, params object[] args)
279 { return new WvHtml(null, wv.fmt(f, args)); }
280 public WvHtml func(Func<WvHtml> f)
281 { return new WvHtml(null, new HtmlFunc(f)); }
283 // Javascripty bits
284 public Attr _confirm(string msg)
286 return _attr("onclick",
287 wv.fmt("return confirm(\"{0}\");", msg));
290 // Toplevel
291 public WvHtml html(params object[] args)
293 return new WvHtml
294 (null,
295 v("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" "
296 + "\"http://www.w3.org/TR/html4/strict.dtd\">\n"),
297 tag("html", args));
300 // Header tags
301 public WvHtml head(params object[] args)
302 { return tag("head", args); }
303 public WvHtml title(params object[] args)
304 { return tag("title", args); }
305 public WvHtml meta(params object[] args)
306 { return tag("meta", args); }
307 public WvHtml link(params object[] args)
308 { return tag("link", args); }
310 // FIXME: script tags get confused by IE if you use <script... />
311 // syntax, so we have to force (badly!) <script>...</script> syntax
312 // here.
313 public WvHtml script(params object[] args)
314 { return tag("script", args); }
316 // Scripts
317 public WvHtml javascript_file(string src, params object[] args)
318 { return script(_attr("type", "text/javascript"),
319 _src(src),
320 args); }
321 public WvHtml js_file(string src, params object[] args)
322 { return javascript_file(src, args); }
324 // Stylesheets
325 public WvHtml css_file(string src, params object[] args)
326 { return link(_attr("rel", "stylesheet"),
327 _attr("href", src),
328 _attr("type", "text/css"),
329 args); }
331 // Body tags
332 public WvHtml body(params object[] args)
333 { return tag("body", args); }
335 // Images
336 public WvHtml img(string src, params object[] args)
337 { return tag("img", _src(src), args); }
339 // Anchors
340 public WvHtml a(params object[] args)
341 { return tag("a", args); }
342 public WvHtml ahref(string href, params object[] args)
343 { return a(_attr("href", href), args); }
345 // Sections
346 public WvHtml p(params object[] args)
347 { return tag("p", args); }
348 public WvHtml div(params object[] args)
349 { return tag("div", args); }
350 public WvHtml span(params object[] args)
351 { return tag("span", args); }
352 public WvHtml br {
353 // This looks weird, but works better with IE.
354 get { return new WvHtml(null, v("<br />")); }
357 // Text
358 public WvHtml b(params object[] args)
359 { return tag("b", args); }
360 public WvHtml i(params object[] args)
361 { return tag("i", args); }
362 public WvHtml sup(params object[] args)
363 { return tag("sup", args); }
364 public WvHtml nbsp {
365 get { return v("&nbsp;"); }
368 // Headings
369 public WvHtml h1(params object[] args)
370 { return tag("h1", args); }
371 public WvHtml h2(params object[] args)
372 { return tag("h2", args); }
373 public WvHtml h3(params object[] args)
374 { return tag("h3", args); }
375 public WvHtml h4(params object[] args)
376 { return tag("h4", args); }
377 public WvHtml h5(params object[] args)
378 { return tag("h5", args); }
379 public WvHtml h6(params object[] args)
380 { return tag("h6", args); }
382 // Lists
383 public WvHtml ol(params object[] args)
384 { return tag("ol", args); }
385 public WvHtml ul(params object[] args)
386 { return tag("ul", args); }
387 public WvHtml li(params object[] args)
388 { return tag("li", args); }
390 // Tables
391 public WvHtml table(params object[] args)
392 { return tag("table", args); }
393 public WvHtml tr(params object[] args)
394 { return tag("tr", args); }
395 public WvHtml tr_empty
396 { get { return tr(td(nbsp)); } }
397 public WvHtml td(params object[] args)
398 { return tag("td", args); }
399 public WvHtml th(params object[] args)
400 { return tag("th", args); }
402 // Forms
403 public WvHtml form(string method, string url,
404 params object[] args)
405 { return tag("form",
406 _attr("method", method),
407 _attr("action", url),
408 args); }
409 public WvHtml submit(string id, params object[] args)
410 { return tag("input", _attr("type", "submit"),
411 _id(id), _name(id),
412 _attr("value", id),
413 args); }
414 public WvHtml input(string id, int length, string defval,
415 params object[] args)
416 { return tag("input", _name(id), _size(length),
417 _value(defval), args); }
418 public WvHtml input(string id, int length)
419 { return input(id, length, ""); }
420 public WvHtml hidden(string id, object value)
421 { return tag("input", _type("hidden"),
422 _name(id), _value(value.ToString())); }
423 public WvHtml select(string id, params object[] args)
424 { return tag("select", _name(id), args); }
425 public WvHtml option(string name, string display,
426 params object[] args)
427 { return tag("option", _value(name), display, args,
428 nbsp, nbsp, nbsp); }
429 public WvHtml textarea(string name, params object[] args)
430 { return tag("textarea", _name(name), args); }
433 } // namespace