1
1
import { v4 as randomUUID } from 'uuid' ;
2
- import { ActionButton , ActionType , type ViewModel } from '.' ;
2
+ import { ActionButton , ActionType , TodoList , type ViewModel } from '.' ;
3
3
import { Item } from './Item' ;
4
4
import { EditItemModal } from 'src/component' ;
5
5
import { moment } from 'obsidian' ;
6
6
import { processExtensions , ExtensionType } from 'src/extension' ;
7
- import { updateTodoItemFromEl } from 'src/stateEditor' ;
7
+ import { update , updateTodoItemFromEl } from 'src/stateEditor' ;
8
8
import { ActionButtonV2 } from './ActionButtonV2' ;
9
9
import { DEFAULT_SETTINGS } from 'src/settings' ;
10
10
import { SETTINGS_READ_ONLY } from 'src/main' ;
11
11
12
+ const DOUBLE_TAP_DELAY_MS = 300 ;
13
+ const LONG_PRESS_THRESHOLD_MS = 600 ;
14
+
12
15
export default class TodoItem extends Item implements ViewModel {
13
16
static HTML_CLS = 'todotxt-item' ;
14
17
static ID_REGEX = / ^ i t e m - \S + - ( \d + ) $ / ;
15
18
16
19
#id: string ;
20
+ private _lastTap : number ;
21
+ private _longPressTimer : NodeJS . Timeout ;
17
22
18
23
constructor ( text : string ) {
19
24
super ( text ) ;
@@ -54,7 +59,7 @@ export default class TodoItem extends Item implements ViewModel {
54
59
55
60
itemDiv . append (
56
61
this . buildDescriptionHtml ( ) ,
57
- this . buildActionsHtml ( ) ,
62
+ this . buildActionsHtml ( itemDiv ) ,
58
63
) ;
59
64
60
65
return itemDiv ;
@@ -201,39 +206,43 @@ export default class TodoItem extends Item implements ViewModel {
201
206
}
202
207
203
208
// @ts -ignore
204
- if ( ! app . isMobile && ! this . complete ( ) ) {
205
- // WYSIWYG editting
206
- description . setAttr ( 'tabindex' , 0 ) ;
207
- description . contentEditable = 'true' ;
208
-
209
- description . addEventListener ( 'focus' , e => {
210
- description . spellcheck = true ;
211
- } ) ;
212
-
213
- description . addEventListener ( 'blur' , e => {
214
- description . spellcheck = false ;
215
- if ( description . textContent ) {
216
- description . textContent = description . textContent . trimEnd ( ) ;
217
- }
218
- if ( description . textContent !== this . getBody ( ) ) {
219
- this . setBody ( description . textContent ?? '' ) ;
220
- updateTodoItemFromEl ( description , this ) ;
221
- }
222
- } ) ;
223
-
224
- description . addEventListener ( 'keydown' , e => {
225
- // console.log(e.key)
226
- if ( e . key === 'Enter' ) {
227
- e . preventDefault ( ) ;
228
- description . blur ( ) ;
229
- } else if ( e . key === 'Escape' ) {
230
- e . preventDefault ( ) ;
231
- description . textContent = this . getBody ( ) ;
232
- description . blur ( ) ;
233
- } else if ( e . key === 'ArrowDown' || e . key === 'ArrowUp' ) {
234
- e . preventDefault ( ) ;
235
- }
236
- } ) ;
209
+ if ( app . isMobile ) {
210
+ this . addMobileEventListeners ( description ) ;
211
+ } else {
212
+ if ( ! this . complete ( ) ) {
213
+ // WYSIWYG editting
214
+ description . setAttr ( 'tabindex' , 0 ) ;
215
+ description . contentEditable = 'true' ;
216
+
217
+ description . addEventListener ( 'focus' , e => {
218
+ description . spellcheck = true ;
219
+ } ) ;
220
+
221
+ description . addEventListener ( 'blur' , e => {
222
+ description . spellcheck = false ;
223
+ if ( description . textContent ) {
224
+ description . textContent = description . textContent . trimEnd ( ) ;
225
+ }
226
+ if ( description . textContent !== this . getBody ( ) ) {
227
+ this . setBody ( description . textContent ?? '' ) ;
228
+ updateTodoItemFromEl ( description , this ) ;
229
+ }
230
+ } ) ;
231
+
232
+ description . addEventListener ( 'keydown' , e => {
233
+ // console.log(e.key)
234
+ if ( e . key === 'Enter' ) {
235
+ e . preventDefault ( ) ;
236
+ description . blur ( ) ;
237
+ } else if ( e . key === 'Escape' ) {
238
+ e . preventDefault ( ) ;
239
+ description . textContent = this . getBody ( ) ;
240
+ description . blur ( ) ;
241
+ } else if ( e . key === 'ArrowDown' || e . key === 'ArrowUp' ) {
242
+ e . preventDefault ( ) ;
243
+ }
244
+ } ) ;
245
+ }
237
246
}
238
247
239
248
return description ;
@@ -295,11 +304,12 @@ export default class TodoItem extends Item implements ViewModel {
295
304
}
296
305
}
297
306
298
- private buildActionsHtml ( ) : HTMLSpanElement {
307
+ private buildActionsHtml ( el : HTMLElement ) : HTMLSpanElement {
299
308
const actions = document . createElement ( 'span' ) ;
300
309
actions . className = 'todotxt-item-actions' ;
301
310
302
- if ( this . priority ( ) === null && ! this . complete ( ) ) {
311
+ // @ts -ignore
312
+ if ( ! app . isMobile && this . priority ( ) === null && ! this . complete ( ) ) {
303
313
const prioritizeBtn = new ActionButtonV2 (
304
314
ActionType . STAR ,
305
315
e => this . prioritize ( e ) ,
@@ -308,7 +318,6 @@ export default class TodoItem extends Item implements ViewModel {
308
318
}
309
319
310
320
actions . append (
311
- new ActionButton ( ActionType . EDIT , EditItemModal . ID , this . id ) . render ( ) ,
312
321
new ActionButton ( ActionType . DEL , 'todotxt-delete-item' , this . id ) . render ( ) ,
313
322
) ;
314
323
@@ -346,9 +355,45 @@ export default class TodoItem extends Item implements ViewModel {
346
355
return select ;
347
356
}
348
357
349
- private prioritize ( e : MouseEvent ) {
358
+ private prioritize ( e : Event ) {
350
359
const t = e . target as SVGElement ;
351
360
this . setPriority ( SETTINGS_READ_ONLY . defaultPriority ?? DEFAULT_SETTINGS . defaultPriority ) ;
352
361
updateTodoItemFromEl ( t , this ) ;
353
362
}
363
+
364
+ private addMobileEventListeners ( el : HTMLElement ) {
365
+ const prioritizeOnDoubleTap = ( e : Event ) => {
366
+ const currentTime = new Date ( ) . getTime ( ) ;
367
+ const tapLength = currentTime - this . _lastTap ;
368
+ if ( tapLength < DOUBLE_TAP_DELAY_MS && tapLength > 0 ) {
369
+ e . preventDefault ( ) ;
370
+ if ( ! this . priority ( ) ) {
371
+ this . prioritize ( e ) ;
372
+ }
373
+ }
374
+ this . _lastTap = currentTime ;
375
+ } ;
376
+ el . addEventListener ( 'touchend' , prioritizeOnDoubleTap ) ;
377
+
378
+ // edit on long press
379
+ el . addEventListener ( 'touchend' , ( ) => clearTimeout ( this . _longPressTimer ) ) ;
380
+ el . addEventListener ( 'touchstart' , ( ) => {
381
+ this . _longPressTimer = setTimeout ( ( ) => {
382
+ this . openEditModal ( el ) ;
383
+ } , LONG_PRESS_THRESHOLD_MS ) ;
384
+ } ) ;
385
+ } ;
386
+
387
+ private openEditModal ( el : HTMLElement ) {
388
+ const editModal = new EditItemModal ( this . asInputText ( ) , el , ( result ) => {
389
+ const { todoList, from, to } = TodoList . from ( el ) ;
390
+ if ( this . toString ( ) === result . toString ( ) ) return ;
391
+ todoList . removeItem ( this . idx ! ) ;
392
+ todoList . add ( result ) ;
393
+ update ( from , to , todoList ) ;
394
+ } ) ;
395
+ editModal . open ( ) ;
396
+ editModal . textComponent . inputEl . select ( ) ;
397
+ editModal . textComponent . inputEl . selectionStart = editModal . item . asInputText ( ) . length ;
398
+ }
354
399
}
0 commit comments