Drag and drop tag pills is dangerous (tag pills can have big drag payloads)

I have a facility that allows be to drag any link/title to a drop zone and add that title as a tag or to a list.

However if you drag and drop a tag pill rather than a simple title, every title with that tag will be “dropped” and added to the list.

  • This can be useful, but;
  • Now if you have tags with hundreds of members bad results can occur, if there is a user confirmation set for each tag, (are you sure? yes/no) it could take you hours of clicks, to break out of this process, so instead you may have to close your wiki and loose any unsaved changes (just happened :frowning: )

Problem

I cant see a way when defining a droppable area to set a limit to the number of elements that can be dropped in one user action.

We could limit the number of titles in the drag step but this involves editing the core macros relating to the tag and tag pill macros.

Possible solutions

This means I am looking for one or more solutions.

  • To break out of the process if it occurs
  • To somehow set the droppable area to only accept the first (or only title), or first N titles.
  • Disable the tag pill drag option for all titles but itself, or set a maximum.
    • If necessary we could add this “feature” back using a tag pill item using $:/tags/TagDropdown
  • Perhaps we could enhance the action-confirm message to include the ability to cancel all going forward ?
<$action-confirm $message="Remove $(actionTiddler)$ as a tag here?">

Any guidance appreciated.

Tip:
If this happens to you and your tiddler has a lot, even hundreds of tags, a quick and easy way to remove them is to edit the tiddler, and add the tags field with the field containing a single tag or space, this will replace the tags field with this value in one step.

  • Yes, if you add a field that already exists with a value set, it will replace the current field/value.

This would be ideal, or if a counter variable were available and we had another action to cancel all, we could test that counter, and exist the process.

Or is it possible to test if the drag source is a tag pill?

If we had a way to have it open a modal to confirm or cancel i think thatd be best.

Maybd if its multiple things, there could be a parameter that lets you choose a ‘select which ones you wish to do x with’ and it would list each item with a checkbox next to it.

How these could be done, I’m unsure, but figured it should be mentioned, from a design standpoint.

Ah, inspired by your comment, Perhaps we could have the droppable widget, add each title to a list (not tags), that would be the only drop action. Then due to the existence of the list we could have a separate process or action, that will transfer the title(s) to the tag.

  • To avoid having a second trigger and additional user action it may help if the draggable widget could trigger additional actions after processing all items. But I doubt this would be possible to design.

If the action confirm allowed an exit, ie yes/no/cancel it would be easier, but I don’t know if this would be possible.

  • I think action confirm stops the parent trigger from propagating (the title action), but we need an option to “also” stop the grandparent trigger propagating eg cancel the drop trigger, not the drop action (my terminology may not be correct)

The actionVariable should contain a title-list if you use startactions or endactions with the droppable widget. So you should be able to decide there what to do with many titles.

There should be no need for new core functions.

1 Like

@pmario thanks for the assistance, but I having trouble working this out, or through to a solution, despite what you have said.

  • My code is designed to accept things using a droppable widget
  • I believe the drag and drop is initiated in the Draggable Widget, which in this case (I assume) is in use within the $link widget and Tag pill macro, which I did not want to have to modify.

Presumably then when I code the drop area with the following;

<$droppable actions=<<drop-on-tags-actions>> >
something to drop on top of
</$droppable>

The above then executes the <<drop-on-tags-actions>> once for each title dropped.

drop-on-tags-actions

\define drop-on-tags-actions()
<$fieldmangler>
<$list filter="[<modifier>match[normal]] +[<actionTiddler>is[tag]]" variable=~>
   <$action-sendmessage $message="tm-add-tag" $param=<<actionTiddler>>/>
</$list>
<$list filter="[<modifier>match[normal]] +[<actionTiddler>!is[tag]]" variable=~>
   <$action-confirm $message="Add $(actionTiddler)$ as a tag here? It is not yet used as a tag!">
   <$action-sendmessage $message="tm-add-tag" $param=<<actionTiddler>>/>
</$list>
<$list filter="[<modifier>match[ctrl]] +[<actionTiddler>is[tag]]" variable=~>
   <$action-confirm $message="Remove $(actionTiddler)$ as a tag here?">
   <$action-sendmessage $message="tm-remove-tag" $param=<<actionTiddler>>/>
</$list>
</$fieldmangler>
\end
  • These are the actions, which behave as if actioned once for each title.

So where do I intervene to make use of the actionVariable? The Droppable widget includes a tip as follows,

Note that the [[actionTiddler Variable]] holds a single, unquoted title. This is unlike the DraggableWidget which uses the same variable to pass a quoted [[Title List]].

Thanks in advance.

[Edited]
I see that the tag pill macro refers to $:/core/ui/TagTemplate which then uses “list-tagged-draggable” for the dropdown list, and sets a dragFilter="[all[current]tagging[]]" while calling tag-pill-body (which does not use the draggable widget?

It seems the docs of the actionVariable is wrong. It states, that the droppableWidget also has an endactions parameter, which is does not.

So there may be a new variable needed eg: actionVariableList which does contain a TitleList that can be “counted”.

IMO this will need to be a feature request at GH

I did create a GH issue with a proposal

1 Like

Thanks @pmario I added a couple of comments there.

We could add a warning to the droppable widget Documentation saying it unconditionally performs the action for every title dropped. So if you drop a list, such as a tag pill it will apply the whole list.

Then if we create a droplist or droppablelist widget that provides access to the whole list, on drop, and a separate step needs to be taken to trigger actions for each title.

  • This may deserve a new widget as it would not trigger any actions unless they are provided, within the widget, and often within further logic.
  • It could be used to just save the whole list in a tiddler or field, and not process each title.
    • This would be a useful feature in its own right to assist with dragging and dropping lists rather than just titles.

I wonder if a new %loop as discussed here would be an opportunity to make use of a list of titles being given in a drop.

  • That is we introduce a new mechanism for handling a list in a loop with the ability to exit.

Maybe I’m misunderstanding the problem (I’d have to do some tests), but if the problem is that whatever you give as “actions” is run once per each tiddler (and the actionTiddler being the “currentTiddler” in the behind-the-scenes loop), rather than you getting to control the looping, then I wonder if simply making a variable actionCounter (equivalent to setting a “counter” in the list widget) available to the action string would solve the problem. Then you could just surround your actions with something like <% if [<actionCounter>compare:integer:lteq[50]] %><% endif %>.

The problem is the droppable widget does not have this feature of a counter variable.

@pmario’s solution is to;

It is proposed to add a new parameter eg: listactions to the droppable-widget. The connected action should get a variable eg: actionTiddlerList which contains a TW TitleList.

This would then call an action that could use a list and counter variable to iterate the actionTiddlerList including allow introduction of a limit, eg: limit[10] or your @bluepenguindeveloper suggestion;

  • <% if [<actionCounter>compare:integer:lteq[50]] %>…<% endif %>

However another way to then proceed the list is the suggested loop, where I could have a confirmation and cancelation button displayed for each item, and use the loop exit feature (if it existed) to cancel the process.

There is no need to have an exit condition inside the list-widget, if you know the number of elements upfront. Possible workflow:

  • You can count the elements first
  • You can tell the user that the existing import will have 1000 elements, and that asking for permission with each element does not make sense.
  • So you suggest to “Import all” or “Cancel Import”
  • Done.

If an actionTiddlerList variable gets added, then presumably you could write:

<$list filter="[enlist<actionTiddlerList>]" limit="10">...</$list>

(Or you could set the counter with the list widget, or whatever.)

Right, so even without @pmario 's proposal (or until all the debates get settled), if we enhanced the droppable widget to create a counter variable, then you could use it in your actions.

(Presumably the droppable widget already creates a list when processing the actions, so it probably wouldn’t be a big change to add counter="actionCounter" to it.)

  • Actually I was proposing this in the loop construct, but yes that possibly means it’s in the list widget.

The ability to exit a loop is a common construct, and we don’t have this in TiddlyWiki. I could argue the case for such a feature which is present in most software, languages, and macro platforms.

  • Perhaps you could demonstrate that there is no need to have an exit condition in all possible algorithms in TiddlyWiki?
  • Although I will construct an example below.

Mario, this is mostly true, “if you know the number of elements upfront”. But First, what if you don’t Know the number of elements to process, because we want to allow the user to choose, not just upfront?

I will give you an example to illustrate,

In my personal organiser, I have N items to process, N could be 1-100 or more. I know how many I need to process in the long run so I start “trigger” the process, for each I check a set of fields, make some changes and move to the next one, 1-9 are done in a matter of milliseconds then we get to the 10th, this has some errors in the data that need to be corrected (or not available at the time), so a modal pops up to warn or intervein, the user makes a change and it moves on to the next in the list. Unfortunately, a lot of items need this manual attention, and it is taking much longer than I currently have time for, then the phone rings.

  • I have no way to exit this loop and record details of my phone call.
  • I did suggest introducing an exit/cancel to the action confirm widget but was told it can’t be done.

Now Imagin if I made an error crafting the filter, or I dragged a tiddler Pill with 900 tagged items, and the process has started, I have no choice but to respond to every manual interaction.

  • Sure I could warn that there are 900 but the user may start with the intention to do them all, but find a need to exit the process and restart later.

Speculation: There may be a way to write an algorithm in TiddlyWiki Script that ultimately acts like a cancelable process, but it will not be strait forward. It would be better to provision this in one or more of the current widgets.