Drag-and-drop fields between tiddlers

I have thought allowing this on regular tiddlers may be useful, even if the field/value pair is not visible. Perhaps even a list of field/value pairs. For example to make one tiddler like another without a clone or detailed instructions. eg tiddler-type=todo, description=“describe this item”, caption=“short name”.

If you can share a generic solution given your recent activity please consider doing so.

Let’s suppose we want to make a general-purpose drag-and-drop mechanism to copy fields between tiddlers that are being edited. The basic methodology would be something like this:

  • wrap the field names displayed in the EditTemplate/fields in a $draggable widget
    • the widget’s startActions param writes fieldname and fieldvalue to a temp tiddler (e.g., $:/temp/dragdata)
    • the widget’s endActions param deletes the temp tiddler to clean up afterwards
  • wrap the background of the EditTemplate in a $droppable widget
    • the widget’s actions param gets the fieldname and fieldvalue from the $:/temp/dragdata tiddler and uses $action-setfield to add that field to the current tiddler.

Here’s a quick example of how to accomplish this:

First, to make the tiddler editor’s field names draggable, edit $:/core/ui/EditTemplate/fields and replace the first occurence of this:

<$text text=<<currentField>>/>:

with this:

<$draggable tiddler={{{ [<currentTiddler>get<currentField>else[]] }}}
   startActions='<$action-setfield $tiddler="$:/temp/dragdata"
      fieldname=<<currentField>> fieldvalue={{{ [<currentTiddler>get<currentField>] }}}/>'
   endActions='<$action-deletetiddler $tiddler="$:/temp/dragdata"/>'>
<$text text=<<currentField>>/>:
</$draggable>

Then, to handle the “drop on a tiddler editor’s background”, edit $:/core/ui/EditTemplate, and change this:

<$transclude tiddler=<<listItem>>/>

to this:

<$droppable actions=<<dropfield>>><$transclude tiddler=<<listItem>>/></$droppable>

and add this \procedure definition to the top of the tiddler:

\procedure dropfield()
<%if [[$:/temp/dragdata]is[tiddler]] %>
<$let newfield={{{ [[$:/temp/dragdata]get[fieldname]] }}} newvalue={{{ [[$:/temp/dragdata]get[fieldvalue]] }}}>
   <$action-confirm
      $message=`A field named "$(newfield)$" already exists.  OK to overwrite?`
      $prompt={{{ [<currentTiddler>!has:field<newfield>then[no]else[yes]] }}}>
      <$action-setfield $field=<<newfield>> $value=<<newvalue>>/>
   </$action-confirm>
</$let>
<%endif%>
\end

Notes:

  • In the $draggable widget, the $tiddler param is set to the value of the field being dragged (or blank if it has no value). This allows you to drag a field name and drop it into an $edit-text widget to copy the field’s value into that input control (all text inputs have a built-in drop handler to accept text values!)
  • The dropfield() handler makes sure that a $:/temp/dragdata tiddler exists. This prevents it from responding to other drop events (such as dropping a link or some text).
  • The dropfield() handler also checks to see if the “target” fieldname already exists. If it does, the handler asks for confirmation to overwrite it.

Note that this is only a very basic example of how to use drag-and-drop to copy fields between tiddlers while they are being edited.You could add more to it, such as using a $:/config tiddler to enable/disable the $draggable widget.

enjoy,
-e

3 Likes