Index: items.py ================================================================== --- items.py +++ items.py @@ -63,11 +63,12 @@ # A JSON wrap-up of our content def for_json(self): items = [] res = {"name": self.name, "items": items, "gen": self.gen} - for i in sorted(self.items.itervalues(), key=lambda _i: _i.name): + for i in sorted(self.items.itervalues(), + key=lambda _i: _i.name.lower()): # Don't share deleted if i.deleted(): continue items.append(i.for_json()) return res Index: js/shopr.js ================================================================== --- js/shopr.js +++ js/shopr.js @@ -25,10 +25,13 @@ const cur_idxs = new Set([0, 1, 2]); // Map from the Element ID to its Item ID in the DB const iids = {}; +// When itname is naming an item to edit, this is its Item ID +var itname_iid = null; + // // These toggle the filtering based on color // // Each toggles between darker version of color (showing it) // and its lighter counterpart. @@ -160,10 +163,11 @@ function hold_item(e) { if (!e.id.startsWith("item")) { return false; } itname.value = e.innerText; + itname_iid = iids[e.id]; setcur(scritem); } // Click an item, probably switch the index of the item function click_item(e) { @@ -318,11 +322,13 @@ oidx += 1; continue; } // Inserted cell? - if (i1.name < i2.name) { + // (Our server orders case insenstive, so to track their order + // we need to honor that here.) + if (i1.name.toLowerCase() < i2.name.toLowerCase()) { e2.style.background = "green"; changed = true; nidx += 1; continue; } @@ -477,10 +483,34 @@ // Requesting URL, including authentication req.open("POST", url); const op = {"op": "add", "name": ifv}; req.send(JSON.stringify(op)); } + +// Do a PUT op with authentication to our current list +function xhr_put(msg, fn) { + // Construct URL; our list, authen + const url = "/l/" + encodeURIComponent(cur_list) + + ".json" + authURL; + + // PUT w. authen, op == "delete this iid" + const req = new XMLHttpRequest(); + req.open("PUT", url); + + // Optional callback + if (fn != null) { + req.onreadystatechange = () => { + if (req.readyState != 4) { + return; + } + + fn(req.status, req.responseText); + return; + } + } + req.send(JSON.stringify(msg)); +} // Remove an item // // It's the one which was long held to get this menu function del_iname() { @@ -494,23 +524,34 @@ if (iid == null) { // WTF? return; } - // Construct URL; our list, authen - let url = "/l/" + encodeURIComponent(cur_list) + - ".json" + authURL; - - // PUT w. authen, op == "delete this iid" - const req = new XMLHttpRequest(); - req.open("PUT", url); - const op = {"op": "del", "iid": iid}; - req.send(JSON.stringify(op)); + // Request delete + xhr_put({op: "del", iid: iid}, null); // Leave menu for item (which should be Going Away) cancel_scritem(); } + +// Change item's name +function new_iname() { + if (!itname.value) { + alert("Please enter the new item name"); + return false; + } + const callb = (code, txt) => { + if (code != 200) { + alert("Rename failed: " + txt); + } else { + // Go back to main display + ifilter.value = ""; + cancel_scritem(); + } + }; + xhr_put({op: "rename", iid: itname_iid, name: itname.value}, callb); +} // Choose a list function sel_list(e) { cur_list = e.currentTarget.textContent; localStorage.setItem("curlist", cur_list); Index: put.py ================================================================== --- put.py +++ put.py @@ -42,10 +42,13 @@ if op == "idx": iid = int(d["iid"]) col = int(d["col"]) elif op == "del": iid = int(d["iid"]) + elif op == "rename": + iid = int(d["iid"]) + name = str(d["name"]) else: return True,self.send_error(400, "No such op") except: return True,self.send_error(400, "Malformed JSON") @@ -59,7 +62,29 @@ if op == "del": if l.del_item(iid): return True,self.send_json({"ok": True}) return True,self.send_error(400, "Bad item") + # Change item's name + if op == "rename": + i = l.items.get(iid) + if i is None: + return True,self.send_error(400, "No such item") + + # Just adjusting capitalization. Since all comparisons + # are case insensitive, this is always OK. + nl = name.lower() + if i.name.lower() != nl: + + # Can't name on top of another element + for i2 in l.items.itervalues(): + if i2.name.lower() == nl: + return True,self.send_error(409, "Name exists") + + # Our users see this change + i.name = name + l.next_gen() + + return True,self.send_json({"ok": True}) + # "Can't Happen" return True,self.send_error(500)