mirror of
https://github.com/Jermolene/TiddlyWiki5.git
synced 2026-01-20 19:41:32 -08:00
Merge 613679ffce into ae4e99951a
This commit is contained in:
commit
09b7fe3b4e
12 changed files with 553 additions and 132 deletions
|
|
@ -193,6 +193,7 @@ Subscript/Caption: subscript
|
|||
Subscript/Hint: Apply subscript formatting to selection
|
||||
Superscript/Caption: superscript
|
||||
Superscript/Hint: Apply superscript formatting to selection
|
||||
ToggleDragnDrop/Hint: Toggle drag-and-drop of the tiddlers in the story river
|
||||
ToggleSidebar/Hint: Toggle the sidebar visibility
|
||||
Transcludify/Caption: transclusion
|
||||
Transcludify/Hint: Wrap selection in curly brackets
|
||||
|
|
|
|||
|
|
@ -27,122 +27,127 @@ exports.makeDraggable = function(options) {
|
|||
if(!options.selector && ((domNode.tagName || "").toLowerCase() !== "a")) {
|
||||
domNode.setAttribute("draggable","true");
|
||||
}
|
||||
// Add event handlers
|
||||
$tw.utils.addEventListeners(domNode,[
|
||||
{name: "dragstart", handlerFunction: function(event) {
|
||||
if(event.dataTransfer === undefined) {
|
||||
return false;
|
||||
var dragStartHandler = function(event) {
|
||||
if(event.dataTransfer === undefined) {
|
||||
return false;
|
||||
}
|
||||
// Collect the tiddlers being dragged
|
||||
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
|
||||
dragFilter = options.dragFilterFn && options.dragFilterFn(),
|
||||
titles = dragTiddler ? [dragTiddler] : [],
|
||||
startActions = options.startActions,
|
||||
variables;
|
||||
if(dragFilter) {
|
||||
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget));
|
||||
}
|
||||
var titleString = $tw.utils.stringifyList(titles);
|
||||
// Check that we've something to drag
|
||||
if(titles.length > 0 && (options.selector && $tw.utils.domMatchesSelector(event.target,options.selector) || event.target === domNode)) {
|
||||
// Mark the drag in progress
|
||||
$tw.dragInProgress = domNode;
|
||||
// Set the dragging class on the element being dragged
|
||||
$tw.utils.addClass(domNode,"tc-dragging");
|
||||
// Invoke drag-start actions if given
|
||||
if(startActions !== undefined) {
|
||||
// Collect our variables
|
||||
variables = $tw.utils.collectDOMVariables(domNode,null,event);
|
||||
variables.modifier = $tw.keyboardManager.getEventModifierKeyDescriptor(event);
|
||||
variables["actionTiddler"] = titleString;
|
||||
options.widget.invokeActionString(startActions,options.widget,event,variables);
|
||||
}
|
||||
// Create the drag image elements
|
||||
dragImage = options.widget.document.createElement("div");
|
||||
dragImage.className = "tc-tiddler-dragger";
|
||||
var inner = options.widget.document.createElement("div");
|
||||
inner.className = "tc-tiddler-dragger-inner";
|
||||
inner.appendChild(options.widget.document.createTextNode(
|
||||
titles.length === 1 ?
|
||||
titles[0] :
|
||||
titles.length + " tiddlers"
|
||||
));
|
||||
dragImage.appendChild(inner);
|
||||
options.widget.document.body.appendChild(dragImage);
|
||||
// Set the data transfer properties
|
||||
var dataTransfer = event.dataTransfer;
|
||||
// Set up the image
|
||||
dataTransfer.effectAllowed = "all";
|
||||
if(dataTransfer.setDragImage) {
|
||||
if(dragImageType === "pill") {
|
||||
dataTransfer.setDragImage(dragImage.firstChild,-16,-16);
|
||||
} else if(dragImageType === "blank") {
|
||||
dragImage.removeChild(dragImage.firstChild);
|
||||
dataTransfer.setDragImage(dragImage,0,0);
|
||||
} else {
|
||||
var r = domNode.getBoundingClientRect();
|
||||
dataTransfer.setDragImage(domNode,event.clientX-r.left,event.clientY-r.top);
|
||||
}
|
||||
}
|
||||
// Set up the data transfer
|
||||
if(dataTransfer.clearData) {
|
||||
dataTransfer.clearData();
|
||||
}
|
||||
var jsonData = [];
|
||||
if(titles.length > 1) {
|
||||
titles.forEach(function(title) {
|
||||
jsonData.push(options.widget.wiki.getTiddlerAsJson(title));
|
||||
});
|
||||
jsonData = "[" + jsonData.join(",") + "]";
|
||||
} else {
|
||||
jsonData = options.widget.wiki.getTiddlerAsJson(titles[0]);
|
||||
}
|
||||
// IE doesn't like these content types
|
||||
if(!$tw.browser.isIE) {
|
||||
dataTransfer.setData("text/vnd.tiddler",jsonData);
|
||||
dataTransfer.setData("text/plain",titleString);
|
||||
dataTransfer.setData("text/x-moz-url","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||
}
|
||||
// If browser is Chrome-like and has a touch-input device do NOT .setData
|
||||
if(!($tw.browser.isMobileChrome)) {
|
||||
dataTransfer.setData("URL","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||
}
|
||||
dataTransfer.setData("Text",titleString);
|
||||
event.stopPropagation();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var dragEndHandler = function(event) {
|
||||
if((options.selector && $tw.utils.domMatchesSelector(event.target,options.selector)) || event.target === domNode) {
|
||||
// Collect the tiddlers being dragged
|
||||
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
|
||||
dragFilter = options.dragFilterFn && options.dragFilterFn(),
|
||||
titles = dragTiddler ? [dragTiddler] : [],
|
||||
startActions = options.startActions,
|
||||
variables,
|
||||
domNodeRect;
|
||||
endActions = options.endActions,
|
||||
variables;
|
||||
if(dragFilter) {
|
||||
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget));
|
||||
}
|
||||
var titleString = $tw.utils.stringifyList(titles);
|
||||
// Check that we've something to drag
|
||||
if(titles.length > 0 && (options.selector && $tw.utils.domMatchesSelector(event.target,options.selector) || event.target === domNode)) {
|
||||
// Mark the drag in progress
|
||||
$tw.dragInProgress = domNode;
|
||||
// Set the dragging class on the element being dragged
|
||||
$tw.utils.addClass(domNode,"tc-dragging");
|
||||
// Invoke drag-start actions if given
|
||||
if(startActions !== undefined) {
|
||||
// Collect our variables
|
||||
variables = $tw.utils.collectDOMVariables(domNode,null,event);
|
||||
variables.modifier = $tw.keyboardManager.getEventModifierKeyDescriptor(event);
|
||||
variables["actionTiddler"] = titleString;
|
||||
options.widget.invokeActionString(startActions,options.widget,event,variables);
|
||||
}
|
||||
// Create the drag image elements
|
||||
dragImage = options.widget.document.createElement("div");
|
||||
dragImage.className = "tc-tiddler-dragger";
|
||||
var inner = options.widget.document.createElement("div");
|
||||
inner.className = "tc-tiddler-dragger-inner";
|
||||
inner.appendChild(options.widget.document.createTextNode(
|
||||
titles.length === 1 ?
|
||||
titles[0] :
|
||||
titles.length + " tiddlers"
|
||||
));
|
||||
dragImage.appendChild(inner);
|
||||
options.widget.document.body.appendChild(dragImage);
|
||||
// Set the data transfer properties
|
||||
var dataTransfer = event.dataTransfer;
|
||||
// Set up the image
|
||||
dataTransfer.effectAllowed = "all";
|
||||
if(dataTransfer.setDragImage) {
|
||||
if(dragImageType === "pill") {
|
||||
dataTransfer.setDragImage(dragImage.firstChild,-16,-16);
|
||||
} else if(dragImageType === "blank") {
|
||||
dragImage.removeChild(dragImage.firstChild);
|
||||
dataTransfer.setDragImage(dragImage,0,0);
|
||||
} else {
|
||||
var r = domNode.getBoundingClientRect();
|
||||
dataTransfer.setDragImage(domNode,event.clientX-r.left,event.clientY-r.top);
|
||||
}
|
||||
}
|
||||
// Set up the data transfer
|
||||
if(dataTransfer.clearData) {
|
||||
dataTransfer.clearData();
|
||||
}
|
||||
var jsonData = [];
|
||||
if(titles.length > 1) {
|
||||
titles.forEach(function(title) {
|
||||
jsonData.push(options.widget.wiki.getTiddlerAsJson(title));
|
||||
});
|
||||
jsonData = "[" + jsonData.join(",") + "]";
|
||||
} else {
|
||||
jsonData = options.widget.wiki.getTiddlerAsJson(titles[0]);
|
||||
}
|
||||
// IE doesn't like these content types
|
||||
if(!$tw.browser.isIE) {
|
||||
dataTransfer.setData("text/vnd.tiddler",jsonData);
|
||||
dataTransfer.setData("text/plain",titleString);
|
||||
dataTransfer.setData("text/x-moz-url","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||
}
|
||||
// If browser is Chrome-like and has a touch-input device do NOT .setData
|
||||
if(!($tw.browser.isMobileChrome)) {
|
||||
dataTransfer.setData("URL","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||
}
|
||||
dataTransfer.setData("Text",titleString);
|
||||
event.stopPropagation();
|
||||
$tw.dragInProgress = null;
|
||||
// Invoke drag-end actions if given
|
||||
if(endActions !== undefined) {
|
||||
variables = $tw.utils.collectDOMVariables(domNode,null,event);
|
||||
variables.modifier = $tw.keyboardManager.getEventModifierKeyDescriptor(event);
|
||||
variables["actionTiddler"] = titleString;
|
||||
options.widget.invokeActionString(endActions,options.widget,event,variables);
|
||||
}
|
||||
return false;
|
||||
}},
|
||||
{name: "dragend", handlerFunction: function(event) {
|
||||
if((options.selector && $tw.utils.domMatchesSelector(event.target,options.selector)) || event.target === domNode) {
|
||||
// Collect the tiddlers being dragged
|
||||
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
|
||||
dragFilter = options.dragFilterFn && options.dragFilterFn(),
|
||||
titles = dragTiddler ? [dragTiddler] : [],
|
||||
endActions = options.endActions,
|
||||
variables;
|
||||
if(dragFilter) {
|
||||
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget));
|
||||
}
|
||||
var titleString = $tw.utils.stringifyList(titles);
|
||||
$tw.dragInProgress = null;
|
||||
// Invoke drag-end actions if given
|
||||
if(endActions !== undefined) {
|
||||
variables = $tw.utils.collectDOMVariables(domNode,null,event);
|
||||
variables.modifier = $tw.keyboardManager.getEventModifierKeyDescriptor(event);
|
||||
variables["actionTiddler"] = titleString;
|
||||
options.widget.invokeActionString(endActions,options.widget,event,variables);
|
||||
}
|
||||
// Remove the dragging class on the element being dragged
|
||||
$tw.utils.removeClass(domNode,"tc-dragging");
|
||||
// Delete the drag image element
|
||||
if(dragImage) {
|
||||
dragImage.parentNode.removeChild(dragImage);
|
||||
dragImage = null;
|
||||
}
|
||||
// Remove the dragging class on the element being dragged
|
||||
$tw.utils.removeClass(domNode,"tc-dragging");
|
||||
// Delete the drag image element
|
||||
if(dragImage) {
|
||||
dragImage.parentNode.removeChild(dragImage);
|
||||
dragImage = null;
|
||||
}
|
||||
return false;
|
||||
}}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Add event handlers
|
||||
options.widget.dragStartListenerReference = dragStartHandler;
|
||||
options.widget.dragEndListenerReference = dragEndHandler;
|
||||
$tw.utils.addEventListeners(domNode,[
|
||||
{name: "dragstart", handlerFunction: dragStartHandler},
|
||||
{name: "dragend", handlerFunction: dragEndHandler}
|
||||
]);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,12 @@ DraggableWidget.prototype.render = function(parent,nextSibling) {
|
|||
// Insert the node into the DOM and render any children
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.renderChildren(domNode,null);
|
||||
this.makeDraggable(domNode);
|
||||
this.domNodes.push(domNode);
|
||||
};
|
||||
|
||||
DraggableWidget.prototype.makeDraggable = function(domNode) {
|
||||
var self = this;
|
||||
// Add event handlers
|
||||
if(this.dragEnable) {
|
||||
$tw.utils.makeDraggable({
|
||||
|
|
@ -69,8 +75,11 @@ DraggableWidget.prototype.render = function(parent,nextSibling) {
|
|||
widget: this,
|
||||
selector: self.dragHandleSelector
|
||||
});
|
||||
} else if(this.dragStartListenerReference && this.dragEndListenerReference) {
|
||||
domNode.removeEventListener("dragstart",this.dragStartListenerReference,false);
|
||||
domNode.removeEventListener("dragend",this.dragEndListenerReference,false);
|
||||
domNode.removeAttribute("draggable");
|
||||
}
|
||||
this.domNodes.push(domNode);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -111,10 +120,17 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
|||
*/
|
||||
DraggableWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.tag || changedAttributes.selector || changedAttributes.dragimagetype || changedAttributes.enable || changedAttributes.startactions || changedAttributes.endactions) {
|
||||
if(changedAttributes.tag || changedAttributes.selector || changedAttributes.dragimagetype || changedAttributes.startactions || changedAttributes.endactions) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
this.dragEnable = this.getAttribute("enable","yes") === "yes";
|
||||
this.makeDraggable(this.domNodes[0]);
|
||||
if(!this.dragHandleSelector && this.dragEnable && (this.domNodes[0].classList && !this.domNodes[0].classList.contains("tc-draggable"))) {
|
||||
this.domNodes[0].classList.add("tc-draggable");
|
||||
} else if(!this.dragHandleSelector && !this.dragEnable && (this.domNodes[0].classList && this.domNodes[0].classList.contains("tc-draggable"))) {
|
||||
this.domNodes[0].classList.remove("tc-draggable");
|
||||
}
|
||||
if(changedAttributes["class"]) {
|
||||
this.updateDomNodeClasses();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ DroppableWidget.prototype.render = function(parent,nextSibling) {
|
|||
{name: "dragenter", handlerObject: this, handlerMethod: "handleDragEnterEvent"},
|
||||
{name: "dragover", handlerObject: this, handlerMethod: "handleDragOverEvent"},
|
||||
{name: "dragleave", handlerObject: this, handlerMethod: "handleDragLeaveEvent"},
|
||||
{name: "drop", handlerObject: this, handlerMethod: "handleDropEvent"}
|
||||
{name: "drop", handlerObject: this, handlerMethod: "handleDropEvent"},
|
||||
{name: "dragend", handlerObject: this, handlerMethod: "handleDragLeaveEvent"}
|
||||
]);
|
||||
} else {
|
||||
$tw.utils.addClass(this.domNode,this.disabledClass);
|
||||
|
|
@ -69,6 +70,11 @@ DroppableWidget.prototype.enterDrag = function(event) {
|
|||
}
|
||||
// If we're entering for the first time we need to apply highlighting
|
||||
$tw.utils.addClass(this.domNodes[0],"tc-dragover");
|
||||
// Invoke any enter actions
|
||||
if(this.droppableEnterActions) {
|
||||
var modifierKey = $tw.keyboardManager.getEventModifierKeyDescriptor(event);
|
||||
this.invokeActionString(this.droppableEnterActions,this,event,{modifier: modifierKey});
|
||||
}
|
||||
};
|
||||
|
||||
DroppableWidget.prototype.leaveDrag = function(event) {
|
||||
|
|
@ -82,6 +88,11 @@ DroppableWidget.prototype.leaveDrag = function(event) {
|
|||
if(this.domNodes[0]) {
|
||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
||||
}
|
||||
// Invoke any leave actions
|
||||
if(this.droppableLeaveActions) {
|
||||
var modifierKey = $tw.keyboardManager.getEventModifierKeyDescriptor(event);
|
||||
this.invokeActionString(this.droppableLeaveActions,this,event,{modifier: modifierKey});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -106,7 +117,20 @@ DroppableWidget.prototype.handleDragOverEvent = function(event) {
|
|||
return false;
|
||||
};
|
||||
|
||||
DroppableWidget.prototype.handleDragLeaveEvent = function(event) {
|
||||
DroppableWidget.prototype.handleDragEndEvent = function(event) {
|
||||
if(this.domNodes[0]) {
|
||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
||||
}
|
||||
this.currentlyEntered = [];
|
||||
// Invoke any end actions
|
||||
if(this.droppableEndActions) {
|
||||
var modifierKey = $tw.keyboardManager.getEventModifierKeyDescriptor(event);
|
||||
this.invokeActionString(this.droppableEndActions,this,event,{modifier: modifierKey});
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
DroppableWidget.prototype.handleDragLeaveEvent = function(event) {
|
||||
this.leaveDrag(event);
|
||||
return false;
|
||||
};
|
||||
|
|
@ -166,6 +190,9 @@ Compute the internal state of the widget
|
|||
DroppableWidget.prototype.execute = function() {
|
||||
this.droppableActions = this.getAttribute("actions");
|
||||
this.droppableListActions = this.getAttribute("listActions");
|
||||
this.droppableEnterActions = this.getAttribute("dragenteractions");
|
||||
this.droppableLeaveActions = this.getAttribute("dragleaveactions");
|
||||
this.droppableEndActions = this.getAttribute("dragendactions");
|
||||
this.droppableEffect = this.getAttribute("effect","copy");
|
||||
this.droppableTag = this.getAttribute("tag");
|
||||
this.droppableEnable = (this.getAttribute("enable") || "yes") === "yes";
|
||||
|
|
|
|||
9
core/ui/KeyboardShortcuts/toggle-dragndrop.tid
Normal file
9
core/ui/KeyboardShortcuts/toggle-dragndrop.tid
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
title: $:/core/ui/KeyboardShortcuts/toggle-dragndrop
|
||||
tags: $:/tags/KeyboardShortcut
|
||||
key: ((toggle-dragndrop))
|
||||
|
||||
<%if [{$:/config/story/dragndrop/enable}match[no]] %>
|
||||
<$action-setfield $tiddler="$:/config/story/dragndrop/enable" text="yes"/>
|
||||
<% else %>
|
||||
<$action-setfield $tiddler="$:/config/story/dragndrop/enable" text="no"/>
|
||||
<% endif %>
|
||||
|
|
@ -1,6 +1,11 @@
|
|||
title: $:/core/ui/PageTemplate/story
|
||||
tags: $:/tags/PageTemplate
|
||||
|
||||
\procedure content()
|
||||
\whitespace trim
|
||||
{{||$:/core/ui/StoryTiddlerTemplate}}
|
||||
\end
|
||||
|
||||
\whitespace trim
|
||||
<section class="tc-story-river" role="main">
|
||||
|
||||
|
|
@ -14,7 +19,11 @@ tags: $:/tags/PageTemplate
|
|||
|
||||
</section>
|
||||
|
||||
<$list filter="[list[$:/StoryList]]" history="$:/HistoryList" template="$:/core/ui/StoryTiddlerTemplate" storyview={{$:/view}} emptyMessage={{$:/config/EmptyStoryMessage}}/>
|
||||
<$list filter="[list[$:/StoryList]]" history="$:/HistoryList" storyview={{$:/view}} emptyMessage={{$:/config/EmptyStoryMessage}}>
|
||||
|
||||
<$transclude $variable="make-draggable-droppable" tiddler=<<currentTiddler>> enable={{$:/config/story/dragndrop/enable}} list="$:/StoryList" content=<<content>> styleMarginBottom="28px" stylePaddingLeft="42px" stylePaddingRight="42px"/>
|
||||
|
||||
</$list>
|
||||
|
||||
<section class="story-frontdrop">
|
||||
|
||||
|
|
|
|||
|
|
@ -5,33 +5,18 @@ caption: {{$:/language/SideBar/Open/Caption}}
|
|||
\whitespace trim
|
||||
\define lingo-base() $:/language/CloseAll/
|
||||
|
||||
\define drop-actions()
|
||||
<$action-listops $tiddler=<<tv-story-list>> $subfilter="+[insertbefore<actionTiddler>,<currentTiddler>]"/>
|
||||
\end
|
||||
|
||||
\define placeholder()
|
||||
<div class="tc-droppable-placeholder"/>
|
||||
\end
|
||||
|
||||
\define droppable-item(button)
|
||||
\whitespace trim
|
||||
<$droppable actions=<<drop-actions>> enable=<<tv-allow-drag-and-drop>> tag="div">
|
||||
<<placeholder>>
|
||||
<div>
|
||||
$button$
|
||||
\define lingo-base() $:/language/CloseAll/
|
||||
|
||||
\define content()
|
||||
<div class="tc-sidebar-tab-open-item">
|
||||
<$button message='tm-close-tiddler' tooltip={{$:/language/Buttons/Close/Hint}} aria-label={{$:/language/Buttons/Close/Caption}} class='tc-btn-invisible tc-btn-mini tc-small-gap-right'>{{$:/core/images/close-button}}</$button><$link draggable="no"/>
|
||||
</div>
|
||||
</$droppable>
|
||||
\end
|
||||
|
||||
<div class="tc-sidebar-tab-open">
|
||||
<$list filter="[list<tv-story-list>]" history=<<tv-history-list>> storyview="pop">
|
||||
<div class="tc-sidebar-tab-open-item">
|
||||
<$macrocall $name="droppable-item" button="<$button message='tm-close-tiddler' tooltip={{$:/language/Buttons/Close/Hint}} aria-label={{$:/language/Buttons/Close/Caption}} class='tc-btn-invisible tc-btn-mini tc-small-gap-right'>{{$:/core/images/close-button}}</$button><$link/>"/>
|
||||
</div>
|
||||
<$transclude $variable="make-draggable-droppable" tiddler=<<currentTiddler>> list=<<tv-story-list>> content=<<content>> animationDuration="200"/>
|
||||
</$list>
|
||||
<$tiddler tiddler="">
|
||||
<div>
|
||||
<$macrocall $name="droppable-item" button="<$button message='tm-close-all-tiddlers' class='tc-btn-invisible tc-btn-mini'><<lingo Button>></$button>"/>
|
||||
</div>
|
||||
</$tiddler>
|
||||
</div>
|
||||
<$button message='tm-close-all-tiddlers' class='tc-btn-invisible tc-btn-mini'><<lingo Button>></$button>
|
||||
|
|
|
|||
3
core/wiki/config/DragnDrop.tid
Normal file
3
core/wiki/config/DragnDrop.tid
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
title: $:/config/story/dragndrop/enable
|
||||
|
||||
no
|
||||
|
|
@ -44,6 +44,7 @@ stamp: {{$:/language/Buttons/Stamp/Hint}}
|
|||
strikethrough: {{$:/language/Buttons/Strikethrough/Hint}}
|
||||
subscript: {{$:/language/Buttons/Subscript/Hint}}
|
||||
superscript: {{$:/language/Buttons/Superscript/Hint}}
|
||||
toggle-dragndrop: {{$:/language/Buttons/ToggleDragnDrop/Hint}}
|
||||
toggle-sidebar: {{$:/language/Buttons/ToggleSidebar/Hint}}
|
||||
transcludify: {{$:/language/Buttons/Transcludify/Hint}}
|
||||
underline: {{$:/language/Buttons/Underline/Hint}}
|
||||
|
|
|
|||
|
|
@ -38,5 +38,6 @@ stamp: ctrl-S
|
|||
strikethrough: ctrl-T
|
||||
subscript: ctrl-shift-B
|
||||
superscript: ctrl-shift-P
|
||||
toggle-dragndrop: alt-D
|
||||
toggle-sidebar: alt-shift-S
|
||||
transcludify: alt-shift-T
|
||||
|
|
|
|||
349
core/wiki/macros/dragndrop.tid
Normal file
349
core/wiki/macros/dragndrop.tid
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
title: $:/core/wiki/macros/dragndrop
|
||||
tags: $:/tags/Global
|
||||
|
||||
\procedure draggable-droppable-bottom-drag-enter-actions()
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
drag-count={{{ [<dragStateTiddler>get[drag-count]add[1]] }}}
|
||||
drag-enter-class=<<qualifiedDragEnterClass>>
|
||||
/>
|
||||
<%if [<dragStateTiddler>has[drag-enter-count]] %>
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
target-before=""
|
||||
target-after={{{ [list<list>after<tiddler>] }}}
|
||||
/>
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
start-next-tiddler=""
|
||||
copy=""
|
||||
target=<<tiddler>>
|
||||
margin="bottom"
|
||||
nth={{{ [list<list>allbefore<tiddler>count[]add[1]] }}}
|
||||
next-tiddler=""
|
||||
from-index={{{ [list<list>allbefore<tiddler>count[]add[1]] }}}
|
||||
from-list=<<list>>
|
||||
drag-enter-count={{{ [<dragStateTiddler>get[drag-enter-count]add[1]] }}}
|
||||
/>
|
||||
<% else %>
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
drag-enter-count="1"
|
||||
/>
|
||||
<% endif %>
|
||||
\end
|
||||
|
||||
\procedure draggable-droppable-top-drag-enter-actions()
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
drag-count={{{ [<dragStateTiddler>get[drag-count]add[1]] }}}
|
||||
drag-enter-class=<<qualifiedDragEnterClass>>
|
||||
/>
|
||||
<%if [<dragStateTiddler>has[drag-enter-count]] %>
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
target-before={{{ [list<list>before<tiddler>] }}}
|
||||
target-after=""
|
||||
/>
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
start-next-tiddler=""
|
||||
copy=""
|
||||
target=<<tiddler>>
|
||||
margin="top"
|
||||
nth={{{ [list<list>allbefore<tiddler>count[]] }}}
|
||||
next-tiddler=""
|
||||
from-index={{{ [list<list>allbefore<tiddler>count[]] }}}
|
||||
from-list=<<list>>
|
||||
drag-enter-count={{{ [<dragStateTiddler>get[drag-enter-count]add[1]] }}}
|
||||
/>
|
||||
<% else %>
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
drag-enter-count="1"
|
||||
/>
|
||||
<% endif %>
|
||||
\end
|
||||
|
||||
\procedure draggable-droppable-bottom-drop-actions-inner()
|
||||
<$let
|
||||
nextTiddler={{{ [list<list>after<tiddler>] }}}
|
||||
>
|
||||
<%if [<nextTiddler>match[]] %>
|
||||
<$action-listops
|
||||
$tiddler=<<list>>
|
||||
$subfilter="[<actionTiddler>]"
|
||||
/>
|
||||
<!-- here we could set the current-tiddler field of the history to the value of the actionTiddler -->
|
||||
<% else %>
|
||||
<%if [<actionTiddler>!match<nextTiddler>] %>
|
||||
<$action-listops
|
||||
$tiddler=<<list>>
|
||||
$subfilter="+[insertbefore<actionTiddler>,<nextTiddler>]"
|
||||
/>
|
||||
<!-- here we could set the current-tiddler field of the history to the value of the actionTiddler -->
|
||||
<% else %>
|
||||
<$action-deletetiddler
|
||||
$tiddler={{{ [<dragStateTiddler>addsuffix[/drag-handled]] }}}
|
||||
/>
|
||||
<$action-deletetiddler
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
/>
|
||||
<% endif %>
|
||||
<% endif %>
|
||||
<$action-deletetiddler
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
/>
|
||||
<<dropActions>>
|
||||
</$let>
|
||||
<!-- here we could set the current-tiddler field of the start-history to a different value -->
|
||||
\end
|
||||
|
||||
\procedure draggable-droppable-bottom-drop-actions()
|
||||
<$action-setfield
|
||||
$tiddler={{{ [<dragStateTiddler>addsuffix[/drag-handled]] }}}
|
||||
text="yes"
|
||||
/>
|
||||
<%if [<actionTiddler>removeprefix<prefix>removesuffix<suffix>] %>
|
||||
<$let
|
||||
actionTiddler={{{ [<actionTiddler>removeprefix<prefix>removesuffix<suffix>] }}}
|
||||
>
|
||||
<$transclude
|
||||
$variable="draggable-droppable-bottom-drop-actions-inner"
|
||||
/>
|
||||
</$let>
|
||||
<% else %>
|
||||
<$transclude
|
||||
$variable="draggable-droppable-bottom-drop-actions-inner"
|
||||
/>
|
||||
<% endif %>
|
||||
<<dropActions>>
|
||||
\end
|
||||
|
||||
\procedure draggable-droppable-top-drop-actions-inner()
|
||||
<%if [<actionTiddler>!match<tiddler>] %>
|
||||
<$action-listops
|
||||
$tiddler=<<list>>
|
||||
$subfilter="+[insertbefore<actionTiddler>,<tiddler>]"
|
||||
/>
|
||||
<!-- here we could set the current-tiddler field of the history to the value of the actionTiddler -->
|
||||
<% else %>
|
||||
<$action-deletetiddler
|
||||
$tiddler={{{ [<dragStateTiddler>addsuffix[/drag-handled]] }}}
|
||||
/>
|
||||
<$action-deletetiddler
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
/>
|
||||
<% endif %>
|
||||
<$action-deletetiddler
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
/>
|
||||
<!-- here we could set the current-tiddler field of the start-history to a different value -->
|
||||
\end
|
||||
|
||||
\procedure draggable-droppable-top-drop-actions()
|
||||
<$action-setfield
|
||||
$tiddler={{{ [<dragStateTiddler>addsuffix[/drag-handled]] }}}
|
||||
text="yes"
|
||||
/>
|
||||
<%if [<actionTiddler>removeprefix<prefix>removesuffix<suffix>] %>
|
||||
<$let
|
||||
actionTiddler={{{ [<actionTiddler>removeprefix<prefix>removesuffix<suffix>] }}}
|
||||
>
|
||||
<$transclude
|
||||
$variable="draggable-droppable-top-drop-actions-inner"
|
||||
/>
|
||||
</$let>
|
||||
<% else %>
|
||||
<$transclude
|
||||
$variable="draggable-droppable-top-drop-actions-inner"
|
||||
/>
|
||||
<% endif %>
|
||||
\end
|
||||
|
||||
\procedure draggable-droppable-drag-end-actions()
|
||||
<%if [<dragStateTiddler>addsuffix[/drag-handled]is[missing]] %>
|
||||
<$let
|
||||
fromList={{{ [<dragStateTiddler>get[start-from-list]] }}}
|
||||
fromIndex={{{ [<dragStateTiddler>get[start-from-index]] }}}
|
||||
listBeforeTiddler={{{ [list<fromList>zth<fromIndex>] }}}
|
||||
actionTiddler={{{ [<actionTiddler>removeprefix<prefix>removesuffix<suffix>] :else[<actionTiddler>] }}}
|
||||
>
|
||||
<%if [<listBeforeTiddler>!is[blank]] %>
|
||||
<$action-listops
|
||||
$tiddler=<<fromStoryList>>
|
||||
$subfilter="+[insertbefore<actionTiddler>,<listBeforeTiddler>]"
|
||||
/>
|
||||
<% else %>
|
||||
<$action-listops
|
||||
$tiddler=<<fromStoryList>>
|
||||
$subfilter="[<actionTiddler>]"
|
||||
/>
|
||||
<% endif %>
|
||||
<$action-deletetiddler
|
||||
$tiddler={{{ [<dragStateTiddler>addsuffix[/drag-handled]] }}}
|
||||
/>
|
||||
<$action-deletetiddler
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
/>
|
||||
</$let>
|
||||
<% else %>
|
||||
<$action-deletetiddler
|
||||
$tiddler={{{ [<dragStateTiddler>addsuffix[/drag-handled]] }}}
|
||||
/>
|
||||
<% endif %>
|
||||
\end
|
||||
|
||||
\procedure draggable-droppable-drag-start-actions()
|
||||
<$let
|
||||
nth={{{ [list<list>allbefore<tiddler>count[]] }}}
|
||||
listLength={{{ [list<list>count[]subtract[1]] }}}
|
||||
>
|
||||
<%if [<nth>match<listLength>] %>
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
before-tiddler={{{ [list<list>before<tiddler>] }}}
|
||||
/>
|
||||
<% endif %>
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
drag-count="0"
|
||||
nth=<<nth>>
|
||||
height=<<tv-selectednode-height>>
|
||||
width=<<tv-selectednode-width>>
|
||||
margin-bottom=<<styleMarginBottom>>
|
||||
start-next-tiddler={{{ [list<list>after<tiddler>] }}}
|
||||
start-from-index={{{ [list<list>allbefore<tiddler>count[]] }}}
|
||||
start-from-list=<<list>>
|
||||
/>
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
drag-tiddler=<<tiddler>>
|
||||
next-tiddler={{{ [list<list>after<tiddler>] }}}
|
||||
from-index={{{ [list<list>allbefore<tiddler>count[]] }}}
|
||||
from-list=<<list>>
|
||||
from-history=<<history>>
|
||||
target={{{ [list<list>after<tiddler>] }}}
|
||||
/>
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
tags="$:/tags/DragStateTiddler"
|
||||
text="yes"
|
||||
/>
|
||||
<%if [<modifier>!match[ctrl]] %>
|
||||
<$action-listops
|
||||
$tiddler=<<list>>
|
||||
$subfilter="-[<tiddler>]"
|
||||
/>
|
||||
<% else %>
|
||||
<$action-setfield
|
||||
$tiddler=<<dragStateTiddler>>
|
||||
copy="yes"
|
||||
/>
|
||||
<% endif %>
|
||||
</$let>
|
||||
\end
|
||||
|
||||
\function get.drag.state.tiddler.height() [<dragStateTiddler>get[height]addsuffix[px]]
|
||||
\function get.drag.state.tiddler.margin.bottom() [<dragStateTiddler>get[margin-bottom]]
|
||||
|
||||
\function get.draggable.droppable.bottom.class() tc-draggable-droppable-drop-bottom [<dragStateTiddler>get[margin]match[bottom]then<qualifiedDragEnterClass>] :and[join[ ]]
|
||||
\function get.draggable.droppable.top.class() tc-draggable-droppable-drop-top [<dragStateTiddler>get[margin]match[top]then<qualifiedDragEnterClass>] :and[join[ ]]
|
||||
|
||||
\function get.tiddler.before.target() [<dragStateTiddler>get[target]] :reduce[list<list>before<currentTiddler>]
|
||||
\function get.tiddler.after.target() [<dragStateTiddler>get[target]] :reduce[list<list>after<currentTiddler>]
|
||||
|
||||
\function get.styleTransition()
|
||||
[<dragStateTiddler>get[start-next-tiddler]match<tiddler>then[none]]
|
||||
:else[[margin-top ]addsuffix<animationDuration>addsuffix[ms ]addsuffix<animationCurve>addsuffix[, margin-bottom ]addsuffix<animationDuration>addsuffix[ms ]addsuffix<animationCurve>]
|
||||
\end
|
||||
|
||||
\function get.styleTop() [<dragStateTiddler>get[start-next-tiddler]match<tiddler>then[calc(-]addsuffix<get.drag.state.tiddler.height>addsuffix[ - (2 * ]addsuffix<get.drag.state.tiddler.margin.bottom>addsuffix[)]] :else[<dragStateTiddler>get[drag-enter-class]match<qualifiedDragEnterClass>then<dragStateTiddler>get[margin]match[top]then[calc(-]addsuffix<get.drag.state.tiddler.height>addsuffix[ - (2 * ]addsuffix<get.drag.state.tiddler.margin.bottom>addsuffix[)]] :else[[calc( ]addsuffix[-]addsuffix<styleMarginTop>addsuffix[)]]
|
||||
|
||||
\function get.styleBottom() [[calc( ]addsuffix[-]addsuffix<styleMarginBottom>addsuffix[)]]
|
||||
\function get.styleLeft() [[calc( ]addsuffix[-]addsuffix<stylePaddingLeft>addsuffix[)]]
|
||||
|
||||
\function get.styleTopHeight() [<dragStateTiddler>get[start-next-tiddler]match<tiddler>then[calc(50% + ]addsuffix<get.drag.state.tiddler.margin.bottom>addsuffix[ + ]addsuffix<get.drag.state.tiddler.height>addsuffix[)]] :else[<dragStateTiddler>get[drag-enter-class]match<qualifiedDragEnterClass>then<dragStateTiddler>get[margin]match[top]then[calc(50% + (2 * ]addsuffix<get.drag.state.tiddler.margin.bottom>addsuffix[) + ]addsuffix<get.drag.state.tiddler.height>addsuffix[)]] :else[[calc(50% + ]addsuffix<styleMarginBottom>addsuffix[)]]
|
||||
|
||||
\function get.styleBottomHeight() [<dragStateTiddler>get[drag-enter-class]match<qualifiedDragEnterClass>then<dragStateTiddler>get[margin]match[bottom]then[calc(50% + ]addsuffix<get.drag.state.tiddler.height>addsuffix[ + ]addsuffix<get.drag.state.tiddler.margin.bottom>addsuffix[)]] :else[[50%]]
|
||||
|
||||
\function get.styleWidth() [[calc(100% + ]addsuffix<stylePaddingLeft>addsuffix[ + ]addsuffix<stylePaddingRight>addsuffix[)]]
|
||||
|
||||
\function get.styleMarginTop() [<dragStateTiddler>get[start-next-tiddler]match<tiddler>then[calc(]addsuffix<get.drag.state.tiddler.height>addsuffix[ + (2 * ]addsuffix<get.drag.state.tiddler.margin.bottom>addsuffix[))]] :else[<dragStateTiddler>get[drag-enter-class]match<qualifiedDragEnterClass>then<dragStateTiddler>get[margin]match[top]then<dragStateTiddler>get[height]addsuffix[px]addprefix[calc(]addsuffix[ + (2 * ]addsuffix<styleMarginBottom>addsuffix[))]] :else[[0px]]
|
||||
\function get.styleMarginBottom() [<dragStateTiddler>get[drag-enter-class]match<qualifiedDragEnterClass>then<dragStateTiddler>get[margin]match[bottom]then<dragStateTiddler>get[height]addsuffix[px]addprefix[calc(]addsuffix[ + (2 * ]addsuffix<styleMarginBottom>addsuffix[))]] :else[[0px]]
|
||||
|
||||
\function get.draggable.droppable.class() tc-draggable-droppable-qualifier [<qualifiedDragEnterClass>] :and[join[ ]]
|
||||
\function get.flexDirection() [<direction>match[vertical]then[row]] [<direction>match[horizontal]then[column]]
|
||||
|
||||
\procedure make-draggable-droppable(tiddler:"",class:"",content:"",list:"",enable:"yes",dropActions:"",history:"",dragStateTiddler:"$:/state/tiddlywiki/dragging",direction:"vertical",styleMarginTop:"0px",styleMarginBottom:"0px",stylePaddingLeft:"0px",stylePaddingRight:"0px",styleZIndex:"501",animationDuration:"175",animationCurve:"linear")
|
||||
\whitespace trim
|
||||
<$tiddler tiddler=<<tiddler>>>
|
||||
<$let
|
||||
prefix="[["
|
||||
suffix="]]"
|
||||
transclusion=<<tiddler>>
|
||||
qualifiedDragEnterClass={{{ [<tiddler>addsuffix<qualfiy>sha256[64]] }}}
|
||||
>
|
||||
<$draggable
|
||||
enable=<<enable>>
|
||||
tiddler=<<tiddler>>
|
||||
startactions=<<draggable-droppable-drag-start-actions>>
|
||||
endactions=<<draggable-droppable-drag-end-actions>>
|
||||
class=<<class>>
|
||||
>
|
||||
<div
|
||||
class=<<get.draggable.droppable.class>>
|
||||
style.display="flex"
|
||||
style.position="relative"
|
||||
style.flex-direction=<<get.flexDirection>>
|
||||
style.border="none"
|
||||
style.margin-top=<<get.styleMarginTop>>
|
||||
style.margin-bottom=<<get.styleMarginBottom>>
|
||||
style.transition=<<get.styleTransition>>
|
||||
>
|
||||
<$set name="tv-enable-drag-and-drop" value={{{ [<enable>match[yes]then[no]] :else[<tv-enable-drag-and-drop>] }}}>
|
||||
<<content>>
|
||||
</$set>
|
||||
<%if [<dragStateTiddler>get[text]match[yes]] %>
|
||||
<%if [<direction>match[vertical]] %>
|
||||
<$droppable
|
||||
class=<<get.draggable.droppable.top.class>>
|
||||
actions=<<draggable-droppable-top-drop-actions>>
|
||||
dragenteractions=<<draggable-droppable-top-drag-enter-actions>>
|
||||
>
|
||||
<div
|
||||
class="tc-draggable-droppable-drop-top-placeholder"
|
||||
style.position="absolute"
|
||||
style.border="none"
|
||||
style.top=<<get.styleTop>>
|
||||
style.left=<<get.styleLeft>>
|
||||
style.height=<<get.styleTopHeight>>
|
||||
style.width=<<get.styleWidth>>
|
||||
style.z-index=<<styleZIndex>>
|
||||
/>
|
||||
</$droppable>
|
||||
<$droppable
|
||||
class=<<get.draggable.droppable.bottom.class>>
|
||||
actions=<<draggable-droppable-bottom-drop-actions>>
|
||||
dragenteractions=<<draggable-droppable-bottom-drag-enter-actions>>
|
||||
>
|
||||
<div
|
||||
class="tc-draggable-droppable-drop-bottom-placeholder"
|
||||
style.position="absolute"
|
||||
style.border="none"
|
||||
style.top="50%"
|
||||
style.left=<<get.styleLeft>>
|
||||
style.height=<<get.styleBottomHeight>>
|
||||
style.width=<<get.styleWidth>>
|
||||
style.z-index=<<styleZIndex>>
|
||||
/>
|
||||
</$droppable>
|
||||
<%elseif [<direction>match[horizontal]] %>
|
||||
<!-- horizontal handling missing at the moment -->
|
||||
<% endif %>
|
||||
<% endif %>
|
||||
</div>
|
||||
</$draggable>
|
||||
</$let>
|
||||
</$tiddler>
|
||||
\end
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
title: $:/changenotes/5.4.0/#9507
|
||||
created: 20251218204100502
|
||||
modified: 20251218204100502
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: enhancement
|
||||
change-category: usability
|
||||
description: Dragndrop procedures for enhanced dragndrop lists
|
||||
release: 5.4.0
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9507
|
||||
github-contributors: BurningTreeC
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
This pull request extends Tiddlywiki with advanced drag-and-drop procedures.
|
||||
|
||||
Lists can be expanded using drag-and-drop, and the drag-and-drop experience feels more natural.
|
||||
Loading…
Add table
Add a link
Reference in a new issue