shopr

Check-in [eef76568c0]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Span color filtering. Deal with online/offline. Quiet complaint if we abort our long poll.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:eef76568c032c346556b4d52be200ac61f2bb15074484541dae37c97b27c1e6a
User & Date: vandys 2019-06-23 16:35:17
Context
2019-06-23
21:43
Tighten up display, especially for small screens. Fix gold/yellow toggle. Use item ID's, get rid of numbering confusion when adding (and, I suppose, deleting) items to the list. check-in: 5dc54d9bcb user: vandys tags: trunk
16:35
Span color filtering. Deal with online/offline. Quiet complaint if we abort our long poll. check-in: eef76568c0 user: vandys tags: trunk
15:44
Start laying out more menu stuff check-in: 0524a8bdc1 user: vandys tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to css/shopr.css.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#scrlist2 {
 margin-bottom: 15px;
}
#scrlist2 > span, #scrlist2 > input, #scrlist2 > button {
 border: 3px solid black;
 border-radius: 6px;
}
#spanR {
 background: pink;
}
#spanG {
 background: PaleGreen;
}
#spanY {
 background: lightyellow;
}
#items {
 display: flex;
 flex-wrap: wrap;
}
#items > span {
 flex-grow: 0;
 width: 9%;







<
<
<
<
<
<
<
<
<







11
12
13
14
15
16
17









18
19
20
21
22
23
24
#scrlist2 {
 margin-bottom: 15px;
}
#scrlist2 > span, #scrlist2 > input, #scrlist2 > button {
 border: 3px solid black;
 border-radius: 6px;
}









#items {
 display: flex;
 flex-wrap: wrap;
}
#items > span {
 flex-grow: 0;
 width: 9%;

Changes to html/shopr.html.

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 <div id="scrlists2">
 </div>
</div>

<div id="scrlist" style="display: none;">
 <div id="scrlist2">
  <span style="background: white;">+RGY</span>
  <span id="spanR" onclick="filtR();">R</span>
  <span id="spanG" onclick="filtG();">G</span>
  <span id="spanY" onclick="filtY();">Y</span>
  <input type="text" id="ifilter"
   onkeyup="update_filter();" placeholder="Choose or Add">
  <button onclick="addit();">+</button>
  <img src="/imgs/menu.svg" style="float: right;" />
 </div>
 <div id="items">
 </div>







|
|
|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 <div id="scrlists2">
 </div>
</div>

<div id="scrlist" style="display: none;">
 <div id="scrlist2">
  <span style="background: white;">+RGY</span>
  <span id="spanR" onclick="filtR();" style="background: red;">R</span>
  <span id="spanG" onclick="filtG();" style="background: green;">G</span>
  <span id="spanY" onclick="filtY();" style="background: gold;">Y</span>
  <input type="text" id="ifilter"
   onkeyup="update_filter();" placeholder="Choose or Add">
  <button onclick="addit();">+</button>
  <img src="/imgs/menu.svg" style="float: right;" />
 </div>
 <div id="items">
 </div>

Changes to js/shopr.js.

15
16
17
18
19
20
21






































22
23
24
25
26
27
28
..
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
..
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
...
188
189
190
191
192
193
194
195

196
197
198
199
200
201
202
...
281
282
283
284
285
286
287

288
289
290
291
292
293
294
295

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
...
320
321
322
323
324
325
326

327
328
329
330
331
332
333
...
408
409
410
411
412
413
414

415
416
417
418
419
420
421
...
464
465
466
467
468
469
470
















471
472
473
474
475
476



477
478
479
480
481
482
483
// Current generation of cur_list we hold
var curgen = null;

// List of elems as last delivered by the server
// {name: "listname", items: [item1, ...], gen: <int>}
//  item: {name: "item name", idx: <int>}
var cur_names = null, show_names = null;







































// Currently displayed page elem
var curdiv = null;
function setcur(e) {
    if (curdiv != null) {
	curdiv.style.display = "none";
    }
................................................................................

    // But then how'd we get here?
    if (cur_bright == null) {
	return;
    }

    // Clear elem local styling
    cur_bright.style.border = "";
    cur_bright = null;

    // Wah
    alert("Item update: can't reach server");
}

// Server update came in OK
................................................................................
	return;
    }

    // We're OK now
    clearTimeout(tmo_bright);

    // Stop highlighting
    cur_bright.style.border = "";

    // All state cleared
    cur_bright = tmo_bright = null;
}

// Set the outline bright white
//
// This can clear when we get a server update, or else
//  after a timeout we clear it ourselves and warn that
//  the server apparently never heard about the change.
function set_bright(e) {
    e.style.border = "6px solid white";
    cur_bright = e;
    tmo_bright = setTimeout(cancel_bright, 3000);
}

// Back to item list
function cancel_scritem() {
    setcur(scrlist);
................................................................................
	    s2.classList.add("isel");
	} else {
	    s3.textContent = l.name;
	    s3.classList.add("isel");
	}

	// Currently filtered?  Hide it.
	if (ifv && !l.name.toLowerCase().includes(ifv)) {

	    s1.style.display =
	    s2.style.display =
	    s3.style.display = "none";
	}

	// Add to DOM
	items.appendChild(s1);
................................................................................
    } else {
	// Didn't spot anything new, so paint now.
	show_new_list(ls);
    }
}

// Display the current list

function paint_list() {
    const req = new XMLHttpRequest();
    req.onreadystatechange = () => {
	if (req.readyState != 4) {
	    return;
	}

	// Pending display op now resolved

	ok_bright();

	if (req.status != 200) {
	    if (req.status == 403) {
		// Changed, password, deleted account, ???
		setcur(scrlogin);
		alert("Login credentials failed, please try again");
	    } else {
		alert("Failed to get list " + cur_list);
	    }
	    return;
	}

	// Server seems happy
	show_list(JSON.parse(req.responseText));
	return;
................................................................................
    if (curgen != null) {
	url += ("&gen=" + curgen.toString());
    }

    // Requesting URL, including authentication
    req.open("GET", url);
    req.send();

}

// Typing in our "filter" input field, so adjust what
//  we show.
// Note, our search is case insensitive, but we keep the input in
//  its typed case, so that if they're entering a new item name it
//  can be added in the original input format.
................................................................................
    const op = {"op": "add", "name": ifv};
    req.send(JSON.stringify(op));
}

// Choose a list
function sel_list(e) {
    cur_list = e.currentTarget.textContent;

    cur_names = null;
    paint_list();
    return false;
}

// Display choice of lists
//
................................................................................
	return;
    };

    // Requesting URL, including authentication
    req.open("GET", "/lists.json" + authURL);
    req.send();
}

















// Initial load of shopr app page
function init_page() {
    // Manage click/long-hold of item list
    const c = new Clicker(items, click_item, hold_item);




    // Saved values?
    const u = localStorage.getItem("user");
    if (u != null) {
	uname = user.value = u;
    }
    const p = localStorage.getItem("password");
    if (p != null) {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







|





|





|







 







|
>







 







>








>








|







 







>







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






>
>
>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
...
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
...
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
...
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
...
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
// Current generation of cur_list we hold
var curgen = null;

// List of elems as last delivered by the server
// {name: "listname", items: [item1, ...], gen: <int>}
//  item: {name: "item name", idx: <int>}
var cur_names = null, show_names = null;

// Set of indices currently being displayed
// Initial state, show all
const cur_idxs = new Set([0, 1, 2]);

//
// These goggle the filtering based on color
//
// Each toggles between darker version of color (showing it)
//  and its lighter counterpart.
//
function filtR() {
    if (cur_idxs.delete(0)) {
	spanR.style.background = "pink";
    } else {
	cur_idxs.add(0);
	spanR.style.background = "red";
    }
    show_new_list(cur_names);
}
function filtG() {
    if (cur_idxs.delete(1)) {
	spanG.style.background = "PaleGreen";
    } else {
	cur_idxs.add(1);
	spanG.style.background = "green";
    }
    show_new_list(cur_names);
}
function filtY() {
    if (cur_idxs.delete(2)) {
	spanY.style.background = "#F3E5AB";
    } else {
	cur_idxs.add(0);
	spanY.style.background = "gold";
    }
    show_new_list(cur_names);
}

// Currently displayed page elem
var curdiv = null;
function setcur(e) {
    if (curdiv != null) {
	curdiv.style.display = "none";
    }
................................................................................

    // But then how'd we get here?
    if (cur_bright == null) {
	return;
    }

    // Clear elem local styling
    cur_bright.style.background = "";
    cur_bright = null;

    // Wah
    alert("Item update: can't reach server");
}

// Server update came in OK
................................................................................
	return;
    }

    // We're OK now
    clearTimeout(tmo_bright);

    // Stop highlighting
    cur_bright.style.background = "";

    // All state cleared
    cur_bright = tmo_bright = null;
}

// Immediate visual confirmation of tap
//
// This can clear when we get a server update, or else
//  after a timeout we clear it ourselves and warn that
//  the server apparently never heard about the change.
function set_bright(e) {
    e.style.background = "white";
    cur_bright = e;
    tmo_bright = setTimeout(cancel_bright, 3000);
}

// Back to item list
function cancel_scritem() {
    setcur(scrlist);
................................................................................
	    s2.classList.add("isel");
	} else {
	    s3.textContent = l.name;
	    s3.classList.add("isel");
	}

	// Currently filtered?  Hide it.
	if ((ifv && !l.name.toLowerCase().includes(ifv)) ||
		!cur_idxs.has(l.idx)) {
	    s1.style.display =
	    s2.style.display =
	    s3.style.display = "none";
	}

	// Add to DOM
	items.appendChild(s1);
................................................................................
    } else {
	// Didn't spot anything new, so paint now.
	show_new_list(ls);
    }
}

// Display the current list
var paint_req = null;
function paint_list() {
    const req = new XMLHttpRequest();
    req.onreadystatechange = () => {
	if (req.readyState != 4) {
	    return;
	}

	// Pending display op now resolved
	paint_req = null;
	ok_bright();

	if (req.status != 200) {
	    if (req.status == 403) {
		// Changed, password, deleted account, ???
		setcur(scrlogin);
		alert("Login credentials failed, please try again");
	    } else {
		console.log("Failed to get list " + cur_list);
	    }
	    return;
	}

	// Server seems happy
	show_list(JSON.parse(req.responseText));
	return;
................................................................................
    if (curgen != null) {
	url += ("&gen=" + curgen.toString());
    }

    // Requesting URL, including authentication
    req.open("GET", url);
    req.send();
    paint_req = req;
}

// Typing in our "filter" input field, so adjust what
//  we show.
// Note, our search is case insensitive, but we keep the input in
//  its typed case, so that if they're entering a new item name it
//  can be added in the original input format.
................................................................................
    const op = {"op": "add", "name": ifv};
    req.send(JSON.stringify(op));
}

// Choose a list
function sel_list(e) {
    cur_list = e.currentTarget.textContent;
    localStorage.setItem("curlist", cur_list);
    cur_names = null;
    paint_list();
    return false;
}

// Display choice of lists
//
................................................................................
	return;
    };

    // Requesting URL, including authentication
    req.open("GET", "/lists.json" + authURL);
    req.send();
}

// Notice when we're in front of the user or not
function updateVisibility() {
    if (document.hidden == false) {
	// We care about screen updates again
	if (paint_req == null) {
	    paint_list()
	}
    } else {
	// Losing screen, don't worry about list changes
	if (paint_req != null) {
	    paint_req.abort();
	    paint_req = null;
	}
    }
}

// Initial load of shopr app page
function init_page() {
    // Manage click/long-hold of item list
    const c = new Clicker(items, click_item, hold_item);

    // We don't jabber except when we're on screen
    document.addEventListener("visibilitychange", updateVisibility);

    // Saved values?
    const u = localStorage.getItem("user");
    if (u != null) {
	uname = user.value = u;
    }
    const p = localStorage.getItem("password");
    if (p != null) {