]> git.ktnx.net Git - lsl.git/blob - public/javascripts/lsl.js
move edi list trigger to list name heading
[lsl.git] / public / javascripts / lsl.js
1 "use strict";
2 (function(){
3 var uri_base, environment, devel_env;   // filled on page load from an HTML attribute
4 var start_time = Date.now();
5
6 var ui_icon_class_re = new RegExp('\\bui-icon-\\S+\\b');
7 var uri_id_re = new RegExp('/(\\d+)$');
8 var lists_version = -1;
9 var lists = [];
10 var selected_list;
11
12 function debug(...args) {
13     if (devel_env)
14         console.debug.apply(console, args);
15 }
16
17 function uri_id(uri) {
18     var m = uri.match(uri_id_re);
19     return m ? m[1] : null;
20 }
21 function add_list_item(data) {
22     var item = $('<li>').addClass('list-item-row').data('item', data);
23     var cb = $('<input type="checkbox">');
24     if (data.done) cb.prop('checked', true);
25     item.append(cb);
26     item.append($('<span class="description">').text(data.description || ''));
27     item.append($('<span class="edit-trigger">').text('…'));
28
29     $('#list-items').append(item);
30     $('#list-contents').addClass('have-list-items');
31 }
32 function got_lists_version(new_version) {
33     if (new_version != lists_version)
34         window.setTimeout(load_lists);
35 }
36 function got_list_version(new_version) {
37     if (new_version != selected_list.attr('lsl-version'))
38         window.setTimeout(
39             () => load_list_items(selected_list.data('lsl-uri'), selected_list));
40 }
41 function load_list_items(uri, target) {
42     $.get(uri)
43     .done(item_data => {
44         target.data('items', item_data);
45
46         // TODO: merge new items into existing ones
47         // keep track of the last existing item, and append new one
48         // after it, prepending if there is no last existing item
49         // the newly prepended/inserted item becomes the last existing
50         $('#list-contents').removeClass('have-list-items');
51         var item_list = $('#list-items').empty();
52
53         $.each(item_data.items, (i,item) => {
54             add_list_item(item);
55         });
56
57         got_lists_version(item_data.lists_version);
58     });
59 }
60 function select_list(new_selected_list) {
61     if (new_selected_list && selected_list
62         && new_selected_list.length && selected_list.length
63         && new_selected_list.get(0) == selected_list.get(0)
64     )
65         return;
66
67     if (new_selected_list && !new_selected_list.length)
68         new_selected_list = null;
69
70     $('#page').toggleClass('have-lists', !!new_selected_list);
71
72     if (selected_list)
73         selected_list.removeClass('selected');
74
75     if (new_selected_list) {
76         load_list_items(new_selected_list.data('lsl-uri'), new_selected_list);
77         new_selected_list.addClass('selected');
78         $('#selected-list-name').text(new_selected_list.data('lsl-name'));
79     }
80
81     selected_list = new_selected_list;
82 }
83 function edit_list() {
84     var d = $('<div>')
85         .append(
86             $('<fieldset>')
87                 .append(
88                     $('<legend>').text('List name'),
89                     $('<input type="text" size="40">')
90                     .val(selected_list.data('lsl-name'))
91                 )
92         );
93
94     d.dialog({
95         autoOpen: true,
96         modal: true,
97         title: 'Edit list',
98         width: 'max-content',
99         buttons: [
100             {
101                 class: 'btn-delete',
102                 icon: 'ui-icon-trash',
103                 text: 'Delete',
104                 click: () => {
105                     delete_list(d);
106                 },
107             },
108             {
109                 text: 'Cancel',
110                 click: ()=>{ d.dialog('destroy'); },
111             },
112             {
113                 icon: 'ui-icon-disk',
114                 text: 'OK',
115                 click: () => {
116                     save_list(d);
117                 },
118             },
119         ],
120     });
121 }
122 function delete_list(dlg) {
123     // TODO: store all data including list items in a "Deleted"
124     // pop-up with an "Undo" link that can be used to restore the list
125     var lists_ver = lists_version;
126     $.ajax( selected_list.data('lsl-uri'),
127         { type: 'DELETE' }
128     )
129     .done((d)=>{
130         lists_version = lists_ver + 1;
131         var deleted_list = selected_list;
132
133         var new_selected = deleted_list.next();
134         if (new_selected.length) {
135             select_list(new_selected)
136         }
137         else {
138             new_selected = deleted_list.prev();
139             if (new_selected.length) {
140                 select_list(new_selected);
141             }
142             else {
143                 $('#page').removeClass('have-lists');
144             }
145         }
146
147         deleted_list.remove();
148         dlg.dialog('destroy');
149         got_lists_version(d.lists_version);
150     });
151         dlg.dialog('destroy');
152         got_lists_version(d.lists_version);
153     });
154 }
155 function load_lists() {
156     return $.get(uri_base + '/api/v1/list')
157     .always(()=>{
158         var splash = $('#splash');
159         if (splash.length) {
160             var dur = splash.css('transition-duration');
161             if (dur && dur.endsWith('s')) {
162                 dur = 1000 * parseFloat(dur.substring(0, dur.length-1));
163             }
164             else
165                 dur = 1000;
166
167             var now = Date.now();
168             window.setTimeout(() => {
169                 splash.addClass('done');
170                 debug('scheduling splash removal in '+dur+'ms');
171                 window.setTimeout(()=>{ splash.remove(); }, dur);
172             },
173                 Math.max(0, 500 - (now - start_time))
174             );
175         }
176     })
177     .done(data => {
178         lists_version = data.lists_version;
179
180         var lists = $('#lists');
181         lists.find('>li').addClass('old');
182
183         $.each(data.lists, (i, list) => {
184             var list_id = uri_id(list.uri);
185             var existing = lists.find('li#list-'+list_id);
186             if (existing.length) {
187                 existing.data('lsl-version', list.version)
188                 .data('lsl-name', list.name)
189                 .removeClass('old');
190                 existing.find('span.list-name').text(list.name);
191             }
192             else {
193                 var list_item = $('<li>')
194                     .prop('id', 'list-'+list_id)
195                     .data('lsl-uri', list.uri)
196                     .data('lsl-version', list.version)
197                     .data('lsl-name', list.name)
198                     .append(
199                         $('<span class="list-name">')
200                         .text(list.name)
201                     );
202                 lists.append(list_item);
203             }
204         });
205
206         if (!selected_list || selected_list.hasClass('old'))
207             select_list(lists.find('>li').eq(0));
208
209         lists.find('li.old').remove();
210     });
211 }
212 function new_list_submission_done(data) {
213     $('input[name="list_name"]').val('').trigger('change');
214
215     if (data.lists_version != lists_version) {
216         load_lists()
217         .done((d)=>{
218             var new_list = $('li#list-'+uri_id(data.uri));
219             if (new_list.length)
220                 select_list(new_list);
221         });
222         return;
223     }
224
225     console.log("TODO: easy-add new list");
226
227 }
228 function handle_new_list_submission(){
229     $.post(uri_base + '/api/v1/list',
230         JSON.stringify({name:$('input[name="list_name"]').val()}))
231     .done(new_list_submission_done);
232     return false;
233 }
234 function new_list_item_submission_done(data) {
235     got_lists_version(data.lists_version);
236     got_list_version(data.list_version);
237
238     var item_data = selected_list.data('items');
239
240     var new_item = {
241         description: $('#new-list-item input[type="text"]').val().trim(),
242         done: $('#new-list-item input[type="checkbox"]').prop('checked'),
243         version: 1,
244     };
245     item_data.items.push(new_item);
246     item_data.version = data.version;
247     add_list_item(new_item);
248
249     $('#new-list-item input').val('');
250 }
251 function handle_new_list_item_submission(){
252     var description = $('#new-list-item input[type="text"]').val().trim();
253     if (description.length == 0) return;
254
255     $.post(selected_list.data('lsl-uri'),
256         JSON.stringify({
257             description: description,
258             done: $('#new-list-item input[type="checkbox"]').prop('checked')
259         }),
260     )
261     .done(new_list_item_submission_done);
262 }
263 function handle_list_item_state_changed(ev) {
264     var item = $(ev.target).closest('li');
265     var cb = item.find('input[type="checkbox"]');
266     var item_data = item.data('item');
267
268     $.ajax(item_data.uri,
269         {   type: 'PUT',
270             data: JSON.stringify({
271                 version: item_data.version,
272                 done: cb.prop('checked')})
273         }
274     )
275     .done(function(resp){
276         item_data.version = resp.version;
277         got_lists_version(resp.lists_version);
278         got_list_version(resp.list_version);
279     });
280 }
281 $(function(){
282     uri_base = $('#page').attr('lsl-uri-base');
283     environment = $('#page').attr('lsl-environment');
284     devel_env = environment == 'development';
285
286     $(document).ajaxStart(function(){
287         $(document).addClass('blocked');
288         window.setTimeout(
289             function() {
290                 $(document).addClass('busy');
291             }
292         );
293     });
294     $(document).ajaxStop(function(){
295         $(document).removeClass('busy');
296         window.setTimeout(
297             function() {
298                 $(document).removeClass('blocked');
299             },
300             1000 );
301     });
302     $.ajaxSetup({contentType: 'application/json'});
303     $('button, input[type="submit"], input[type="reset"]').each(function(){
304         var class_prop = $(this).prop('class');
305         var icon_classes = class_prop.match(ui_icon_class_re);
306         $(this).button({icon: icon_classes?icon_classes[0]:null});
307     });
308
309     $('#new-list-sidebar-item button').on('click', handle_new_list_submission);
310     $('#new-list-sidebar-item input').on('keypress', function(ev) {
311         if (13 == ev.keyCode) {
312             handle_new_list_submission();
313             return false;
314         }
315
316         return true;
317     });
318     $('#lists')
319         .on('click', 'li', ev=>{
320             select_list($(ev.target).closest('li'));
321         });
322     $('#list-edit-trigger').on('click', ev => {
323         edit_list();
324         return false;
325     });
326     $('#new-list-item button').on('click', handle_new_list_item_submission);
327     $('#new-list-item input').on('keypress', ev => {
328         if (13 == ev.keyCode) {
329             handle_new_list_item_submission();
330             return false;
331         }
332         return true;
333     });
334     $('#list-items').on('change', '.list-item-row input[type="checkbox"]', handle_list_item_state_changed);
335     load_lists();
336 });
337 })();