@@ -9,10 +9,11 @@ window.LIST_EVENTS = {
9
9
DELETE : 'list:delete' ,
10
10
}
11
11
12
- function dispatchTaskEvent ( eventName , task , isDone ) {
12
+ function dispatchTaskEvent ( eventName , task , isDone , target ) {
13
+ target = target || document
13
14
const taskChangeEvent = new CustomEvent ( eventName , { detail : { task : task , done : isDone } } )
14
15
15
- document . dispatchEvent ( taskChangeEvent )
16
+ target . dispatchEvent ( taskChangeEvent )
16
17
}
17
18
18
19
/**
@@ -32,7 +33,7 @@ class TaskControl extends HTMLElement {
32
33
33
34
get form ( ) { return this . querySelector ( 'form' ) }
34
35
35
- get taskCategory ( ) { return Sortable . utils . closest ( this , `. ${ TaskCategory . TAG } ` ) }
36
+ get taskCategory ( ) { return Sortable . utils . closest ( this , TaskCategory . TAG ) }
36
37
37
38
setup ( ) {
38
39
this . on ( this . form , 'submit' , this . _submitHandler . bind ( this ) )
@@ -46,6 +47,7 @@ class TaskControl extends HTMLElement {
46
47
47
48
taskItem = this . taskCategory . addTask ( taskItem )
48
49
dispatchTaskEvent ( TASK_EVENTS . CHANGE , task , false )
50
+ dispatchTaskEvent ( TASK_EVENTS . CHANGE , task , false , this . taskCategory )
49
51
50
52
return taskItem
51
53
}
@@ -94,6 +96,8 @@ class TaskItem extends HTMLElement {
94
96
95
97
get task ( ) { return this . getAttribute ( 'name' ) }
96
98
99
+ get taskCategory ( ) { return Sortable . utils . closest ( this , TaskCategory . TAG ) }
100
+
97
101
setup ( ) {
98
102
if ( this . hasAttribute ( 'done' ) && this . getAttribute ( 'done' ) !== 'false' ) {
99
103
this . done = true
@@ -111,12 +115,14 @@ class TaskItem extends HTMLElement {
111
115
112
116
// order here is important, bubble up event before changing internal state
113
117
dispatchTaskEvent ( TASK_EVENTS . CHANGE , this . name , checked )
118
+ dispatchTaskEvent ( TASK_EVENTS . CHANGE , this . name , checked , this . taskCategory )
114
119
this . done = checked
115
120
}
116
121
117
122
_deleteHandler ( ) {
118
123
this . remove ( )
119
124
dispatchTaskEvent ( TASK_EVENTS . DELETE , this . name )
125
+ dispatchTaskEvent ( TASK_EVENTS . DELETE , this . name , checked , this . taskCategory )
120
126
}
121
127
}
122
128
@@ -142,6 +148,10 @@ class TaskCategory extends HTMLElement {
142
148
143
149
get deleteButton ( ) { return this . querySelector ( '.delete' ) }
144
150
151
+ get progress ( ) { return this . querySelector ( 'progress' ) }
152
+
153
+ get progressLabel ( ) { return this . querySelector ( '.progress-label' ) }
154
+
145
155
get name ( ) { return this . getAttribute ( 'name' ) . trim ( ) }
146
156
147
157
get nameLabel ( ) { return this . querySelector ( '.category--name' ) }
@@ -151,15 +161,10 @@ class TaskCategory extends HTMLElement {
151
161
get tasksContainer ( ) { return this . querySelector ( '.tasks-container' ) }
152
162
153
163
get tasks ( ) {
154
- const _tasks = [ ]
155
-
156
- this . querySelectorAll ( TaskItem . TAG )
157
- . forEach ( ( task ) => _tasks . push ( { done : ! ! task . done , name : task . name } ) )
158
-
159
- return _tasks ;
164
+ return Array . from ( this . querySelectorAll ( TaskItem . TAG ) )
165
+ . map ( task => ( { done : ! ! task . done , name : task . name } ) )
160
166
}
161
167
162
-
163
168
static addList ( target ) {
164
169
const listName = window . prompt ( NEW_LIST_PROMPT )
165
170
@@ -179,6 +184,9 @@ class TaskCategory extends HTMLElement {
179
184
180
185
this . on ( this . colorPicker , 'change' , this . _colorChangeHandler . bind ( this ) )
181
186
this . on ( this . deleteButton , 'click' , this . _deleteHandler . bind ( this ) )
187
+ this . on ( this , TASK_EVENTS . CHANGE , this . _updateProgress . bind ( this ) )
188
+ this . on ( this , TASK_EVENTS . DELETE , this . _updateProgress . bind ( this ) )
189
+ this . _updateProgress ( )
182
190
}
183
191
184
192
addTask ( taskItem ) {
@@ -196,6 +204,18 @@ class TaskCategory extends HTMLElement {
196
204
document . dispatchEvent ( new CustomEvent ( LIST_EVENTS . DELETE , { detail : { name : this . name } } ) )
197
205
}
198
206
}
207
+
208
+ _updateProgress ( ev ) {
209
+ // give a few milliseconds to the browser to update elements
210
+ window . setTimeout ( ( ) => {
211
+ const _tasks = this . tasks
212
+ const doneAmount = _tasks . filter ( task => task . done ) . length
213
+ const percent = ( doneAmount / _tasks . length ) * 100
214
+
215
+ this . progress . value = percent
216
+ this . progressLabel . textContent = `${ percent . toFixed ( 2 ) } %`
217
+ } , 100 )
218
+ }
199
219
}
200
220
201
221
class ColorPicker extends HTMLElement {
@@ -268,11 +288,11 @@ class ColorPicker extends HTMLElement {
268
288
}
269
289
}
270
290
271
- class BackendSettings extends HTMLElement {
291
+ class TodoSettings extends HTMLElement {
272
292
static EXTENDED_ELEMENT = 'article'
273
- static TAG = 'backend -settings'
274
- static TEMPLATE_ID = 'backendsettings -template'
275
- static BACKEND_CHANGE_EVENT = 'backend :change'
293
+ static TAG = 'todo -settings'
294
+ static TEMPLATE_ID = 'todo-settings -template'
295
+ static SETTINGS_CHANGE_EVENT = 'settings :change'
276
296
277
297
get form ( ) { return this . querySelector ( 'form' ) }
278
298
@@ -288,6 +308,9 @@ class BackendSettings extends HTMLElement {
288
308
get passphrase ( ) { return this . querySelector ( 'form textarea[name=backend_passphrase]' ) }
289
309
set passphrase ( newVal ) { this . querySelector ( 'form textarea[name=backend_passphrase]' ) . value = newVal }
290
310
311
+ get navCompact ( ) { return this . querySelector ( '#nav_compact' ) }
312
+ get tasksProgress ( ) { return this . querySelector ( '#tasks_progress' ) }
313
+
291
314
/**
292
315
* Setup controls reactivity:
293
316
*
@@ -300,10 +323,9 @@ class BackendSettings extends HTMLElement {
300
323
*/
301
324
setup ( ) {
302
325
this . setupAutoStorage ( )
303
- this . on ( this . url , 'input' , this . _inputHandler . bind ( this ) )
304
- this . on ( this . username , 'input' , this . _inputHandler . bind ( this ) )
305
- this . on ( this . passphrase , 'input' , this . _inputHandler . bind ( this ) )
306
- this . on ( this . enabled , 'input' , this . _inputHandler . bind ( this ) )
326
+ Array . from ( this . querySelectorAll ( 'input' ) ) . forEach ( ( el ) => {
327
+ this . on ( el , 'input' , this . _inputHandler . bind ( this ) )
328
+ } )
307
329
this . on ( this . form , 'submit' , this . _submitHandler . bind ( this ) )
308
330
}
309
331
@@ -324,16 +346,33 @@ class BackendSettings extends HTMLElement {
324
346
325
347
emitConfig ( ) {
326
348
const payload = {
327
- url : this . url . value ,
328
- username : this . username . value ,
329
- passphrase : this . passphrase . value ,
330
- enabled : ! ! this . enabled . checked ,
349
+ backend : {
350
+ enabled : ! ! this . enabled . checked ,
351
+ passphrase : this . passphrase . value ,
352
+ username : this . username . value ,
353
+ url : this . url . value ,
354
+ } ,
355
+ nav : {
356
+ compact : this . navCompact . checked ,
357
+ } ,
358
+ tasks : {
359
+ progress : this . tasksProgress . checked ,
360
+ } ,
331
361
}
332
- const newEv = new CustomEvent ( this . constructor . BACKEND_CHANGE_EVENT , { detail : payload } )
362
+ const newEv = new CustomEvent ( this . constructor . SETTINGS_CHANGE_EVENT , { detail : payload } )
333
363
334
364
document . dispatchEvent ( newEv )
335
365
}
336
366
367
+ applyConfig ( config ) {
368
+ this . enabled = config . backend ?. enabled
369
+ this . passphrase = config . backend ?. passphrase
370
+ this . url = config . backend ?. url
371
+ this . username = config . backend ?. username
372
+ this . navCompact . checked = ! ! config . nav ?. compact
373
+ this . tasksProgress . checked = ! ! config . tasks ?. progress
374
+ }
375
+
337
376
_inputHandler ( ev ) {
338
377
this . emitConfig ( )
339
378
}
@@ -411,7 +450,7 @@ class LogMessage extends HTMLElement {
411
450
412
451
function defineComponents ( ) {
413
452
const components = [
414
- BackendSettings ,
453
+ TodoSettings ,
415
454
ColorPicker ,
416
455
LogMessage ,
417
456
TaskCategory ,
0 commit comments