mirror of
https://github.com/Jermolene/TiddlyWiki5.git
synced 2025-12-06 02:30:46 -08:00
Merge c5d46f6425 into 5cd3084298
This commit is contained in:
commit
bc840fa471
4 changed files with 912 additions and 69 deletions
|
|
@ -9,34 +9,539 @@ A simple slide animation that varies the height of the element
|
|||
|
||||
"use strict";
|
||||
|
||||
// Helper function to get current computed dimensions during animation
|
||||
function getCurrentDimensions(domNode, isHorizontal) {
|
||||
var computedStyle = window.getComputedStyle(domNode);
|
||||
if(isHorizontal) {
|
||||
return {
|
||||
size: parseFloat(computedStyle.width) || 0,
|
||||
marginStart: parseFloat(computedStyle.marginLeft) || 0,
|
||||
marginEnd: parseFloat(computedStyle.marginRight) || 0,
|
||||
paddingStart: parseFloat(computedStyle.paddingLeft) || 0,
|
||||
paddingEnd: parseFloat(computedStyle.paddingRight) || 0,
|
||||
opacity: parseFloat(computedStyle.opacity) || 0
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
size: parseFloat(computedStyle.height) || 0,
|
||||
marginStart: parseFloat(computedStyle.marginTop) || 0,
|
||||
marginEnd: parseFloat(computedStyle.marginBottom) || 0,
|
||||
paddingStart: parseFloat(computedStyle.paddingTop) || 0,
|
||||
paddingEnd: parseFloat(computedStyle.paddingBottom) || 0,
|
||||
opacity: parseFloat(computedStyle.opacity) || 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to check if element is currently animating
|
||||
function isAnimating(domNode) {
|
||||
return domNode.dataset.slideAnimating === "true";
|
||||
}
|
||||
|
||||
// Helper to mark animation state
|
||||
function setAnimating(domNode, state) {
|
||||
if(state) {
|
||||
domNode.dataset.slideAnimating = "true";
|
||||
} else {
|
||||
delete domNode.dataset.slideAnimating;
|
||||
}
|
||||
}
|
||||
|
||||
function slideOpen(domNode,options) {
|
||||
options = options || {};
|
||||
var duration = options.duration || $tw.utils.getAnimationDuration();
|
||||
// Get the current height of the domNode
|
||||
var direction = options.direction || "vertical";
|
||||
var isHorizontal = direction === "horizontal";
|
||||
var origin = options.origin || (isHorizontal ? "left" : "top");
|
||||
|
||||
// If currently animating, capture current state
|
||||
var startState;
|
||||
var needsTargetDimensions = true;
|
||||
|
||||
if(isAnimating(domNode)) {
|
||||
startState = getCurrentDimensions(domNode, isHorizontal);
|
||||
// Remove any existing transition end handlers
|
||||
var oldHandler = domNode._slideTransitionHandler;
|
||||
if(oldHandler) {
|
||||
domNode.removeEventListener("transitionend", oldHandler);
|
||||
}
|
||||
// Always recalculate target dimensions when opening
|
||||
// (the element's natural size may have changed while it was closing)
|
||||
needsTargetDimensions = true;
|
||||
} else {
|
||||
startState = {
|
||||
size: 0,
|
||||
marginStart: 0,
|
||||
marginEnd: 0,
|
||||
paddingStart: 0,
|
||||
paddingEnd: 0,
|
||||
opacity: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Get or update target dimensions
|
||||
if(needsTargetDimensions) {
|
||||
// If we're in the middle of an animation, we need to temporarily reset the element
|
||||
// to get its natural dimensions
|
||||
var originalStyles = {};
|
||||
if(isAnimating(domNode)) {
|
||||
// Store current styles
|
||||
originalStyles.height = domNode.style.height;
|
||||
originalStyles.width = domNode.style.width;
|
||||
originalStyles.transition = domNode.style.transition;
|
||||
|
||||
// Temporarily reset to get natural dimensions
|
||||
domNode.style.transition = "none";
|
||||
domNode.style.height = "";
|
||||
domNode.style.width = "";
|
||||
$tw.utils.forceLayout(domNode);
|
||||
}
|
||||
|
||||
var computedStyle = window.getComputedStyle(domNode),
|
||||
currMarginBottom = parseInt(computedStyle.marginBottom,10),
|
||||
currMarginTop = parseInt(computedStyle.marginTop,10),
|
||||
currPaddingBottom = parseInt(computedStyle.paddingBottom,10),
|
||||
currPaddingTop = parseInt(computedStyle.paddingTop,10),
|
||||
currHeight = domNode.offsetHeight;
|
||||
// Reset the margin once the transition is over
|
||||
setTimeout(function() {
|
||||
targetMarginBottom = parseInt(computedStyle.marginBottom,10),
|
||||
targetMarginTop = parseInt(computedStyle.marginTop,10),
|
||||
targetMarginLeft = parseInt(computedStyle.marginLeft,10),
|
||||
targetMarginRight = parseInt(computedStyle.marginRight,10),
|
||||
targetPaddingBottom = parseInt(computedStyle.paddingBottom,10),
|
||||
targetPaddingTop = parseInt(computedStyle.paddingTop,10),
|
||||
targetPaddingLeft = parseInt(computedStyle.paddingLeft,10),
|
||||
targetPaddingRight = parseInt(computedStyle.paddingRight,10),
|
||||
targetHeight = domNode.offsetHeight,
|
||||
targetWidth = domNode.offsetWidth;
|
||||
|
||||
// Restore original styles if we changed them
|
||||
if(isAnimating(domNode)) {
|
||||
domNode.style.height = originalStyles.height;
|
||||
domNode.style.width = originalStyles.width;
|
||||
domNode.style.transition = originalStyles.transition;
|
||||
}
|
||||
|
||||
// Store target dimensions for potential interruption
|
||||
domNode._slideTargetDimensions = {
|
||||
marginBottom: targetMarginBottom,
|
||||
marginTop: targetMarginTop,
|
||||
marginLeft: targetMarginLeft,
|
||||
marginRight: targetMarginRight,
|
||||
paddingBottom: targetPaddingBottom,
|
||||
paddingTop: targetPaddingTop,
|
||||
paddingLeft: targetPaddingLeft,
|
||||
paddingRight: targetPaddingRight,
|
||||
height: targetHeight,
|
||||
width: targetWidth
|
||||
};
|
||||
}
|
||||
|
||||
// Mark as animating
|
||||
setAnimating(domNode, true);
|
||||
|
||||
// Reset the properties once the transition is over
|
||||
var transitionEndHandler = function() {
|
||||
domNode.removeEventListener("transitionend", transitionEndHandler);
|
||||
delete domNode._slideTransitionHandler;
|
||||
setAnimating(domNode, false);
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "none"},
|
||||
{transition: ""},
|
||||
{marginBottom: ""},
|
||||
{marginTop: ""},
|
||||
{marginLeft: ""},
|
||||
{marginRight: ""},
|
||||
{paddingBottom: ""},
|
||||
{paddingTop: ""},
|
||||
{height: "auto"},
|
||||
{opacity: ""}
|
||||
{paddingLeft: ""},
|
||||
{paddingRight: ""},
|
||||
{height: ""},
|
||||
{width: ""},
|
||||
{opacity: ""},
|
||||
{overflow: ""},
|
||||
{willChange: ""}
|
||||
]);
|
||||
delete domNode._slideTargetDimensions;
|
||||
if(options.callback) {
|
||||
options.callback();
|
||||
}
|
||||
},duration);
|
||||
// Set up the initial position of the element
|
||||
};
|
||||
|
||||
// Store handler reference for potential interruption
|
||||
domNode._slideTransitionHandler = transitionEndHandler;
|
||||
|
||||
// Set up the initial position
|
||||
$tw.utils.setStyle(domNode,[{transition: "none"}]);
|
||||
|
||||
var targets = domNode._slideTargetDimensions;
|
||||
|
||||
if(isHorizontal) {
|
||||
// For horizontal slides, the approach depends on origin
|
||||
if(origin === "right") {
|
||||
// For right origin, element slides in from the right
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "none"},
|
||||
{marginLeft: targets.marginLeft + "px"},
|
||||
{marginRight: (-targets.width - targets.marginLeft - targets.marginRight - targets.paddingLeft - targets.paddingRight) + "px"},
|
||||
{paddingLeft: targets.paddingLeft + "px"},
|
||||
{paddingRight: targets.paddingRight + "px"},
|
||||
{width: targets.width + "px"},
|
||||
{opacity: startState.opacity},
|
||||
{overflow: "hidden"},
|
||||
{willChange: "margin-right, opacity"}
|
||||
]);
|
||||
} else if(origin === "center") {
|
||||
// For center origin, start with zero width and center margins
|
||||
var totalWidth = targets.width + targets.paddingLeft + targets.paddingRight;
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{marginLeft: (totalWidth / 2) + targets.marginLeft + "px"},
|
||||
{marginRight: (totalWidth / 2) + targets.marginRight + "px"},
|
||||
{paddingLeft: startState.paddingStart + "px"},
|
||||
{paddingRight: startState.paddingEnd + "px"},
|
||||
{width: startState.size + "px"},
|
||||
{opacity: startState.opacity},
|
||||
{overflow: "hidden"},
|
||||
{willChange: "width, opacity, margin-left, margin-right, padding-left, padding-right"}
|
||||
]);
|
||||
} else {
|
||||
// Default left origin
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{marginLeft: startState.marginStart + "px"},
|
||||
{marginRight: startState.marginEnd + "px"},
|
||||
{paddingLeft: startState.paddingStart + "px"},
|
||||
{paddingRight: startState.paddingEnd + "px"},
|
||||
{width: startState.size + "px"},
|
||||
{opacity: startState.opacity},
|
||||
{overflow: "hidden"},
|
||||
{willChange: "width, opacity, margin-left, margin-right, padding-left, padding-right"}
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
// For vertical slides
|
||||
if(origin === "bottom") {
|
||||
// For bottom origin, use negative margin-top to hide the element
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{marginTop: (-targets.height - targets.marginTop - targets.marginBottom - targets.paddingTop - targets.paddingBottom) + "px"},
|
||||
{marginBottom: targets.marginBottom + "px"},
|
||||
{paddingTop: targets.paddingTop + "px"},
|
||||
{paddingBottom: targets.paddingBottom + "px"},
|
||||
{height: targets.height + "px"},
|
||||
{opacity: startState.opacity},
|
||||
{overflow: "hidden"},
|
||||
{willChange: "margin-top, opacity"}
|
||||
]);
|
||||
} else if(origin === "center") {
|
||||
// For center origin, start with zero height and center margins
|
||||
var totalHeight = targets.height + targets.paddingTop + targets.paddingBottom;
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{marginTop: (totalHeight / 2) + targets.marginTop + "px"},
|
||||
{marginBottom: (totalHeight / 2) + targets.marginBottom + "px"},
|
||||
{paddingTop: startState.paddingStart + "px"},
|
||||
{paddingBottom: startState.paddingEnd + "px"},
|
||||
{height: startState.size + "px"},
|
||||
{opacity: startState.opacity},
|
||||
{overflow: "hidden"},
|
||||
{willChange: "height, opacity, margin-top, margin-bottom, padding-top, padding-bottom"}
|
||||
]);
|
||||
} else {
|
||||
// Default top origin
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{marginTop: startState.marginStart + "px"},
|
||||
{marginBottom: startState.marginEnd + "px"},
|
||||
{paddingTop: startState.paddingStart + "px"},
|
||||
{paddingBottom: startState.paddingEnd + "px"},
|
||||
{height: startState.size + "px"},
|
||||
{opacity: startState.opacity},
|
||||
{overflow: "hidden"},
|
||||
{willChange: "height, opacity, margin-top, margin-bottom, padding-top, padding-bottom"}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$tw.utils.forceLayout(domNode);
|
||||
|
||||
// Add transition end listener
|
||||
domNode.addEventListener("transitionend", transitionEndHandler);
|
||||
|
||||
// Transition to the final position
|
||||
var easing = options.easing || "cubic-bezier(0.4, 0.0, 0.2, 1)";
|
||||
|
||||
if(isHorizontal) {
|
||||
// Different transitions based on origin
|
||||
if(origin === "right") {
|
||||
// For right origin, we only animate margin-right
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-right " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing},
|
||||
{marginRight: targets.marginRight + "px"},
|
||||
{opacity: "1"}
|
||||
]);
|
||||
} else if(origin === "center") {
|
||||
// For center origin, animate width and margins
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-left " + duration + "ms " + easing + ", " +
|
||||
"margin-right " + duration + "ms " + easing + ", " +
|
||||
"padding-left " + duration + "ms " + easing + ", " +
|
||||
"padding-right " + duration + "ms " + easing + ", " +
|
||||
"width " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing},
|
||||
{marginLeft: targets.marginLeft + "px"},
|
||||
{marginRight: targets.marginRight + "px"},
|
||||
{paddingLeft: targets.paddingLeft + "px"},
|
||||
{paddingRight: targets.paddingRight + "px"},
|
||||
{width: targets.width + "px"},
|
||||
{opacity: "1"}
|
||||
]);
|
||||
} else {
|
||||
// Default left origin
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-left " + duration + "ms " + easing + ", " +
|
||||
"margin-right " + duration + "ms " + easing + ", " +
|
||||
"padding-left " + duration + "ms " + easing + ", " +
|
||||
"padding-right " + duration + "ms " + easing + ", " +
|
||||
"width " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing},
|
||||
{marginLeft: targets.marginLeft + "px"},
|
||||
{marginRight: targets.marginRight + "px"},
|
||||
{paddingLeft: targets.paddingLeft + "px"},
|
||||
{paddingRight: targets.paddingRight + "px"},
|
||||
{width: targets.width + "px"},
|
||||
{opacity: "1"}
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
// Different transitions based on origin for vertical
|
||||
if(origin === "bottom") {
|
||||
// For bottom origin, we only animate margin-top
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-top " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing},
|
||||
{marginTop: targets.marginTop + "px"},
|
||||
{opacity: "1"}
|
||||
]);
|
||||
} else if(origin === "center") {
|
||||
// For center origin, animate height and margins
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-top " + duration + "ms " + easing + ", " +
|
||||
"margin-bottom " + duration + "ms " + easing + ", " +
|
||||
"padding-top " + duration + "ms " + easing + ", " +
|
||||
"padding-bottom " + duration + "ms " + easing + ", " +
|
||||
"height " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing},
|
||||
{marginTop: targets.marginTop + "px"},
|
||||
{marginBottom: targets.marginBottom + "px"},
|
||||
{paddingTop: targets.paddingTop + "px"},
|
||||
{paddingBottom: targets.paddingBottom + "px"},
|
||||
{height: targets.height + "px"},
|
||||
{opacity: "1"}
|
||||
]);
|
||||
} else {
|
||||
// Default top origin
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-top " + duration + "ms " + easing + ", " +
|
||||
"margin-bottom " + duration + "ms " + easing + ", " +
|
||||
"padding-top " + duration + "ms " + easing + ", " +
|
||||
"padding-bottom " + duration + "ms " + easing + ", " +
|
||||
"height " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing},
|
||||
{marginBottom: targets.marginBottom + "px"},
|
||||
{marginTop: targets.marginTop + "px"},
|
||||
{paddingBottom: targets.paddingBottom + "px"},
|
||||
{paddingTop: targets.paddingTop + "px"},
|
||||
{height: targets.height + "px"},
|
||||
{opacity: "1"}
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function slideClosed(domNode,options) {
|
||||
options = options || {};
|
||||
var duration = options.duration || $tw.utils.getAnimationDuration();
|
||||
var direction = options.direction || "vertical";
|
||||
var isHorizontal = direction === "horizontal";
|
||||
var origin = options.origin || (isHorizontal ? "left" : "top");
|
||||
|
||||
// If currently animating, capture current state
|
||||
var startState;
|
||||
if(isAnimating(domNode)) {
|
||||
startState = getCurrentDimensions(domNode, isHorizontal);
|
||||
// Remove any existing transition end handlers
|
||||
var oldHandler = domNode._slideTransitionHandler;
|
||||
if(oldHandler) {
|
||||
domNode.removeEventListener("transitionend", oldHandler);
|
||||
}
|
||||
// Adjust duration based on current progress
|
||||
var progress = startState.opacity; // Use opacity as progress indicator
|
||||
duration = Math.round(duration * progress);
|
||||
} else {
|
||||
// Normal starting state
|
||||
startState = {
|
||||
size: isHorizontal ? domNode.offsetWidth : domNode.offsetHeight,
|
||||
marginStart: parseFloat(window.getComputedStyle(domNode)[isHorizontal ? "marginLeft" : "marginTop"]) || 0,
|
||||
marginEnd: parseFloat(window.getComputedStyle(domNode)[isHorizontal ? "marginRight" : "marginBottom"]) || 0,
|
||||
paddingStart: parseFloat(window.getComputedStyle(domNode)[isHorizontal ? "paddingLeft" : "paddingTop"]) || 0,
|
||||
paddingEnd: parseFloat(window.getComputedStyle(domNode)[isHorizontal ? "paddingRight" : "paddingBottom"]) || 0,
|
||||
opacity: 1
|
||||
};
|
||||
}
|
||||
|
||||
// Mark as animating
|
||||
setAnimating(domNode, true);
|
||||
|
||||
// Clear the properties when animation is over
|
||||
var transitionEndHandler = function() {
|
||||
domNode.removeEventListener("transitionend", transitionEndHandler);
|
||||
delete domNode._slideTransitionHandler;
|
||||
setAnimating(domNode, false);
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: ""},
|
||||
{marginBottom: ""},
|
||||
{marginTop: ""},
|
||||
{marginLeft: ""},
|
||||
{marginRight: ""},
|
||||
{paddingBottom: ""},
|
||||
{paddingTop: ""},
|
||||
{paddingLeft: ""},
|
||||
{paddingRight: ""},
|
||||
{height: ""},
|
||||
{width: ""},
|
||||
{opacity: ""},
|
||||
{overflow: ""},
|
||||
{willChange: ""}
|
||||
]);
|
||||
delete domNode._slideTargetDimensions;
|
||||
if(options.callback) {
|
||||
options.callback();
|
||||
}
|
||||
};
|
||||
|
||||
// Store handler reference
|
||||
domNode._slideTransitionHandler = transitionEndHandler;
|
||||
|
||||
// Set up the initial position
|
||||
$tw.utils.setStyle(domNode,[{transition: "none"}]);
|
||||
|
||||
if(isHorizontal) {
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{width: startState.size + "px"},
|
||||
{marginLeft: startState.marginStart + "px"},
|
||||
{marginRight: startState.marginEnd + "px"},
|
||||
{paddingLeft: startState.paddingStart + "px"},
|
||||
{paddingRight: startState.paddingEnd + "px"},
|
||||
{opacity: startState.opacity},
|
||||
{overflow: "hidden"},
|
||||
{willChange: "width, opacity, margin-left, margin-right, padding-left, padding-right"}
|
||||
]);
|
||||
} else {
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{height: startState.size + "px"},
|
||||
{marginTop: startState.marginStart + "px"},
|
||||
{marginBottom: startState.marginEnd + "px"},
|
||||
{paddingTop: startState.paddingStart + "px"},
|
||||
{paddingBottom: startState.paddingEnd + "px"},
|
||||
{opacity: startState.opacity},
|
||||
{overflow: "hidden"},
|
||||
{willChange: "height, opacity, margin-top, margin-bottom, padding-top, padding-bottom"}
|
||||
]);
|
||||
}
|
||||
|
||||
$tw.utils.forceLayout(domNode);
|
||||
|
||||
// Add transition end listener
|
||||
domNode.addEventListener("transitionend", transitionEndHandler);
|
||||
|
||||
// Transition to the final position
|
||||
var easing = options.easing || "cubic-bezier(0.4, 0.0, 0.2, 1)";
|
||||
|
||||
// Get computed style for calculating negative margins
|
||||
var computedStyle = window.getComputedStyle(domNode);
|
||||
var currentWidth = domNode.offsetWidth;
|
||||
var currentHeight = domNode.offsetHeight;
|
||||
var marginLeft = parseInt(computedStyle.marginLeft, 10) || 0;
|
||||
var marginRight = parseInt(computedStyle.marginRight, 10) || 0;
|
||||
var marginTop = parseInt(computedStyle.marginTop, 10) || 0;
|
||||
var marginBottom = parseInt(computedStyle.marginBottom, 10) || 0;
|
||||
var paddingLeft = parseInt(computedStyle.paddingLeft, 10) || 0;
|
||||
var paddingRight = parseInt(computedStyle.paddingRight, 10) || 0;
|
||||
var paddingTop = parseInt(computedStyle.paddingTop, 10) || 0;
|
||||
var paddingBottom = parseInt(computedStyle.paddingBottom, 10) || 0;
|
||||
|
||||
if(isHorizontal) {
|
||||
// Different transitions based on origin
|
||||
if(origin === "right") {
|
||||
// For right origin, slide out to the right using negative margin-right
|
||||
var totalWidth = currentWidth + marginLeft + marginRight + paddingLeft + paddingRight;
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-right " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing},
|
||||
{marginRight: (-totalWidth) + "px"},
|
||||
{opacity: "0"}
|
||||
]);
|
||||
} else if(origin === "center") {
|
||||
// For center origin, collapse width and expand margins
|
||||
var halfWidth = (currentWidth + paddingLeft + paddingRight) / 2;
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-left " + duration + "ms " + easing + ", " +
|
||||
"margin-right " + duration + "ms " + easing + ", " +
|
||||
"padding-left " + duration + "ms " + easing + ", " +
|
||||
"padding-right " + duration + "ms " + easing + ", " +
|
||||
"width " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing},
|
||||
{marginLeft: (marginLeft + halfWidth) + "px"},
|
||||
{marginRight: (marginRight + halfWidth) + "px"},
|
||||
{paddingLeft: "0px"},
|
||||
{paddingRight: "0px"},
|
||||
{width: "0px"},
|
||||
{opacity: "0"}
|
||||
]);
|
||||
} else {
|
||||
// Default left origin
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-left " + duration + "ms " + easing + ", " +
|
||||
"margin-right " + duration + "ms " + easing + ", " +
|
||||
"padding-left " + duration + "ms " + easing + ", " +
|
||||
"padding-right " + duration + "ms " + easing + ", " +
|
||||
"width " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing},
|
||||
{marginLeft: "0px"},
|
||||
{marginRight: "0px"},
|
||||
{paddingLeft: "0px"},
|
||||
{paddingRight: "0px"},
|
||||
{width: "0px"},
|
||||
{opacity: "0"}
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
// Different transitions based on origin for vertical
|
||||
if(origin === "bottom") {
|
||||
// For bottom origin, slide out to the bottom using negative margin-top
|
||||
var totalHeight = currentHeight + marginTop + marginBottom + paddingTop + paddingBottom;
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-top " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing},
|
||||
{marginTop: (-totalHeight) + "px"},
|
||||
{opacity: "0"}
|
||||
]);
|
||||
} else if(origin === "center") {
|
||||
// For center origin, collapse height and expand margins
|
||||
var halfHeight = (currentHeight + paddingTop + paddingBottom) / 2;
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-top " + duration + "ms " + easing + ", " +
|
||||
"margin-bottom " + duration + "ms " + easing + ", " +
|
||||
"padding-top " + duration + "ms " + easing + ", " +
|
||||
"padding-bottom " + duration + "ms " + easing + ", " +
|
||||
"height " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing},
|
||||
{marginTop: (marginTop + halfHeight) + "px"},
|
||||
{marginBottom: (marginBottom + halfHeight) + "px"},
|
||||
{paddingTop: "0px"},
|
||||
{paddingBottom: "0px"},
|
||||
{height: "0px"},
|
||||
{opacity: "0"}
|
||||
]);
|
||||
} else {
|
||||
// Default top origin
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-top " + duration + "ms " + easing + ", " +
|
||||
"margin-bottom " + duration + "ms " + easing + ", " +
|
||||
"padding-top " + duration + "ms " + easing + ", " +
|
||||
"padding-bottom " + duration + "ms " + easing + ", " +
|
||||
"height " + duration + "ms " + easing + ", " +
|
||||
"opacity " + duration + "ms " + easing},
|
||||
{marginTop: "0px"},
|
||||
{marginBottom: "0px"},
|
||||
{paddingTop: "0px"},
|
||||
|
|
@ -44,67 +549,343 @@ function slideOpen(domNode,options) {
|
|||
{height: "0px"},
|
||||
{opacity: "0"}
|
||||
]);
|
||||
$tw.utils.forceLayout(domNode);
|
||||
// Transition to the final position
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-top " + duration + "ms ease-in-out, " +
|
||||
"margin-bottom " + duration + "ms ease-in-out, " +
|
||||
"padding-top " + duration + "ms ease-in-out, " +
|
||||
"padding-bottom " + duration + "ms ease-in-out, " +
|
||||
"height " + duration + "ms ease-in-out, " +
|
||||
"opacity " + duration + "ms ease-in-out"},
|
||||
{marginBottom: currMarginBottom + "px"},
|
||||
{marginTop: currMarginTop + "px"},
|
||||
{paddingBottom: currPaddingBottom + "px"},
|
||||
{paddingTop: currPaddingTop + "px"},
|
||||
{height: currHeight + "px"},
|
||||
{opacity: "1"}
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function slideClosed(domNode,options) {
|
||||
// Transform-based versions with interruption support
|
||||
function slideOpenTransform(domNode,options) {
|
||||
options = options || {};
|
||||
var duration = options.duration || $tw.utils.getAnimationDuration(),
|
||||
currHeight = domNode.offsetHeight;
|
||||
// Clear the properties we've set when the animation is over
|
||||
setTimeout(function() {
|
||||
var duration = options.duration || $tw.utils.getAnimationDuration();
|
||||
var direction = options.direction || "vertical";
|
||||
var isHorizontal = direction === "horizontal";
|
||||
|
||||
// Get current transform if animating
|
||||
var startScale = 0;
|
||||
var startOpacity = 0;
|
||||
if(isAnimating(domNode)) {
|
||||
var computedStyle = window.getComputedStyle(domNode);
|
||||
var transform = computedStyle.transform;
|
||||
if(transform && transform !== "none") {
|
||||
var matrix = new DOMMatrix(transform);
|
||||
startScale = isHorizontal ? matrix.a : matrix.d;
|
||||
}
|
||||
startOpacity = parseFloat(computedStyle.opacity) || 0;
|
||||
// Remove existing handler
|
||||
var oldHandler = domNode._slideTransitionHandler;
|
||||
if(oldHandler) {
|
||||
domNode.removeEventListener("transitionend", oldHandler);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark as animating
|
||||
setAnimating(domNode, true);
|
||||
|
||||
// Reset after animation
|
||||
var transitionEndHandler = function() {
|
||||
domNode.removeEventListener("transitionend", transitionEndHandler);
|
||||
delete domNode._slideTransitionHandler;
|
||||
setAnimating(domNode, false);
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "none"},
|
||||
{marginBottom: ""},
|
||||
{marginTop: ""},
|
||||
{paddingBottom: ""},
|
||||
{paddingTop: ""},
|
||||
{height: "auto"},
|
||||
{opacity: ""}
|
||||
{transition: ""},
|
||||
{transform: ""},
|
||||
{transformOrigin: ""},
|
||||
{opacity: ""},
|
||||
{willChange: ""}
|
||||
]);
|
||||
if(options.callback) {
|
||||
options.callback();
|
||||
}
|
||||
},duration);
|
||||
// Set up the initial position of the element
|
||||
};
|
||||
|
||||
domNode._slideTransitionHandler = transitionEndHandler;
|
||||
|
||||
// Set initial state
|
||||
var transformOrigin;
|
||||
if(isHorizontal) {
|
||||
transformOrigin = (options.origin || "left") + " center";
|
||||
} else {
|
||||
transformOrigin = "center " + (options.origin || "top");
|
||||
}
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{height: currHeight + "px"},
|
||||
{transition: "none"},
|
||||
{transform: isHorizontal ? "scale3d(" + startScale + ", 1, 1)" : "scale3d(1, " + startScale + ", 1)"},
|
||||
{transformOrigin: transformOrigin},
|
||||
{opacity: startOpacity},
|
||||
{willChange: "transform, opacity"}
|
||||
]);
|
||||
|
||||
$tw.utils.forceLayout(domNode);
|
||||
|
||||
// Add transition end listener
|
||||
domNode.addEventListener("transitionend", transitionEndHandler);
|
||||
|
||||
// Animate to final state
|
||||
var easing = options.easing || "cubic-bezier(0.4, 0.0, 0.2, 1)";
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "transform " + duration + "ms " + easing + ", opacity " + duration + "ms " + easing},
|
||||
{transform: "scale3d(1, 1, 1)"},
|
||||
{opacity: "1"}
|
||||
]);
|
||||
$tw.utils.forceLayout(domNode);
|
||||
// Transition to the final position
|
||||
}
|
||||
|
||||
function slideClosedTransform(domNode,options) {
|
||||
options = options || {};
|
||||
var duration = options.duration || $tw.utils.getAnimationDuration();
|
||||
var direction = options.direction || "vertical";
|
||||
var isHorizontal = direction === "horizontal";
|
||||
|
||||
// Get current transform if animating
|
||||
var startScale = 1;
|
||||
var startOpacity = 1;
|
||||
if(isAnimating(domNode)) {
|
||||
var computedStyle = window.getComputedStyle(domNode);
|
||||
var transform = computedStyle.transform;
|
||||
if(transform && transform !== "none") {
|
||||
var matrix = new DOMMatrix(transform);
|
||||
startScale = isHorizontal ? matrix.a : matrix.d;
|
||||
}
|
||||
startOpacity = parseFloat(computedStyle.opacity) || 1;
|
||||
// Adjust duration based on progress
|
||||
duration = Math.round(duration * startOpacity);
|
||||
// Remove existing handler
|
||||
var oldHandler = domNode._slideTransitionHandler;
|
||||
if(oldHandler) {
|
||||
domNode.removeEventListener("transitionend", oldHandler);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark as animating
|
||||
setAnimating(domNode, true);
|
||||
|
||||
// Reset after animation
|
||||
var transitionEndHandler = function() {
|
||||
domNode.removeEventListener("transitionend", transitionEndHandler);
|
||||
delete domNode._slideTransitionHandler;
|
||||
setAnimating(domNode, false);
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "margin-top " + duration + "ms ease-in-out, " +
|
||||
"margin-bottom " + duration + "ms ease-in-out, " +
|
||||
"padding-top " + duration + "ms ease-in-out, " +
|
||||
"padding-bottom " + duration + "ms ease-in-out, " +
|
||||
"height " + duration + "ms ease-in-out, " +
|
||||
"opacity " + duration + "ms ease-in-out"},
|
||||
{marginTop: "0px"},
|
||||
{marginBottom: "0px"},
|
||||
{paddingTop: "0px"},
|
||||
{paddingBottom: "0px"},
|
||||
{height: "0px"},
|
||||
{transition: ""},
|
||||
{transform: ""},
|
||||
{transformOrigin: ""},
|
||||
{opacity: ""},
|
||||
{willChange: ""}
|
||||
]);
|
||||
if(options.callback) {
|
||||
options.callback();
|
||||
}
|
||||
};
|
||||
|
||||
domNode._slideTransitionHandler = transitionEndHandler;
|
||||
|
||||
// Set initial state
|
||||
var transformOrigin;
|
||||
if(isHorizontal) {
|
||||
transformOrigin = (options.origin || "left") + " center";
|
||||
} else {
|
||||
transformOrigin = "center " + (options.origin || "top");
|
||||
}
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "none"},
|
||||
{transform: isHorizontal ? "scale3d(" + startScale + ", 1, 1)" : "scale3d(1, " + startScale + ", 1)"},
|
||||
{transformOrigin: transformOrigin},
|
||||
{opacity: startOpacity},
|
||||
{willChange: "transform, opacity"}
|
||||
]);
|
||||
|
||||
$tw.utils.forceLayout(domNode);
|
||||
|
||||
// Add transition end listener
|
||||
domNode.addEventListener("transitionend", transitionEndHandler);
|
||||
|
||||
// Animate to final state
|
||||
var easing = options.easing || "cubic-bezier(0.4, 0.0, 0.2, 1)";
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "transform " + duration + "ms " + easing + ", opacity " + duration + "ms " + easing},
|
||||
{transform: isHorizontal ? "scale3d(0, 1, 1)" : "scale3d(1, 0, 1)"},
|
||||
{opacity: "0"}
|
||||
]);
|
||||
}
|
||||
|
||||
// GPU-accelerated versions using clip-path and transforms
|
||||
function slideOpenGPU(domNode, options) {
|
||||
options = options || {};
|
||||
var duration = options.duration || $tw.utils.getAnimationDuration();
|
||||
var direction = options.direction || "vertical";
|
||||
var isHorizontal = direction === "horizontal";
|
||||
var origin = options.origin || (isHorizontal ? "left" : "top");
|
||||
|
||||
// Get dimensions for clip-path
|
||||
var rect = domNode.getBoundingClientRect();
|
||||
var width = rect.width;
|
||||
var height = rect.height;
|
||||
|
||||
// Check if already animating
|
||||
var startOpacity = 0;
|
||||
if(isAnimating(domNode)) {
|
||||
var computedStyle = window.getComputedStyle(domNode);
|
||||
startOpacity = parseFloat(computedStyle.opacity) || 0;
|
||||
// Remove existing handler
|
||||
var oldHandler = domNode._slideTransitionHandler;
|
||||
if(oldHandler) {
|
||||
domNode.removeEventListener("transitionend", oldHandler);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark as animating
|
||||
setAnimating(domNode, true);
|
||||
|
||||
// Reset after animation
|
||||
var transitionEndHandler = function() {
|
||||
domNode.removeEventListener("transitionend", transitionEndHandler);
|
||||
delete domNode._slideTransitionHandler;
|
||||
setAnimating(domNode, false);
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: ""},
|
||||
{clipPath: ""},
|
||||
{transform: ""},
|
||||
{opacity: ""},
|
||||
{willChange: ""}
|
||||
]);
|
||||
if(options.callback) {
|
||||
options.callback();
|
||||
}
|
||||
};
|
||||
|
||||
domNode._slideTransitionHandler = transitionEndHandler;
|
||||
|
||||
// Set initial clip-path based on origin
|
||||
var initialClip, finalClip = "inset(0 0 0 0)";
|
||||
if(isHorizontal) {
|
||||
if(origin === "right") {
|
||||
initialClip = "inset(0 0 0 100%)";
|
||||
} else if(origin === "center") {
|
||||
initialClip = "inset(0 50% 0 50%)";
|
||||
} else {
|
||||
initialClip = "inset(0 100% 0 0)";
|
||||
}
|
||||
} else {
|
||||
if(origin === "bottom") {
|
||||
initialClip = "inset(100% 0 0 0)";
|
||||
} else if(origin === "center") {
|
||||
initialClip = "inset(50% 0 50% 0)";
|
||||
} else {
|
||||
initialClip = "inset(0 0 100% 0)";
|
||||
}
|
||||
}
|
||||
|
||||
// Set initial state
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "none"},
|
||||
{clipPath: initialClip},
|
||||
{transform: "translate3d(0, 0, 0)"},
|
||||
{opacity: startOpacity},
|
||||
{willChange: "clip-path, opacity"}
|
||||
]);
|
||||
|
||||
$tw.utils.forceLayout(domNode);
|
||||
|
||||
// Add transition end listener
|
||||
domNode.addEventListener("transitionend", transitionEndHandler);
|
||||
|
||||
// Animate to final state
|
||||
var easing = options.easing || "cubic-bezier(0.4, 0.0, 0.2, 1)";
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "clip-path " + duration + "ms " + easing + ", opacity " + duration + "ms " + easing},
|
||||
{clipPath: finalClip},
|
||||
{opacity: "1"}
|
||||
]);
|
||||
}
|
||||
|
||||
function slideClosedGPU(domNode, options) {
|
||||
options = options || {};
|
||||
var duration = options.duration || $tw.utils.getAnimationDuration();
|
||||
var direction = options.direction || "vertical";
|
||||
var isHorizontal = direction === "horizontal";
|
||||
var origin = options.origin || (isHorizontal ? "left" : "top");
|
||||
|
||||
// Check if already animating
|
||||
var startOpacity = 1;
|
||||
if(isAnimating(domNode)) {
|
||||
var computedStyle = window.getComputedStyle(domNode);
|
||||
startOpacity = parseFloat(computedStyle.opacity) || 1;
|
||||
duration = Math.round(duration * startOpacity);
|
||||
// Remove existing handler
|
||||
var oldHandler = domNode._slideTransitionHandler;
|
||||
if(oldHandler) {
|
||||
domNode.removeEventListener("transitionend", oldHandler);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark as animating
|
||||
setAnimating(domNode, true);
|
||||
|
||||
// Reset after animation
|
||||
var transitionEndHandler = function() {
|
||||
domNode.removeEventListener("transitionend", transitionEndHandler);
|
||||
delete domNode._slideTransitionHandler;
|
||||
setAnimating(domNode, false);
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: ""},
|
||||
{clipPath: ""},
|
||||
{transform: ""},
|
||||
{opacity: ""},
|
||||
{willChange: ""}
|
||||
]);
|
||||
if(options.callback) {
|
||||
options.callback();
|
||||
}
|
||||
};
|
||||
|
||||
domNode._slideTransitionHandler = transitionEndHandler;
|
||||
|
||||
// Set final clip-path based on origin
|
||||
var finalClip;
|
||||
if(isHorizontal) {
|
||||
if(origin === "right") {
|
||||
finalClip = "inset(0 0 0 100%)";
|
||||
} else if(origin === "center") {
|
||||
finalClip = "inset(0 50% 0 50%)";
|
||||
} else {
|
||||
finalClip = "inset(0 100% 0 0)";
|
||||
}
|
||||
} else {
|
||||
if(origin === "bottom") {
|
||||
finalClip = "inset(100% 0 0 0)";
|
||||
} else if(origin === "center") {
|
||||
finalClip = "inset(50% 0 50% 0)";
|
||||
} else {
|
||||
finalClip = "inset(0 0 100% 0)";
|
||||
}
|
||||
}
|
||||
|
||||
// Set initial state
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "none"},
|
||||
{clipPath: "inset(0 0 0 0)"},
|
||||
{transform: "translate3d(0, 0, 0)"},
|
||||
{opacity: startOpacity},
|
||||
{willChange: "clip-path, opacity"}
|
||||
]);
|
||||
|
||||
$tw.utils.forceLayout(domNode);
|
||||
|
||||
// Add transition end listener
|
||||
domNode.addEventListener("transitionend", transitionEndHandler);
|
||||
|
||||
// Animate to final state
|
||||
var easing = options.easing || "cubic-bezier(0.4, 0.0, 0.2, 1)";
|
||||
$tw.utils.setStyle(domNode,[
|
||||
{transition: "clip-path " + duration + "ms " + easing + ", opacity " + duration + "ms " + easing},
|
||||
{clipPath: finalClip},
|
||||
{opacity: "0"}
|
||||
]);
|
||||
}
|
||||
|
||||
exports.slide = {
|
||||
open: slideOpen,
|
||||
close: slideClosed
|
||||
close: slideClosed,
|
||||
openTransform: slideOpenTransform,
|
||||
closeTransform: slideClosedTransform,
|
||||
openGPU: slideOpenGPU,
|
||||
closeGPU: slideClosedGPU
|
||||
};
|
||||
|
|
|
|||
|
|
@ -120,8 +120,33 @@ RevealWidget.prototype.execute = function() {
|
|||
this["default"] = this.getAttribute("default","");
|
||||
this.animate = this.getAttribute("animate","no");
|
||||
this.retain = this.getAttribute("retain","no");
|
||||
this.openAnimation = this.animate === "no" ? undefined : "open";
|
||||
this.closeAnimation = this.animate === "no" ? undefined : "close";
|
||||
// Animation type configuration
|
||||
this.animationType = this.getAttribute("animationType","default"); // default, transform, gpu
|
||||
// Set animation function names based on type
|
||||
if(this.animate === "no") {
|
||||
this.openAnimation = undefined;
|
||||
this.closeAnimation = undefined;
|
||||
} else {
|
||||
// Use animation type to determine implementation
|
||||
switch(this.animationType) {
|
||||
case "transform":
|
||||
this.openAnimation = "openTransform";
|
||||
this.closeAnimation = "closeTransform";
|
||||
break;
|
||||
case "gpu":
|
||||
this.openAnimation = "openGPU";
|
||||
this.closeAnimation = "closeGPU";
|
||||
break;
|
||||
default:
|
||||
this.openAnimation = "open";
|
||||
this.closeAnimation = "close";
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.animationDuration = parseInt(this.getAttribute("animationDuration") || $tw.utils.getAnimationDuration());
|
||||
this.animationDirection = this.getAttribute("animationDirection");
|
||||
this.animationOrigin = this.getAttribute("animationOrigin");
|
||||
this.animationEasing = this.getAttribute("animationEasing");
|
||||
this.updatePopupPosition = this.getAttribute("updatePopupPosition","no") === "yes";
|
||||
// Compute the title of the state tiddler and read it
|
||||
this.stateTiddlerTitle = this.state;
|
||||
|
|
@ -211,7 +236,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
|||
*/
|
||||
RevealWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.state || changedAttributes.type || changedAttributes.text || changedAttributes.position || changedAttributes.positionAllowNegative || changedAttributes["default"] || changedAttributes.animate || changedAttributes.stateTitle || changedAttributes.stateField || changedAttributes.stateIndex) {
|
||||
if(changedAttributes.state || changedAttributes.type || changedAttributes.text || changedAttributes.position || changedAttributes.positionAllowNegative || changedAttributes["default"] || changedAttributes.animate || changedAttributes.stateTitle || changedAttributes.stateField || changedAttributes.stateIndex || changedAttributes.animationOrigin || changedAttributes.animationType || changedAttributes.animationEasing) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
|
|
@ -233,6 +258,9 @@ RevealWidget.prototype.refresh = function(changedTiddlers) {
|
|||
if(changedAttributes["class"]) {
|
||||
this.assignDomNodeClasses();
|
||||
}
|
||||
if(changedAttributes.animationDuration || changedTiddlers["$:/config/AnimationDuration"]) {
|
||||
this.animationDuration = parseInt(this.getAttribute("animationDuration") || $tw.utils.getAnimationDuration());
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
}
|
||||
};
|
||||
|
|
@ -259,15 +287,42 @@ RevealWidget.prototype.updateState = function() {
|
|||
}
|
||||
if(this.isOpen) {
|
||||
domNode.removeAttribute("hidden");
|
||||
$tw.anim.perform(this.openAnimation,domNode);
|
||||
var animOptions = {};
|
||||
if(this.animationDuration) {
|
||||
animOptions.duration = this.animationDuration;
|
||||
}
|
||||
if(this.animationDirection) {
|
||||
animOptions.direction = this.animationDirection;
|
||||
}
|
||||
if(this.animationOrigin) {
|
||||
animOptions.origin = this.animationOrigin;
|
||||
}
|
||||
if(this.animationEasing) {
|
||||
animOptions.easing = this.animationEasing;
|
||||
}
|
||||
$tw.anim.perform(this.openAnimation,domNode,animOptions);
|
||||
} else {
|
||||
$tw.anim.perform(this.closeAnimation,domNode,{callback: function() {
|
||||
var animOptions = {};
|
||||
if(this.animationDuration) {
|
||||
animOptions.duration = this.animationDuration;
|
||||
}
|
||||
if(this.animationDirection) {
|
||||
animOptions.direction = this.animationDirection;
|
||||
}
|
||||
if(this.animationOrigin) {
|
||||
animOptions.origin = this.animationOrigin;
|
||||
}
|
||||
if(this.animationEasing) {
|
||||
animOptions.easing = this.animationEasing;
|
||||
}
|
||||
animOptions.callback = function() {
|
||||
//make sure that the state hasn't changed during the close animation
|
||||
self.readState()
|
||||
if(!self.isOpen) {
|
||||
domNode.setAttribute("hidden","true");
|
||||
}
|
||||
}});
|
||||
};
|
||||
$tw.anim.perform(self.closeAnimation,domNode,animOptions);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ $:/config/SideBarSegments/Visibility/$(listItem)$
|
|||
|
||||
<div class="tc-sidebar-header">
|
||||
|
||||
<$reveal state="$:/state/sidebar" type="match" text="yes" default="yes" retain="yes" animate="yes">
|
||||
<$reveal state="$:/state/sidebar" type="match" text="yes" default="yes" retain="yes" animate="yes" animationDirection="horizontal" animationType="transform" animationOrigin="right" animationEasing="ease-in-out">
|
||||
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/SideBarSegment]!has[draft.of]]" variable="listItem">
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
caption: reveal
|
||||
created: 20131024141900000
|
||||
jeremy: tiddlywiki
|
||||
modified: 20250211091937860
|
||||
modified: 20250809080611204
|
||||
tags: Widgets
|
||||
title: RevealWidget
|
||||
type: text/vnd.tiddlywiki
|
||||
|
|
@ -37,6 +37,11 @@ The content of the `<$reveal>` widget is displayed according to the rules given
|
|||
|positionAllowNegative |Set to "yes" to prevent computed popup positions from being clamped to be above zero |
|
||||
|default |Default value to use when the state tiddler is missing |
|
||||
|animate |Set to "yes" to animate opening and closure (defaults to "no"; requires "retain" to be set to "yes") |
|
||||
|animationType |<<.from-version "5.4.0">>The type of animation implementation to use: ''default'', ''transform'', or ''gpu'' (defaults to "default") |
|
||||
|animationDuration |<<.from-version "5.4.0">>Duration of the animation in milliseconds (defaults to the global animation duration) |
|
||||
|animationDirection |<<.from-version "5.4.0">>Direction of the animation effect: ''horizontal'' or ''vertical'' (defaults to "vertical") |
|
||||
|animationOrigin |<<.from-version "5.4.0">>Origin point for the animation (e.g., "left", "right", "top", "bottom") |
|
||||
|animationEasing |<<.from-version "5.4.0">>Easing function for the animation |
|
||||
|retain |Set to "yes" to force the content to be retained even when hidden (defaults to "no") |
|
||||
|updatePopupPosition|<<.from-version "5.1.23">>Set to "yes" to update the popup position when the state tiddler is updated (defaults to "no")|
|
||||
|
||||
|
|
@ -45,6 +50,8 @@ This is useful for edge-cases where titles may contain characters that are used
|
|||
|
||||
<<.tip """Retaining the content when hidden can give poor performance since the hidden content requires refresh processing even though it is not displayed. On the other hand, the content can be revealed much more quickly. Note that setting ''animate="yes"'' will also require ''retain="yes"''""">>
|
||||
|
||||
<<.tip """Animations of the reveal widget work only if both ''animate="yes"'' AND ''retain="yes"'' are set. The retain attribute is required because animations need the content to be present in the DOM even when hidden.""">>
|
||||
|
||||
! Examples
|
||||
|
||||
<<testcase TestCases/RevealWidget/SimpleReveal>>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue