╭ changed ─────────────────╮ │src/ui/Repo/Attachment.zig│ ╰──────────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │65 tb.getFocus().kind = .{ .custom = try pa.print("{s}{s}", .{ ui.raw_link_prefix, try url(session.page_arena, identity, &entry.id) }) };│ │66 try row.children.put(allocator, tb.getFocus().id, .{ .widget = .{ .text_box = tb }, .rect = null, .min_size = null }); │ │67 │ │68 - row.getFocus().kind = .{ .custom = try pa.print("form:{s}/attachment:{s}/remove", .{ target_url, &entry.id }) }; │ │68 + // the ✕ opens a page confirming the removal │ │69 var remove = try wgt.TextBox.init(allocator, "✕", .{ .border = .single, .round_corners = true, .wrap_kind = .none }); │ │70 errdefer remove.deinit(allocator); │ │71 remove.getFocus().mode = .all; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │72 - remove.getFocus().kind = .{ .custom = "submit" }; │ │72 + remove.getFocus().kind = .{ .custom = try pa.print("a:{s}/attachment:{s}/remove", .{ target_url, &entry.id }) }; │ │73 try row.children.put(allocator, remove.getFocus().id, .{ .widget = .{ .text_box = remove }, .rect = null, .min_size = .{ .width = 3, .height = null } });│ │74 │ │75 row.getFocus().child_id = row.children.keys()[0]; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │77 } │ │78 } │ │79 │ │80 -// the attachment id carried by a removable row │ │81 -pub fn removeId(row: *wgt.Box(ui.Widget)) ?[evt.event_id_size]u8 { │ │82 - const prefix = "form:"; │ │83 - const infix = "/attachment:"; │ │84 - const suffix = "/remove"; │ │85 - const action = switch (row.getFocus().kind) { │ │80 +// whether a row is an attachment's, by the remove link on its ✕ │ │81 +pub fn isRow(row: *wgt.Box(ui.Widget)) bool { │ │82 + const last = row.children.values()[row.children.count() - 1].widget; │ │83 + if (last != .text_box) return false; │ │84 + const link = switch (last.text_box.focus.kind) { │ │85 .custom => |custom| custom, │ │87 - else => return null, │ │86 + else => return false, │ │87 }; │ │89 - if (!std.mem.startsWith(u8, action, prefix) or !std.mem.endsWith(u8, action, suffix)) return null; │ │90 - const at = std.mem.lastIndexOf(u8, action, infix) orelse return null; │ │91 - const id = action[at + infix.len .. action.len - suffix.len]; │ │92 - if (id.len != evt.event_id_size * 2) return null; │ │93 - var bytes: [evt.event_id_size]u8 = undefined; │ │94 - _ = std.fmt.hexToBytes(&bytes, id) catch return null; │ │95 - return bytes; │ │88 + return std.mem.startsWith(u8, link, "a:") and std.mem.indexOf(u8, link, "/attachment:") != null and std.mem.endsWith(u8, link, "/remove");│ │89 } │ │90 │ │91 // the url an attachment's bytes are served from │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯