comparison mod_http_index/mod_http_index.lua @ 1573:0d8cc6971cdb

mod_http_index: Generates an index of local HTTP apps
author Kim Alvefur <zash@zash.se>
date Thu, 20 Nov 2014 14:48:46 +0100
parents
children 1b5c817cb642
comparison
equal deleted inserted replaced
1572:1aa894db3585 1573:0d8cc6971cdb
1 local st = require "util.stanza";
2 local url = require"socket.url";
3
4 module:depends"http";
5
6 -- local dump = require"util.serialization".new"dump".serialize;
7
8 local function template(data)
9 --[[ DOC
10 Like util.template, but deals with plain text
11 Returns a closure that is called with a table of values
12 {name} is substituted for values["name"] and is XML escaped
13 {name!} is substituted without XML escaping
14 {name?} is optional and is replaced with an empty string if no value exists
15 ]]
16 return function(values)
17 return (data:gsub("{([^}]-)(%p?)}", function (name, opt)
18 local value = values[name];
19 if value then
20 if opt ~= "!" then
21 return st.xml_escape(value);
22 end
23 return value;
24 elseif opt == "?" then
25 return "";
26 end
27 end));
28 end
29 end
30
31 -- TODO Move templates into files
32 local base = template(template[[
33 <!DOCTYPE html>
34 <html>
35 <head>
36 <meta charset="utf-8">
37 <meta name="viewport" content="width=device-width, initial-scale=1">
38 <meta name="generator" value="prosody/{prosody_version} mod_{mod_name}">
39 <link rel="canonical" href="{canonical}">
40 <title>{title}</title>
41 <style>
42 body{background-color:#eeeeec;margin:1ex 0;padding-bottom:3em;font-family:Arial,Helvetica,sans-serif;}
43 header,footer{margin:1ex 1em;}
44 footer{font-size:smaller;color:#babdb6;}
45 .content{background-color:white;padding:1em;list-style-position:inside;}
46 nav{font-size:large;margin:1ex 1ex;clear:both;line-height:1.5em;}
47 nav a{padding: 1ex;text-decoration:none;}
48 nav a[rel="up"]{font-size:smaller;}
49 nav a[rel="prev"]{float:left;}
50 nav a[rel="next"]{float:right;}
51 nav a[rel="next::after"]{content:" →";}
52 nav a[rel="prev::before"]{content:"← ";}
53 nav a:empty::after,nav a:empty::before{content:""}
54 @media screen and (min-width: 460px) {
55 nav{font-size:x-large;margin:1ex 1em;}
56 }
57 a:link,a:visited{color:#2e3436;text-decoration:none;}
58 a:link:hover,a:visited:hover{color:#3465a4;}
59 ul,ol{padding:0;}
60 li{list-style:none;}
61 hr{visibility:hidden;clear:both;}
62 br{clear:both;}
63 li time{float:right;font-size:small;opacity:0.2;}
64 li:hover time{opacity:1;}
65 .room-list .description{font-size:smaller;}
66 q.body::before,q.body::after{content:"";}
67 .presence .verb{font-style:normal;color:#30c030;}
68 .presence.unavailable .verb{color:#c03030;}
69 </style>
70 </head>
71 <body>
72 <header>
73 <h1>{title}</h1>
74 {header!}
75 </header>
76 <hr>
77 <div class="content">
78 {body!}
79 </div>
80 <hr>
81 <footer>
82 {footer!}
83 <br>
84 <div class="powered-by">Prosody {prosody_version?}</div>
85 </footer>
86 </body>
87 </html>
88 ]] { prosody_version = prosody.version, mod_name = module.name });
89
90 local canonical = module:http_url(nil, "/");
91 local page_template = template(base{
92 canonical = canonical;
93 title = "HTTP stuff";
94 header = "";
95 body = [[
96 <nav>
97 <ul>
98 {lines!}
99 </ul>
100 </nav>
101 ]];
102 footer = "";
103 });
104 local line_template = template[[
105 <li><a href="{url}" title="{module}">{name}</a></li>
106 ]];
107
108 local function relative(base, link)
109 base = url.parse(base);
110 link = url.parse(link);
111 for k,v in pairs(base) do
112 if link[k] == v then
113 link[k] = nil;
114 end
115 end
116 return url.build(link);
117 end
118
119 local function handler(event)
120 local items = module:get_host_items("http-provider");
121 local item;
122 for i = 1, #items do
123 item = items[i];
124 if module.name ~= item._provided_by then
125 items[i] = line_template{
126 name = item.name;
127 module = "mod_" .. item._provided_by;
128 url = relative(canonical, module:http_url(item.name, item.default_path));
129 };
130 else
131 items[i] = "";
132 end
133 end
134 event.response.headers.content_type = "text/html";
135 return page_template{
136 lines = table.concat(items);
137 };
138 end
139
140 module:provides("http", {
141 route = {
142 ["GET /"] = handler;
143 };
144 default_path = "/";
145 });