List-order-savvy tagpill drop-down interface: easier to respect/use list-before etc

Here’s an idea that I’m not well-placed to implement now. But I wonder if anyone else recognizes this itch, brought to the surface in this recent thread:

:warning: This is a big deal! I did not fully realize this — that actual removal of fields happens, rather than simply the application of an ordered set of criteria for how any given tag’s children’s appear in sequence. (Does this even remove fields on shadow tiddlers? So I might actually be overwriting a shadow, without touching it, by dragging around within a tag pill where it’s listed, if the shadow had a list-before field?)

This fact (removal of special list-before / list-after fields upon tag-pill reordering) is explicit in the docs here. I had until now focused instead on where the hierarchy of ordering criteria within a tag is clearly spelled out.

more confessional details, feel free to ignore
  • On reflection, I’m pretty sure that I’ve surely carelessly deleted list-before fields without even realizing it. Likely typical case: I want to reorder the tiddlers within an informally tagged “package” (for explanation order) and one of those tagged tiddlers is, say, a cascade tiddler that needs its list-before field because of its cascade-related tag. Or I’m tinkering with a view template in haste, and just want to make sure it shows up at the top for testing.
  • Honestly, am I the only one who uses drag-and-drop too often, when I should really be adding that list-before field, simply because opening the tiddler to create a list-before field would take me out of my workflow, while the tag-pill UI is convenient and ready at hand? …
  • I never understood that in choosing this convenience, I might be actually removing list-before fields from other tiddlers… meaning that even if I scrap my experimental view template (or whatever), I’m leaving my wiki in an unwittingly altered state. In retrospect, I now have a different account of occasions when I’ve muttered, “Gee, I really don’t know why that’s demoted again, I’m sure I had it rightly prioritized yesterday…”

All this makes me toss the following idea out to y’all…

In theory we could have a list-order-savvy tag pill drop-down interface. This intervention would add some recognizable visual clues as to the ordering factors at work. It would help users more easily register whether drag-drop reordering would have unexpected consequences; for example I’d readily see that, say, two tiddlers at top of a tag’s dropdown list both have a blank list-before field (in which case to override the effect of letting inverse [!] alpha-ordering break the tie, perhaps it’s better to open one of them and add more specificity to its list-before field, etc.).

Specifically, I envision tag pill dropdown elements could be subtly but legibly styled with:

  • some default/plain (or transparent?) look throughout if there’s nothing more than default alpha-order at work (no list field in the tag tiddler, no list-before or list-after fields in the tag-child’s tiddlers). Drag-and-drop is “safe” to play with!
  • tag pill’s title tiddler at top displays differently (with underline or greater opacity or something) once it already has a list field (and then the tiddlers actually listed are then also underlined (or whatever), so we can see easily recognize how the end of the list includes recently-added stragglers, which still have the plain/transparent default formatting)…
  • any tiddler that’s at the top of dropdown because of a blank list-before is marked with a subtle up-arrow at left (or palette-tweaked background or something)
  • any tiddler that’s at the bottom of dropdown because of a blank list-after is marked with a subtle down-arrow at left…
  • some miniature/minor variant of that up/down icon marks list-before and list-after fields with contents serving to order a tiddler just above or just below its neighbor(s)…

Above-and-beyond features of a list-order-savvy tagpill: :wink:

  • All of the above features are built-in, but remain visually hidden or dialed-down except on hover, to reduce visual noise.
  • Add a small internal drop-zone at top (and bottom) of tag-pill drag-drop interface that does not change the list field for tag’s home tiddler but instead adds a blank “list-before” field to the tiddler in question. :open_mouth: Or a control-click on a tag-pill-listed-tiddler could include an option to create blank list-before or list-after field, to promote or demote it without generating (or modifying) any list field.
  • When the tag pill list-field order is reordered with drag-and-drop in the familiar way (or when it is generated for the first time that way), a little “pop” effect animates as icons/styling is removed from any tiddlers whose list-before and list-after fields have just been erased. So you have one more reminder that the drag-and-drop has done something beyond create/change the list field of the tag-home tiddler.

I’m not the best person to try this, and have other work to do…

But surely — especially in interacting with cascades! — a stylesheet that does this (perhaps also needing at least one shadow overwrite for tag pill variables) could avoid some blunders and minimize time asking: “Why exactly do these tag-children show up in this order, again?” :face_with_monocle:. If I’m tempted to reorder tag-children with drag-and-drop, how can I be quickly confident I’m not deleting some important tiddler’s list-before field?

One final attempt to articulate the “problem to be solved” here: Reordering with the tag pill drop-down is convenient and intuitive, so people are drawn to using it to adjust ordering on the fly. However, relying on list-before and list-after fields, within the “child” tiddlers, is often the cleaner solution, especially when: (a) tiddlers might need to travel across wikis (b) lists can get super-long (c) there’s a reason for micro-ordering details that is not as simple as a rote list (such as Monday Tuesday Wednesday… ) (d) some tiddlers may have multiple tags where ordering matters, so we’d want a list-before field (with specific contents) to help anchor its place within one tag, without settling its position within a different tag. We need to help users recognize this tradeoff, and to make wise decisions about which ordering criteria to manipulate, and what’s lost if they do manipulate the tag’s list field with drag-and-drop.

Note, this proposal is in keeping with some other ways of adding dimension to the information available through interaction with the tag pill — such as rendering the tag-pill in italic if its “home” node doesn’t exist as a tiddler. Ideally, we do all this in a way that does not feel cluttered or distracting, but simply intuitive — there when you care to look closely, unobtrusive otherwise. :slight_smile:

1 Like

While all that sounds like it might be nice to have, it also sounds like a work-around for a bug that should be fixed. If we stopped deleting the list-before and list-after fields, but instead rewrote the sorting algorithm to properly take into account both the tag’s list field and the items’ specific listing properties, then temporary tag lists would be just that: temporary. Deleting an item from it would just reset to the behavior that existed before it was added.

The sort order is already specified in Tagged Tiddlers. I haven’t looked at the implementation, but it must be able to handle loops (e.g. A: list-before C, B: list-before A, C: list-before B), and direct contradictions (e.g. A list-before B, list-after B). If my minimal tests are correct, it simple defaults to an alphabetic sort if that happens. We would also have to extend to handle conditions where list-before contradicts the tag’s list, but that certainly sounds doable.

Perhaps I’m missing something. Perhaps this was already tried and the team couldn’t find an appropriate algorithm. (If so, any pointers to the GitHub discussions on it?) We might still be able to revisit it. Because a technique that deletes user-defined information is worrisome.

1 Like

Hm… Having list fields be “temporary” seems to require a kind of rewind-restore tracking that isn’t available currently. The list field creation/modification (at least when it’s based on drag-drop reordering) needs to kill the interfering list-before and list-after tags, because the presence of those fields would override their place in the list field when they’re present,… so it would be awkward if dragging things around within the tag pill might fail to achieve the order that results from the drag-and-drop (or if the drag-drop simply “bonked” because of bumping up against a contrary criterion)… However, one could understand the refusal of the drag-drop to “just work” if there were a visual cue reminding you of an empty list-before field standing in the way. In the absence of that, the list-reordering through drag and drop would simply seem to fail to function properly.)

At any rate, I’ve now played around enough at tw-com to think that it’s worth lingering on how the priorities work. It looks like the priority is:

  • empty list-before
  • empty list-after
  • specific list-before
  • specific list-after

… and only the first one of the above sequence has any effect. For example: An empty list-before field trumps an empty list-after field (as one would expect based on the “Order of Tagged Tiddler” docs). But an empty list-after field always trumps any specified list-before field.

A contradiction (specifying the same tiddler title in both list-before and list-after fields) doesn’t simply cause a reversion to alpha-order. The list-before field gets priority and is obeyed.

But also, perhaps frustraitingly, you can’t use both list-before and list-after to help organize overlapping tag lists based on different orderings (without resorting to full-on shift over to brute list order).

Consider how the tiddler Open Collective is tagged with both About and HelloThere. If I erase any existing list field at both of those tag-home tiddlers, and then give Open Collective two special field values (list-before:Examples and list-after:RoadMap — naming one tiddler from each of the two otherwise non-overlapping tag-cohorts), these two field-value pairs do NOT get out of each others’ way, as one might hope.

Instead, the specific list-before field goes into effect (Open Collective appears before Examples within the HelloThere tag), but the list-after specification is ignored (even in the context of a tag like About, where the list-before field value is not part of the same set).

I think we can write the sorting algorithm in such a way that this isn’t necessary. In fact, I started to do this before writing my previous message. It wasn’t complete (I forgot to handle the empty list field values) but it was close. It was during a meeting at work, and I didn’t store it anywhere but on my work machine, but I can try to complete it tomorrow. It’s only a proof-of-concept, but it should let us know if it will work.

What I meant about temporary list fields was simply that if we later delete them, we revert to the same behavior that we had before creating them. And the same is true if we delete individual items from them.

Okay. I hadn’t tested that, although I did test a simple list-before cycle. But that could be simple coincidence too.

I’ll try to finish up that POC tomorrow.

2 Likes

Since TW v5.3.4 the tag Macro has the possibility to use 2 CSS classes tc-tag-missing and tc-tag-exists to style tag-pills – Both of them are assigned to the tag-pills, but the are undefined by default.

Since the tag-pill is prominent part of the default ViewTemplate, it is an opt-in for backwards compatibility reasons. See the tag Macro for styling info.

In the tag-dropdown itself the first item, the tag, has always been formatted using tc-tiddlylink-missing, if it did not exist, which is defined by the LinkWidget

  • If a link is a shadow-tiddler it has the class tc-tiddlylink-shadow
  • If a link is a overwritten shadow tiddler it has the classes: tc-tiddlylink-shadow tc-tiddlylink-resolves
  • If a link is a tiddler with no shadow it has tc-tiddlylink-resolves
1 Like

I do not think we should use list-before and list-after in “multi tag” scenarios.

There is only one reason why the list-before and list-after exist.

  1. To allow users and plugin authors to “customize” the sort order of shadow-tag $:/tags/* list-fields without the need to overwrite the shadow-tiddler.

So using list-before or list-after in a complex user-space multi-tag usecase has to fail by design. It’s designed for 1)

-------- More details

Let’s say $:/tags/Stylesheet has a list-field that lists other shadow tiddlers. eg: A B C

Now if a user wanted to define “custom-styles” and needed it to be listed before: B.

Prior to TW v5.0.9-beta (April 2014) there was no other way, than to overwrite the $:/tags/Stylesheet tiddler.

Since the release cycle in the beta phase was rapid users had a problem to convert a “shadow-tag” to a “system-tag”. Since system-tags are in userspace and are not automatically updated with a new core version.

Between v5.0.2-beta (2013-Dec-15) and v5.0.18-beta (2014-Sept-17) have been 15 other versions. So “preventing” core shadow tiddlers from updates was a problem.


My thoughts

list-tagged-draggable() the macro which removes list-before and list-after exists since March 2017 and I can not remember reported problems, where users did use drag & drop tag-sorting which caused problems later in the process because list-* has been missing from shadow-tags added by plugins.

Your post indicates that field removal has been around a long time (since 2017), and there haven’t been complaints — hence, perhaps, there’s no problem here to solve…?

Until late 2021 (v5.2.1), when cascades became more powerful, tag-ordering was pretty much just cosmetic, except within $:/tags/Stylesheet tag. (Even viewtemplate order was cosmetic — albeit in a very important way. If you mess up the list order, you still see the same things, just in a different order.)

Since v5.2.1 more and more solutions have used list-before (and list-after) fields to position themselves within cascades. Cascade order is much harder to troubleshoot. Still, if there’s a complaint here from me, it’s not a big one. It did take me a while (with the help of Eric’s recent post here) to realize that my use of the tagpill reordering convenience has had some unintended consequences over time.

In my OP, I didn’t go so far as to suggest anything like a “bug” in the actual behavior, especially once the priorities are limitations are clear (which they are, mostly, in the docs).

What I do see is a kind of opacity in the interface. I do see the current order in the tag-pill dropdown, but I don’t easily see why the order comes together the way it does. I prefer not having to guess whether the item(s) at the top are there because of list-before fields or because of a list-field at the tag-home tiddler. I prefer not having to guess whether reordering the tag-pill will actually remove fields from tiddlers. I am not necessarily smart enough to reconstruct those cascade priorities properly (or quickliy) if I accidentally mess them up.

Right now, I certainly can refrain from using the tag-pill DnD reorder until I go find out this information (about list-before fields in shadows, etc.), but in a way that takes me on a detour into opening those tiddlers and examining their fields.

(Side note: Actually, I will probably just make a dynamic view template for each cascade tag’s home node, with rows for each tag-child, and columns for those list- fields… using my technique for making empty field cell render different from non-existing field… though I still won’t easily know what list-before and list-after fields I’ve already unwittingly deleted :grimacing:).

What I’m envisioning here in my OP, is simply an optional visual layer that makes such information discernable within the tagpill-dropdown — information that would make me more aware of the role that list-before (and list-after) fields currently play within a tag-pill’s order.

Almost always, these would be fields put there by plugin developers, not by me. Seeing visual cues for where they saw fit to use list-before fields to help structure that order would usually deter me from simple tag-pill reordering, in favor of adding a special list- field to my own new tiddler.

Thank you @Springer. I need more time to think about this, but I agree that the current behaviour of a drag and drop operation editing shadow tiddlers behind the scenes is problematic. I would consider it a bug, would be interested to explore further to see if we can figure out a solution.

1 Like

Although I did finish this, just to see how it might work, I’ve realized that all I’m doing is reimplementing the behavior that exists. I don’t know why the draggable widget removes the before and after fields, but it certainly seems like a bug. If it was in order to help implement the sorting correctly then I think my version below should demonstrate that it’s not too complex to sort them without resorting (:slight_smile:) to that.

The big problem of course is that there is only one list-before field for a tiddler, but it might get used in multiple lists. So the tag’s list field is crucial. But to deliver a robust tiddler that needs to insert itself in the right place in the list field of a core tiddler—without overriding it— the before/after mechanism is crucial.

(I apologize for that last paragraph; I think all the participants in this thread already understand it. But I needed to write it down for myself, and thought others might wander in later,)


If you’re interested, you can see my plain JS version at http://link.sauyet.com/115 (Edit fixed this link.). We start with two useful but not interesting helper functions, then a bit of code that collects fake tiddlers from a simple declarative list. It should be obvious enough how to add and alter the fake tiddlers. You can also change the tag you want to display, by replacing const main = () => tagSort('Blue') with const main = () => tagSort('White') or const main = () => tagSort('Tangled up in'). After that is the sorting function. I believe it expresses the same interface described above by Springer and in Order of Tagged Tiddlers. While there are many lines, it’s just a long nested conditional statement – a syntactically simpler version of a chain of if / else if statements.

The bug is not as simple as that behaviour being wrong. The reason that it was done is because the before and after fields have priority over the list field, and so any residual before/after fields would affect the sort order. So removing the code that removes the before and after fields would not fix the problem.

Then perhaps the code I linked to above would be a help. It implements the sorting order as described in Tagged Tiddlers. even when the the list-before or list-after fields would conflict with the tag’s list field.

As is typical with comparator-based sorts, it doesn’t do anything special to handle illegitimate cycles. If A < B < C < D < A, then the final order will depend on the order in which the pairwise comparison are done, which may well vary by JS engine. Without looking at the current code, based on a far too tiny sample, I was guessing that when this happened, TW was reverting to alphabetic order. But that may just be coincidence.

I posted a bad link above and will fix it in a moment, but the code in question looks like this:

  tags.sort((
    {title: x, 'list-before': xlb, 'list-after': xla}, 
    {title: y, 'list-before': ylb, 'list-after': yla}
  ) =>
    list.includes(x) && list.includes(y)
      ? list.indexOf(x) - list.indexOf(y)
    : list.includes(x)
       ? -1
    : list.includes(y)
        ? 1
    : xlb == ''
        ? -1
    : ylb == ''
        ? 1
    : xla ==''
        ? 1
    : ylb == ''
        ? -1
    : xlb == y
      ? -1
    : ylb == x
      ? 1
    : xla == y
      ? 1
    : yla == x
      ? -1
    : byName (x, y)   
  )

where byName is a simple case-insensitive title comparator and list is a possibly-empty array representing the values in the tag’s list field.