ncounter.git

git clone https://git.crispbyte.dev/ncounter.git

commit
cea4f35
parent
e42f365
author
CheddarCrisp
date
2020-03-05 02:53:18 +0100 CET
Add validation to forms
Fix values being treated as strings
3 files changed,  +64, -38
M src/ncounter/App.svelte
+18, -12
 1@@ -11,14 +11,16 @@
 2 </div>
 3 {#if showAddDialog}
 4 <div class="dialog">
 5-    <div class="dialog-content">
 6-        <label>Name<input type="text" bind:value={newCounter.title} use:focus/></label>
 7-        <label>Initial Value<input type="text" inputmode="decimal" bind:value={newCounter.initialValue} /></label>
 8-        <label>Target<input type="text" inputmode="decimal" bind:value={newCounter.max} /></label>
 9+    <form class="dialog-content" novalidate bind:this={ dialogForm }>
10+        <label>Counter Name<input type="text" required bind:value={newCounter.title} use:focus/></label>
11+        <label>Initial Value<input type="text" required pattern="(0|([1-9]\d*))(\.\d+)?" inputmode="decimal" bind:value={newCounter.initialValue} /></label>
12+        <label>Target<input type="text" pattern="(0|([1-9]\d*))(\.\d+)?" inputmode="decimal" bind:value={newCounter.max} /></label>
13         <label>Save history<input type="checkbox" bind:checked={newCounter.saveHistory} /></label>
14-        <button on:click={ () => { showAddDialog = false; } }>Cancel</button>
15-        <button class="ok" on:click={ add }>OK</button>
16-    </div>
17+        <div class="buttons">
18+            <button class="ok" on:click|preventDefault={ add }>OK</button>
19+            <button on:click|preventDefault={ () => { showAddDialog = false; } }>Cancel</button>
20+        </div>
21+    </form>
22 </div>
23 {/if}
24 {#if showAbout}
25@@ -32,6 +34,7 @@ import { counters } from './db.js';
26 let showAddDialog = false;
27 let showAbout = false;
28 let newCounter = null;
29+let dialogForm = null;
30 
31 function focus(node){
32     node.focus();
33@@ -41,6 +44,7 @@ function showAdd(){
34     newCounter = {
35         title: '',
36         initialValue: 0,
37+        max: '',
38         saveHistory: false,
39         history: []
40     }
41@@ -49,9 +53,15 @@ function showAdd(){
42 }
43 
44 function add(){
45+    if(!dialogForm.checkValidity()) {
46+        dialogForm.removeAttribute('novalidate');
47+        return;
48+    }
49+
50     const counter = {
51         ...newCounter,
52-        value: newCounter.initialValue
53+        max: newCounter.max !== '' ? +newCounter.max : null,
54+        value: +newCounter.initialValue
55     }
56 
57     counters.add(counter);
58@@ -60,10 +70,6 @@ function add(){
59 }
60 </script>
61 <style lang="scss">
62-    .ok {
63-        margin-left: auto;
64-    }
65-
66     .app {
67         display: flex;
68         flex-direction: column;
M src/ncounter/Counter.svelte
+39, -26
  1@@ -1,7 +1,7 @@
  2 <div class="counter">
  3     <header>{ counter.title }</header>
  4     <span class="value">{ counter.value }</span>
  5-    {#if counter.max}
  6+    {#if counter.max !== null}
  7     <MyProgress value={ counter.value } max={ counter.max }></MyProgress>
  8     {/if}
  9     <div class="controls">
 10@@ -16,24 +16,28 @@
 11     </div>
 12     {#if showValueDialog}
 13     <div class="dialog">
 14-        <div class="dialog-content">
 15+        <form class="dialog-content" novalidate bind:this={ dialogForm }>
 16             <h1>{ showIncrement ? "Add" : "Set" }</h1>
 17-            <input class="dialog-value" type="text" inputmode="decimal" bind:value={ dialogValue } use:focus />
 18-            <button on:click={ dialogCancel }>Cancel</button>
 19-            <button class="ok" on:click={ dialogDone }>OK</button>
 20-        </div>
 21+            <input class="dialog-value" type="text" required pattern="(0|([1-9]\d*))(\.\d+)?" inputmode="decimal" bind:value={ dialogValue } use:focus />
 22+            <div class="buttons">
 23+                <button class="ok" on:click|preventDefault={ dialogDone }>OK</button>
 24+                <button on:click|preventDefault={ dialogCancel }>Cancel</button>
 25+            </div>
 26+        </form>
 27     </div>
 28     {/if}
 29     {#if showEditDialog}
 30     <div class="dialog">
 31-        <div class="dialog-content">
 32-            <label>Name<input type="text" bind:value={editingCounter.title} use:focus/></label>
 33-            <label>Initial Value<input type="text" inputmode="decimal" bind:value={editingCounter.initialValue} /></label>
 34-            <label>Target<input type="text" inputmode="decimal" bind:value={editingCounter.max} /></label>
 35+        <form class="dialog-content" novalidate bind:this={ dialogForm }>
 36+            <label>Name<input type="text" required bind:value={editingCounter.title} use:focus/></label>
 37+            <label>Initial Value<input type="text" required pattern="(0|([1-9]\d*))(\.\d+)?" inputmode="decimal" bind:value={editingCounter.initialValue} /></label>
 38+            <label>Target<input type="text" pattern="(0|([1-9]\d*))(\.\d+)?" inputmode="decimal" bind:value={editingCounter.max} /></label>
 39             <label>Save history<input type="checkbox" bind:checked={editingCounter.saveHistory} /></label>
 40-            <button on:click={ () => { showEditDialog = false; } }>Cancel</button>
 41-            <button class="ok" on:click={ finishEdit }>OK</button>
 42-        </div>
 43+            <div class="buttons">
 44+                <button class="ok" on:click|preventDefault={ finishEdit }>OK</button>
 45+                <button on:click|preventDefault={ () => { showEditDialog = false; } }>Cancel</button>
 46+            </div>
 47+        </form>
 48     </div>
 49     {/if}
 50     {#if showHistory}
 51@@ -56,6 +60,7 @@ let showSet;
 52 let showEditDialog;
 53 let editingCounter;
 54 let showHistory;
 55+let dialogForm;
 56 
 57 $: showValueDialog = showIncrement || showSet;
 58 
 59@@ -68,14 +73,23 @@ function update(newCounter){
 60 }
 61 
 62 function startEdit(e){
 63-    e.stopPropagation();
 64-
 65-    editingCounter = {...counter};
 66+    editingCounter = { ...counter };
 67     showEditDialog = true;
 68 }
 69 
 70 function finishEdit(){
 71-    update(editingCounter);
 72+    if(!dialogForm.checkValidity()) {
 73+        dialogForm.removeAttribute('novalidate');
 74+        return;
 75+    }
 76+
 77+    const updatedCounter = {
 78+        ...editingCounter,
 79+        max: editingCounter.max !== null && editingCounter.max !== '' ? +editingCounter.max : null,
 80+        value: +editingCounter.value
 81+    }
 82+
 83+    update(updatedCounter);
 84     showEditDialog = false;
 85 }
 86 
 87@@ -85,12 +99,17 @@ function dialogCancel(){
 88 }
 89 
 90 function dialogDone(){
 91+    if(!dialogForm.checkValidity()) {
 92+        dialogForm.removeAttribute('novalidate');
 93+        return;
 94+    }
 95+
 96     const newCounter = showIncrement ? {
 97         ...counter,
 98-        value: counter.value + dialogValue
 99+        value: +counter.value + +dialogValue
100     } : {
101         ...counter,
102-        value: dialogValue
103+        value: +dialogValue
104     }
105 
106     update(newCounter);
107@@ -101,12 +120,10 @@ function dialogDone(){
108 }
109 
110 function reset(e){
111-    e.stopPropagation();
112-
113     if(confirm(`Reset ${counter.title}?`)){
114         const newCounter = {
115             ...counter,
116-            value: counter.initialValue
117+            value: +counter.initialValue
118         }
119 
120         update(newCounter);
121@@ -166,8 +183,4 @@ header {
122     width: 100%;
123     margin: 5px 0;
124 }
125-
126-.ok {
127-    margin-left: auto;
128-}
129 </style>
M src/ncounter/site.css
+7, -0
 1@@ -125,6 +125,13 @@ button:focus, button:hover {
 2     width: auto;
 3 }
 4 
 5+.dialog-content .buttons {
 6+    display: flex;
 7+    flex-direction: row-reverse;
 8+    justify-content: space-between;
 9+    width: 100%;
10+}
11+
12 .dialog-content button:focus, .dialog-content button:hover {
13     border: 0;
14     outline: 2px solid var(--button-color);