3 * Copyright (C)2007-2008 Versabanq Innovations Inc. and contributors.
4 * See the included file named LICENSE for license information.
7 using System
.Collections
;
8 using System
.Collections
.Generic
;
18 public delegate object HtmlFunc();
19 //static WvLog log = new WvLog("WvHtml");
23 public string name
, value;
25 public Attr(string name
, string value)
27 wv
.assert(name
!= null);
28 wv
.assert(value != null);
39 public static readonly Attr noattr
= null;
45 public Verbatim(string s
)
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
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)
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
)
92 else if (o
is HtmlFunc
)
93 handler(((HtmlFunc
)o
)());
96 // Normal objects get automatically html-encoded. If
97 // you need to supply verbatim html, use v().
98 cb
.Append(HttpUtility
.HtmlEncode(o
.ToString()));
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);
109 string v
= HttpUtility
.HtmlAttributeEncode(a
.value);
110 if (attrs
.ContainsKey(a
.name
))
111 attrs
[a
.name
] = attrs
[a
.name
] + ' ' + v
;
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)));
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
)
136 cb
.Append(o
.ToString());
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
),
155 return wv
.fmt("{0}>{1}</{2}>",
156 ab
.ToString(), c
, tagname
);
159 return cb
.ToString();
162 public override string ToString()
167 public WvHtml
topmost()
175 public void add(params object[] args
)
178 opens
.Peek().add(args
);
181 foreach (object o
in args
)
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.
194 opens
.Push(new WvHtml());
197 // The reverse of push(). Returns the finished WvHtml subtree,
198 // which you can then add().
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),
210 // // add()s here come after the html() tag
212 // // add()s here come inside the div()
213 // add(p("hello world")); // this gets inserted at the i_c_h
215 // // subsequent add()s come after the html() tag.
216 public WvHtml insert_content_here
{
218 WvHtml h
= new WvHtml();
219 wv
.assert(ich
== null,
220 "There was no twist() after the last i_c_h!");
230 wv
.assert(ich
!= null,
231 "twist() only works after insert_content_here");
236 // To make them stand out, we prefix all the attribute-adding functions
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()); }
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)); }
284 public Attr
_confirm(string msg
)
286 return _attr("onclick",
287 wv
.fmt("return confirm(\"{0}\");", msg
));
291 public WvHtml
html(params object[] args
)
295 v("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" "
296 + "\"http://www.w3.org/TR/html4/strict.dtd\">\n"),
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
313 public WvHtml
script(params object[] args
)
314 { return tag("script", args); }
317 public WvHtml
javascript_file(string src
, params object[] args
)
318 { return script(_attr("type", "text/javascript"),
321 public WvHtml
js_file(string src
, params object[] args
)
322 { return javascript_file(src, args); }
325 public WvHtml
css_file(string src
, params object[] args
)
326 { return link(_attr("rel", "stylesheet"),
328 _attr("type", "text/css"),
332 public WvHtml
body(params object[] args
)
333 { return tag("body", args); }
336 public WvHtml
img(string src
, params object[] args
)
337 { return tag("img", _src(src), args); }
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); }
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); }
353 // This looks weird, but works better with IE.
354 get { return new WvHtml(null, v("<br />")); }
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); }
365 get { return v(" "); }
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); }
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); }
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); }
403 public WvHtml
form(string method
, string url
,
404 params object[] args
)
406 _attr("method", method
),
407 _attr("action", url
),
409 public WvHtml
submit(string id
, params object[] args
)
410 { return tag("input", _attr("type", "submit"),
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
,
429 public WvHtml
textarea(string name
, params object[] args
)
430 { return tag("textarea", _name(name), args); }