Merge: introduce nit_env.sh to setup the shell environement
[nit.git] / contrib / opportunity / src / templates / meetup.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 # Shows a meetup and allows to modify its participants
16 module meetup is i18n
17
18 import opportunity_model
19 import boilerplate
20 import welcome
21 import template
22
23 # Shows a meetup and allows to modify its participants
24 class OpportunityMeetupPage
25 super OpportunityPage
26
27 # Meetup the page is supposed to show
28 var meetup: nullable Meetup = null
29 # Answer mode for the meetup
30 var mode = 0
31
32 init from_id(id: String) do
33 var db = new OpportunityDB.open("opportunity")
34 meetup = db.find_meetup_by_id(id)
35 db.close
36 if meetup != null then mode = meetup.answer_mode
37 init
38 end
39
40 init do
41 header.page_js = "mode = {mode};\n"
42 header.page_js += """
43 function update_scores(){
44 var anss = $('.answer');
45 var count = {};
46 var scores = {};
47 var answers = [];
48 var maxscore = 0;
49
50 // Pizza ratios
51 var pizzas = {};
52 var pizzas_person = {};
53 var pizzas_total = 0.0;
54
55 // Iterate over each participant x possible answers
56 for(i=0; i < anss.length; i++){
57 var incscore = 0;
58 var inccount = 0;
59 var idparts = anss[i].id.split("_");
60 var ansid = idparts[1];
61 var html = anss[i].innerHTML;
62 if(html === "<center>✔</center>"){
63 inccount = 1;
64 incscore = 2;
65 }else if(html === "<center>❓</center>"){
66 incscore = 1;
67 }
68 var intansid = parseInt(ansid)
69 if(answers.indexOf(intansid) == -1){
70 answers.push(intansid);
71 }
72 if(ansid in count){
73 count[ansid] += inccount;
74 }else{
75 count[ansid] = inccount;
76 }
77 if(ansid in scores){
78 scores[ansid] += incscore;
79 }else{
80 scores[ansid] = incscore;
81 }
82 if(scores[ansid] > maxscore){
83 maxscore = scores[ansid];
84 }
85
86 if (ansid in pizzas_person) {
87
88 // Pizza ratio of previous participant
89 for (a in pizzas_person) {
90 var value = pizzas_person[a];
91 if (value != 0.0 && pizzas_total != 0)
92 value /= pizzas_total;
93
94 if (a in pizzas)
95 pizzas[a] += value;
96 else
97 pizzas[a] = value;
98 }
99
100 // Reset for a new person
101 pizzas_person = {};
102 pizzas_total = 0.0;
103 }
104
105 pizzas_total += incscore;
106 pizzas_person[ansid] = incscore;
107 }
108
109 // Pizza ratio of the last participant
110 for (a in pizzas_person) {
111 var value = pizzas_person[a];
112 if (value != 0.0 && pizzas_total != 0)
113 value /= pizzas_total;
114
115 if (a in pizzas)
116 pizzas[a] += value;
117 else
118 pizzas[a] = value;
119 }
120
121 var pizza_unit = document.getElementById("pizza_unit").value;
122 if (pizza_unit)
123 pizza_unit = parseFloat(pizza_unit);
124 else
125 pizza_unit = 1;
126
127 for(i=0; i < answers.length; i++){
128 var ansid = answers[i].toString();
129 var el = $('#total'+ansid)[0];
130 var ins = "<center>"+count[ansid];
131 if(scores[ansid] >= maxscore){
132 ins += "<br/><span style=\\"color:blue\\">★</span>";
133 }
134 ins += "</center>";
135 el.innerHTML = ins;
136
137 // Pizza ratio
138 var val = pizzas[ansid] * pizza_unit;
139
140 el = $('#pizzas'+ansid)[0];
141 ins = "<center>"+val.toFixed(1);
142 ins += "<br><span style=\\"color:orange\\">∇</span>";
143 ins += "</center>";
144 el.innerHTML = ins;
145 }
146
147 var pizza_unit = $("#pizza_unit").val();
148 set_cookie("opportunity_pizza_unit", pizza_unit);
149 }
150 function change_answer(ele, id){
151 // modify only the currently selected entry
152 if (in_modification_id != id) return;
153
154 var e = document.getElementById(ele.id);
155 var i = e.innerHTML;
156 var ans = true;"""
157 if mode == 0 then
158 header.page_js += """
159 if(i === "<center>✔</center>"){
160 ans = 0;
161 e.innerHTML = "<center>✘</center>"
162 e.style.color = "red";
163 }else{
164 ans = 1;
165 e.innerHTML = "<center>✔</center>";
166 e.style.color = "green";
167 }"""
168
169 else
170 header.page_js += """
171 if(i === "<center>✔</center>"){
172 ans = 1;
173 e.innerHTML = "<center>❓</center>"
174 e.style.color = "#B8860B";
175 }else if(i === "<center>❓</center>"){
176 ans = 0;
177 e.innerHTML = "<center>✘</center>"
178 e.style.color = "red";
179 }else{
180 ans = 2;
181 e.innerHTML = "<center>✔</center>";
182 e.style.color = "green";
183 }"""
184 end
185 header.page_js += """
186 var a = ele.id.split('_')
187 var pid = a[1]
188 var aid = a[2]
189 update_scores();
190 $.ajax({
191 type: "POST",
192 url: "./rest/answer",
193 data: {
194 answer_id: aid,
195 pers_id: pid,
196 answer: ans
197 }
198 });
199 }
200 function change_temp_answer(ele){
201 var e = document.getElementById(ele.id);
202 var i = e.innerHTML;"""
203 if mode == 0 then
204 header.page_js += """
205 if(i === "<center>✔</center>"){
206 e.innerHTML = "<center>✘</center>"
207 e.style.color = "red";
208 }else{
209 e.innerHTML = "<center>✔</center>";
210 e.style.color = "green";
211 }
212 """
213 else
214 header.page_js += """
215 if(i === "<center>✔</center>"){
216 e.innerHTML = "<center>❓</center>";
217 e.style.color = "#B8860B";
218 }else if(i === "<center>❓</center>"){
219 e.innerHTML = "<center>✘</center>"
220 e.style.color = "red";
221 }else{
222 e.innerHTML = "<center>✔</center>";
223 e.style.color = "green";
224 }
225 """
226 end
227 header.page_js += """
228 update_scores();
229 }
230 function add_part(ele){
231 var e = document.getElementById(ele.id);
232 var pname = document.getElementById("new_name").value;
233 var arr = e.id.split("_");
234 var mid = arr[1];
235 var ans = $('#' + ele.id).parent().parent().parent().children(".answer");
236 ansmap = {};
237 for(i=0;i<ans.length;i++){
238 var curr = ans.eq(i)
239 """
240 if mode == 0 then
241 header.page_js += """
242 if(curr[0].innerHTML === "<center>✔</center>"){
243 ansmap[curr.attr('id')] = 1
244 }else{
245 ansmap[curr.attr('id')] = 0
246 }"""
247 else
248 header.page_js += """
249 if(curr[0].innerHTML === "<center>✔</center>"){
250 ansmap[curr.attr('id')] = 2
251 }else if(curr[0].innerHTML === "<center>❓</center>"){
252 ansmap[curr.attr('id')] = 1
253 }else{
254 ansmap[curr.attr('id')] = 0
255 }"""
256 end
257 header.page_js += """
258 }
259 $.ajax({
260 type: "POST",
261 url: "./rest/meetup/new_pers",
262 data: {
263 meetup_id: mid,
264 persname: pname,
265 answers: $.param(ansmap)
266 }
267 })
268 .done(function(data){
269 location.reload();
270 })
271 .fail(function(data){
272 //TODO: Notify of failure
273 });
274
275 // Remember the participant's name client-side
276 set_cookie("opportunity_participant_name", pname);
277 }
278
279 function remove_people(ele){
280 var arr = ele.id.split("_")
281 var pid = arr[1]
282 $('#' + ele.id).parent().parent().parent().remove();
283 update_scores();
284 $.ajax({
285 type: "POST",
286 url: "./rest/people",
287 data: {
288 method: "DELETE",
289 p_id: pid
290 }
291 });
292 }
293
294 // ID of line currently open for modification
295 var in_modification_id = null;
296 function modify_people(ele, id){
297 if (in_modification_id != null) {
298 // reset to normal values
299 $('#modify_'+in_modification_id).text("{{{"Modify or delete"}}}");
300 $('#modify_'+in_modification_id).attr("class", "btn btn-xs btn-warning");
301 $('#line_'+in_modification_id).css("background-color", "");
302 $('#delete_'+in_modification_id).css("display", "none");
303 }
304 if (in_modification_id != id) {
305 // activate modifiable mode
306 $('#modify_'+id).text("{{{"Done"}}}");
307 $('#modify_'+id).attr("class", "btn btn-xs btn-success");
308 $('#line_'+id).css("background-color", "LightYellow");
309 $('#delete_'+id).show();
310
311 in_modification_id = id;
312 } else {
313 in_modification_id = null;
314 }
315 }
316
317 function get_cookie(cookie_name) {
318 var name = cookie_name + "=";
319 var ca = document.cookie.split(';');
320 for(var i = 0; i < ca.length; i ++) {
321 var c = ca[i];
322 while (c.charAt(0) == ' ') c = c.substring(1);
323 if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
324 }
325 return "";
326 }
327
328 function set_cookie(cookie_name, value) {
329 var date = new Date();
330 date.setTime(date.getTime() + (365*24*60*60*1000));
331 var expires = "expires="+date.toUTCString();
332 document.cookie = cookie_name + "=" + value + "; " + expires;
333 }
334
335 // Retrieve the last client-side participant's name
336 window.onload = function () {
337 $("#new_name").val(get_cookie("opportunity_participant_name"));
338 $("#new_name").focus();
339
340 $("#pizza_unit").val(get_cookie("opportunity_pizza_unit"));
341
342 update_scores();
343 }
344 """
345 end
346
347 redef fun rendering do
348 if meetup == null then
349 add((new OpportunityHomePage).write_to_string)
350 return
351 end
352 add header
353 var db = new OpportunityDB.open("opportunity")
354 add meetup.to_html(db)
355 db.close
356 add footer
357 end
358 end
359
360 redef class Meetup
361 # Build the HTML for `self`
362 fun to_html(db: OpportunityDB): Writable do
363 var t = new Template
364 t.add """
365 <div class="container">
366 <div class="page-header">
367 <center><h1>{{{name}}}</h1></center>
368 """
369 if not date.is_empty then t.add """
370 <center><h4>{{{"When:"}}} {{{date}}}</h4></center>"""
371
372 if not place.is_empty then t.add """
373 <center><h4>{{{"Where:"}}} {{{place}}}</h4></center>"""
374
375 t.add """
376 </div>
377 <table class="table">
378 """
379 t.add "<th>{"Participant name"}</th>"
380 for i in answers(db) do
381 t.add "<th class=\"text-center\">"
382 t.add i.to_s
383 t.add "</th>"
384 end
385 t.add "<th></th>"
386 t.add "</tr>"
387 for i in participants(db) do
388 i.load_answers(db, self)
389 t.add "<tr id=\"line_{i.id}\">"
390 t.add "<td>"
391 t.add i.to_s
392 t.add "</td>"
393 for j, k in i.answers do
394 var color
395 if answer_mode == 0 then
396 if k == 1 then
397 color = "green"
398 else
399 color = "red"
400 end
401 else
402 if k == 2 then
403 color = "green"
404 else if k == 1 then
405 color = "#B8860B"
406 else
407 color = "red"
408 end
409 end
410 t.add """<td class="answer" onclick="change_answer(this, {{{i.id}}})" id="answer_{{{j.id}}}_{{{i.id}}}" style="color:{{{color}}}">"""
411 t.add "<center>"
412 if answer_mode == 0 then
413 if k == 1 then
414 t.add "✔"
415 else
416 t.add "✘"
417 end
418 else
419 if k == 2 then
420 t.add "✔"
421 else if k == 1 then
422 t.add "❓"
423 else
424 t.add "✘"
425 end
426 end
427 t.add "</center></td>"
428 end
429 t.add """<td class="opportunity-action"><center><button class="btn btn-xs btn-warning" type="button" onclick="modify_people(this, {{{i.id}}})" id="modify_{{{i.id}}}">{{{"Modify or delete"}}}</button>&nbsp;"""
430 t.add """<button class="btn btn-xs btn-danger" type="button" onclick="remove_people(this)" id="delete_{{{i.id}}}" style="display: none;">{{{"Delete"}}}</button></center></td>"""
431 t.add "</tr>"
432 end
433 t.add """
434 <tr id="newrow" style="background-color: LightYellow">
435 <td><input id="new_name" type="text" placeholder="{{{"Your name"}}}" class="input-large"></td>
436 """
437 for i in answers(db) do
438 t.add "<td class=\"answer\" id=\"newans_{i.id}\" onclick=\"change_temp_answer(this)\" style=\"color:red;\"><center>✘</center></td>"
439 end
440 t.add """
441 <td><center><span id="add_{{{id}}}" onclick="add_part(this)" style="color:green;" class="action"><button class="btn btn-xs btn-success" type="button">{{{"Done"}}}</button></span></center></td>"""
442 t.add "</tr>"
443 # Compute score for each answer
444 var scores = new HashMap[Int, Int]
445 var maxsc = 0
446 for i in answers(db) do
447 scores[i.id] = i.score(db)
448 if scores[i.id] > maxsc then maxsc = scores[i.id]
449 end
450 t.add """
451 <tr id="total">
452 <th>Total ({{{participants(db).length}}})</th>
453 """
454 for i in answers(db) do t.add """
455 <th id="total{{{i.id}}}"><center></center></th>
456 """
457 t.add """
458 </tr>
459 <tr id="pizzas">
460 <th>
461 {{{"%1 ratio × %2".format("<span style='color:orange'>∇</span>", "<input id='pizza_unit' type='number' placeholder='1' text='1' class='inputsm' style='width: 8ex !important;' onchange='update_scores()' onkeypress='update_scores()' onpaste='update_scores()' oninput='update_scores()'>")}}}
462 </th>
463 """
464 for i in answers(db) do t.add """
465 <th id="pizzas{{{i.id}}}"></center></th>
466 """
467 t.add "</th>"
468 t.add """
469 <th></th>
470 </tr>"""
471 t.add "</table>"
472 t.add "</div>"
473 return t
474 end
475 end