]> git.ktnx.net Git - lsl.git/blob - public/javascripts/lsl.js
identify lists by their id (part of the URI)
[lsl.git] / public / javascripts / lsl.js
1 "use strict";
2 (function(){
3 var ui_icon_class_re = new RegExp('\\bui-icon-\\S+\\b');
4 var uri_id_re = new RegExp('/(\\d+)$');
5 var uri_base;   // filled on page load from an HTML attribute
6 var lists_version = -1;
7 var lists = [];
8 var selected_list;
9
10 function uri_id(uri) {
11     var m = uri.match(uri_id_re);
12     return m ? m[1] : null;
13 }
14 function add_list_item(data) {
15     var item = $('<li>').addClass('list-item-row').data('item', data);
16     var cb = $('<input type="checkbox">');
17     if (data.done) cb.prop('checked', true);
18     item.append(cb);
19     item.append($('<span class="description">').text(data.description || ''));
20     item.append($('<span class="edit-trigger">').text('…'));
21
22     $('#list-items').append(item).addClass('have-list-items');
23 }
24 function got_lists_version(new_version) {
25     if (new_version != lists_version)
26         window.setTimeout(load_lists);
27 }
28 function got_list_version(new_version) {
29     if (new_version != selected_list.attr('lsl-version'))
30         window.setTimeout(
31             () => load_list_items(selected_list.data('lsl-uri'), selected_list));
32 }
33 function load_list_items(uri, target) {
34     $.get(uri)
35     .done(item_data => {
36         target.data('items', item_data);
37
38         // TODO: merge new items into existing ones
39         // keep track of the last existing item, and append new one
40         // after it, prepending if there is no last existing item
41         // the newly prepended/inserted item becomes the last existing
42         var item_list = $('#list-items').empty().removeClass('have-list-items');
43
44         $.each(item_data.items, (i,item) => {
45             add_list_item(item);
46         });
47
48         got_lists_version(item_data.lists_version);
49     });
50 }
51 function select_list(new_selected_list) {
52     if (new_selected_list && selected_list
53         && new_selected_list.length && selected_list.length
54         && new_selected_list.get(0) == selected_list.get(0)
55     )
56         return;
57
58     if (new_selected_list && !new_selected_list.length)
59         new_selected_list = null;
60
61     $('#page').toggleClass('have-lists', !!new_selected_list);
62
63     if (selected_list)
64         selected_list.removeClass('selected');
65
66     if (new_selected_list) {
67         load_list_items(new_selected_list.data('lsl-uri'), new_selected_list);
68         new_selected_list.addClass('selected');
69         $('#selected-list-name').text(new_selected_list.data('lsl-name'));
70     }
71
72     selected_list = new_selected_list;
73 }
74 function load_lists() {
75     $.get(uri_base + '/api/v1/list')
76     .done(data => {
77         lists_version = data.lists_version;
78
79         var lists = $('#lists');
80         lists.find('>li').addClass('old');
81
82         $.each(data.lists, (i, list) => {
83             var list_id = uri_id(list.uri);
84             var existing = lists.find('li#list-'+list_id);
85             if (existing.length) {
86                 existing.data('lsl-version', list.version)
87                 .data('lsl-name', list.name)
88                 .text(list.name)
89                 .removeClass('old');
90             }
91             else {
92                 var list_item = $('<li>')
93                     .prop('id', 'list-'+list_id)
94                     .data('lsl-uri', list.uri)
95                     .data('lsl-version', list.version)
96                     .data('lsl-name', list.name)
97                     .text(list.name);
98                 lists.append(list_item);
99             }
100         });
101
102         if (!selected_list || selected_list.hasClass('old'))
103             select_list(lists.find('>li').eq(0));
104
105         lists.find('li.old').remove();
106     });
107 }
108 function new_list_submission_done(data) {
109     if (data.lists_version != lists_version) {
110         load_lists();
111         return;
112     }
113
114     console.log("TODO: easy-add new list");
115
116 }
117 function handle_new_list_submission(){
118     $.post(uri_base + '/api/v1/list',
119         JSON.stringify({name:$('input[name="list_name"]').val()}))
120     .done(new_list_submission_done);
121     return false;
122 }
123 function new_list_item_submission_done(data) {
124     got_lists_version(data.lists_version);
125     got_list_version(data.list_version);
126
127     var item_data = selected_list.data('items');
128
129     var new_item = {
130         description: $('#new-list-item input[type="text"]').val().trim(),
131         done: $('#new-list-item input[type="checkbox"]').prop('checked'),
132         version: 1,
133     };
134     item_data.items.push(new_item);
135     item_data.version = data.version;
136     add_list_item(new_item);
137
138     $('#new-list-item input').val('');
139 }
140 function handle_new_list_item_submission(){
141     var description = $('#new-list-item input[type="text"]').val().trim();
142     if (description.length == 0) return;
143
144     $.post(selected_list.data('lsl-uri'),
145         JSON.stringify({
146             description: description,
147             done: $('#new-list-item input[type="checkbox"]').prop('checked')
148         }),
149     )
150     .done(new_list_item_submission_done);
151 }
152 function handle_list_item_state_changed(ev) {
153     var item = $(ev.target).closest('li');
154     var cb = item.find('input[type="checkbox"]');
155     var item_data = item.data('item');
156
157     $.ajax(item_data.uri,
158         {   type: 'PUT',
159             data: JSON.stringify({
160                 version: item_data.version,
161                 done: cb.prop('checked')})
162         }
163     )
164     .done(function(resp){
165         item_data.version = resp.version;
166         got_lists_version(resp.lists_version);
167         got_list_version(resp.list_version);
168     });
169 }
170 $(function(){
171     uri_base = $('#page').attr('lsl-uri-base');
172     $(document).ajaxStart(function(){
173         $(document).addClass('blocked');
174         window.setTimeout(
175             function() {
176                 $(document).addClass('busy');
177             }
178         );
179     });
180     $(document).ajaxStop(function(){
181         $(document).removeClass('busy');
182         window.setTimeout(
183             function() {
184                 $(document).removeClass('blocked');
185             },
186             1000 );
187     });
188     $.ajaxSetup({contentType: 'application/json'});
189     $('button, input[type="submit"], input[type="reset"]').each(function(){
190         var class_prop = $(this).prop('class');
191         var icon_classes = class_prop.match(ui_icon_class_re);
192         $(this).button({icon: icon_classes?icon_classes[0]:null});
193     });
194
195     $('#new-list-sidebar-item button').on('click', handle_new_list_submission);
196     $('#new-list-sidebar-item input').on('keypress', function(ev) {
197         if (13 == ev.keyCode) {
198             handle_new_list_submission();
199             return false;
200         }
201
202         return true;
203     });
204     $('ul#lists').on('click', 'li', ev=>{
205         select_list($(ev.target));
206     });
207     $('#new-list-item button').on('click', handle_new_list_item_submission);
208     $('#new-list-item input').on('keypress', ev => {
209         if (13 == ev.keyCode) {
210             handle_new_list_item_submission();
211             return false;
212         }
213         return true;
214     });
215     $('#list-items').on('change', '.list-item-row input[type="checkbox"]', handle_list_item_state_changed);
216     load_lists();
217 });
218 })();