Merge: new `with` statement
[nit.git] / lib / html / bootstrap.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # HTML templates for Bootstrap components.
16 #
17 # See http://getbootstrap.com/components/
18 module bootstrap
19
20 import template
21
22 # Bootstrap component abstraction.
23 #
24 # Mainly used to factoryze CSS treatments.
25 # Can be used in the future to handle generic stuff like attributes or escaping.
26 #
27 # TODO merge with html::HTMTag without init conflict?
28 # HTMLTag requires the main init to pass a tagname,
29 # this was so much verbose here.
30 abstract class BSComponent
31 super Template
32
33 # CSS classes to add on this element.
34 var css_classes = new Array[String]
35
36 # Render `self` css clases as a `class` attribute.
37 fun render_css_classes: String do
38 if css_classes.is_empty then return ""
39 return " class=\"{css_classes.join(" ")}\""
40 end
41 end
42
43 # A `<a>` tag.
44 #
45 # Not really a Bootstrap component but used in other components
46 # that it required its own abstraction.
47 #
48 # Example:
49 # ~~~
50 # var lnk = new Link("http://nitlanguage.org", "Nit")
51 # assert lnk.write_to_string == "<a href=\"http://nitlanguage.org\">Nit</a>"
52 # ~~~
53 #
54 # Creates a link with a title attribute:
55 # ~~~
56 # lnk = new Link.with_title("http://nitlanguage.org", "Nit", "Nit homepage")
57 # assert lnk.write_to_string == "<a href=\"http://nitlanguage.org\" title=\"Nit homepage\">Nit</a>"
58 # ~~~
59 class Link
60 super BSComponent
61
62 # URL pointed by this link.
63 var href: String is writable
64
65 # Displayed text.
66 var text: Writable is writable
67
68 # Optional title.
69 var title: nullable String is noinit, writable
70
71 # Creates a link with a `title` attribute.
72 init with_title(href: String, text: Writable, title: nullable String) do
73 self.href = href
74 self.text = text
75 self.title = title
76 end
77
78 redef fun rendering do
79 add "<a{render_css_classes} href=\"{href}\""
80 if title != null then add " title=\"{title.write_to_string}\""
81 add ">{text}</a>"
82 end
83 end
84
85 # A `<h1>` to `<h6>` tag.
86 #
87 # Not really a Bootstrap component but used in other components
88 # that it required its own abstraction.
89 #
90 # Example:
91 # ~~~
92 # var h1 = new Header(1, "Title")
93 # assert h1.write_to_string == "<h1>Title</h1>"
94 # ~~~
95 #
96 # With subtext:
97 # ~~~
98 # var h6 = new Header.with_subtext(6, "Title", "with subtext")
99 # assert h6.write_to_string == "<h6>Title<small>with subtext</small></h6>"
100 # ~~~
101 class Header
102 super BSComponent
103
104 # Header level between 1 and 6.
105 var level: Int
106
107 # Displayed text.
108 var text: Writable
109
110 # Optional subtext.
111 var subtext: nullable Writable is noinit, writable
112
113 # Creates a link with a `title` attribute.
114 init with_subtext(level: Int, text: Writable, subtext: String) do
115 self.level = level
116 self.text = text
117 self.subtext = subtext
118 end
119
120 redef fun rendering do
121 add "<h{level}{render_css_classes}>{text.write_to_string}"
122 if subtext != null then add "<small>{subtext.write_to_string}</small>"
123 add "</h{level}>"
124 end
125 end
126
127 # An abstract HTML list.
128 #
129 # Many Bootstrap components are built around a HTML list.
130 #
131 # Used to factorize behavior between OrderedList and UnorderedList.
132 abstract class HTMLList
133 super BSComponent
134
135 # A list contains `<li>` tags as children.
136 #
137 # See ListItem.
138 var items = new Array[ListItem]
139
140 # Adds a new ListItem to `self`.
141 fun add_li(item: ListItem) do items.add item
142
143 # Does `self` contains no items?
144 fun is_empty: Bool do return items.is_empty
145 end
146
147 # A `<ol>` list tag.
148 #
149 # Example:
150 #
151 # ~~~
152 # var lst = new OrderedList
153 # lst.add_li(new ListItem("foo"))
154 # lst.add_li(new ListItem("bar"))
155 # lst.add_li(new ListItem("baz"))
156 #
157 # assert lst.write_to_string == """
158 # <ol>
159 # <li>foo</li>
160 # <li>bar</li>
161 # <li>baz</li>
162 # </ol>
163 # """
164 # ~~~
165 class OrderedList
166 super HTMLList
167
168 redef fun rendering do
169 addn "<ol{render_css_classes}>"
170 for item in items do add item
171 addn "</ol>"
172 end
173 end
174
175 # A `<ul>` list tag.
176 #
177 # Example:
178 #
179 # ~~~
180 # var lst = new UnorderedList
181 # lst.add_li(new ListItem("foo"))
182 # lst.add_li(new ListItem("bar"))
183 # lst.add_li(new ListItem("baz"))
184 #
185 # assert lst.write_to_string == """
186 # <ul>
187 # <li>foo</li>
188 # <li>bar</li>
189 # <li>baz</li>
190 # </ul>
191 # """
192 # ~~~
193 class UnorderedList
194 super HTMLList
195
196 redef fun rendering do
197 addn "<ul{render_css_classes}>"
198 for item in items do add item
199 addn "</ul>"
200 end
201 end
202
203 # A `<li>` tag.
204 class ListItem
205 super BSComponent
206
207 # Content to display in this list item.
208 var text: Writable is writable
209
210 redef fun rendering do addn "<li{render_css_classes}>{text.write_to_string}</li>"
211 end
212
213 # A Boostrap icon.
214 #
215 # See http://getbootstrap.com/components/#glyphicons
216 #
217 # Example:
218 #
219 # ~~~
220 # var icon = new BSIcon("star")
221 # assert icon.write_to_string == "<span class=\"glyphicon glyphicon-star\" aria-hidden=\"true\"></span>"
222 # ~~~
223 class BSIcon
224 super BSComponent
225
226 # Glyphicon name to display.
227 #
228 # See full list at http://getbootstrap.com/components/#glyphicons.
229 var icon: String
230
231 init do css_classes.add "glyphicon glyphicon-{icon}"
232
233 redef fun rendering do
234 add "<span{render_css_classes} aria-hidden=\"true\"></span>"
235 end
236 end
237
238 # A Bootstrap breadcrumbs component.
239 #
240 # See http://getbootstrap.com/components/#breadcrumbs
241 #
242 # Example:
243 #
244 # ~~~
245 # var bc = new BSBreadCrumbs
246 # bc.add_li(new ListItem("foo"))
247 # bc.add_li(new ListItem("bar"))
248 # bc.add_li(new ListItem("baz"))
249 #
250 # assert bc.write_to_string == """
251 # <ol class=\"breadcrumbs\">
252 # <li>foo</li>
253 # <li>bar</li>
254 # <li class=\"active\">baz</li>
255 # </ol>
256 # """
257 # ~~~
258 class BSBreadCrumbs
259 super OrderedList
260
261 init do css_classes.add "breadcrumbs"
262
263 redef fun rendering do
264 items.last.css_classes.add "active"
265 super
266 end
267 end
268
269 # A Bootstrap label component.
270 #
271 # See http://getbootstrap.com/components/#labels
272 #
273 # Example:
274 #
275 # ~~~
276 # var lbl = new BSLabel("danger", "Danger!")
277 # assert lbl.write_to_string == "<span class=\"label label-danger\">Danger!</span>"
278 # ~~~
279 class BSLabel
280 super BSComponent
281
282 # Class used to change the color of the label.
283 #
284 # Can be one of `default`, `primary`, `success`, `info`, `warning` or `danger`.
285 var color: String
286
287 # Text to display in the label.
288 var text: Writable
289
290 init do css_classes.add "label label-{color}"
291
292 redef fun rendering do
293 add "<span{render_css_classes}>{text.write_to_string}</span>"
294 end
295 end
296
297 # A Bootstrap badge component.
298 #
299 # See http://getbootstrap.com/components/#badges
300 #
301 # Example:
302 #
303 # ~~~
304 # var b = new BSBadge("42 messages")
305 # assert b.write_to_string == "<span class=\"badge\">42 messages</span>"
306 # ~~~
307 class BSBadge
308 super BSComponent
309
310 # Text to display in the label.
311 var text: Writable
312
313 init do css_classes.add "badge"
314
315 redef fun rendering do
316 add "<span{render_css_classes}>{text.write_to_string}</span>"
317 end
318 end
319
320 # A Bootstrap page header component.
321 #
322 # See http://getbootstrap.com/components/#page-header
323 #
324 # Example:
325 #
326 # ~~~
327 # var h = new BSPageHeader("Welcome")
328 # assert h.write_to_string == """
329 # <div class=\"page-header\">
330 # Welcome
331 # </div>
332 # """
333 # ~~~
334 class BSPageHeader
335 super BSComponent
336
337 # Text to display as title.
338 var text: Writable
339
340 init do css_classes.add "page-header"
341
342 redef fun rendering do
343 addn "<div{render_css_classes}>"
344 addn text.write_to_string
345 addn "</div>"
346 end
347 end
348
349 # A Bootstrap alert component.
350 #
351 # See http://getbootstrap.com/components/#alerts
352 #
353 # Example:
354 #
355 # ~~~
356 # var alert = new BSAlert("danger", "Danger!")
357 # assert alert.write_to_string == """
358 # <div class="alert alert-danger">
359 # Danger!
360 # </div>
361 # """
362 # ~~~
363 class BSAlert
364 super BSComponent
365
366 # Class used to change the color of the alert.
367 #
368 # Can be one of `primary`, `success`, `info`, `warning` or `danger`.
369 var color: String
370
371 # Text to display in the alert.
372 var text: Writable
373
374 # Can the alert be dismissed by clicking the close button?
375 #
376 # See http://getbootstrap.com/components/#alerts-dismissible
377 #
378 # Default is `false`.
379 var is_dismissible = false
380
381 init do css_classes.add "alert alert-{color}"
382
383 redef fun rendering do
384 addn "<div{render_css_classes}>"
385 if is_dismissible then
386 add "<button type=\"button\" class=\"close\" data-dismiss=\"alert\""
387 add "aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span>"
388 addn "</button>"
389 end
390 addn text.write_to_string
391 addn "</div>"
392 end
393 end
394
395 # A Bootstrap panel component.
396 #
397 # See http://getbootstrap.com/components/#panels
398 #
399 # Example:
400 #
401 # ~~~
402 # var p = new BSPanel("default", "Panel content")
403 #
404 # assert p.write_to_string == """
405 # <div class="panel panel-default">
406 # <div class="panel-body">
407 # Panel content
408 # </div>
409 # </div>
410 # """
411 # ~~~
412 #
413 # Panel with heading:
414 #
415 # ~~~
416 # p = new BSPanel("danger", "Panel content")
417 # p.heading = "Panel heading"
418 #
419 # assert p.write_to_string == """
420 # <div class="panel panel-danger">
421 # <div class="panel-heading">
422 # Panel heading
423 # </div>
424 # <div class="panel-body">
425 # Panel content
426 # </div>
427 # </div>
428 # """
429 # ~~~
430 class BSPanel
431 super BSComponent
432
433 # Panel color.
434 #
435 # Can be one of `default`, `primary`, `success`, `info`, `warning` or `danger`.
436 var color: String
437
438 # Panel header if any.
439 var heading: nullable Writable is noinit, writable
440
441 # Body to display in the panel.
442 var body: Writable
443
444 # Panel footer is any.
445 var footer: nullable Writable is noinit, writable
446
447 init do css_classes.add "panel panel-{color}"
448
449 redef fun rendering do
450 addn "<div{render_css_classes}>"
451 if heading != null then
452 addn "<div class=\"panel-heading\">"
453 addn heading.write_to_string
454 addn "</div>"
455 end
456 addn "<div class=\"panel-body\">"
457 addn body.write_to_string
458 addn "</div>"
459 if footer != null then
460 addn "<div class=\"panel-footer\">"
461 addn footer.write_to_string
462 addn "</div>"
463 end
464 addn "</div>"
465 end
466 end