///|
/// moveBefore API - Experimental DOM API for moving nodes without losing state
/// https://developer.mozilla.org/en-US/docs/Web/API/Element/moveBefore
///
/// Unlike insertBefore which removes and re-inserts (losing state like animations,
/// focus, iframe content), moveBefore preserves the node's state.
///
/// Browser support: Limited (Chrome 133+, Firefox experimental)
///|
/// Check if moveBefore is supported in the current environment
pub fn is_move_before_supported() -> Bool {
move_before_supported()
}
///|
extern "js" fn move_before_supported() -> Bool =
#| () => typeof Element.prototype.moveBefore === 'function'
///|
/// Move a node before a reference node, preserving state (animations, focus, etc.)
/// Falls back to insertBefore if moveBefore is not supported.
///
/// Parameters:
/// - parent: The parent node to move the child within
/// - node: The node to move
/// - ref_node: The reference node (node will be inserted before this), or None for end
///
/// Returns the moved node
pub fn move_before(
parent : @js_dom.Node,
node : @js_dom.Node,
ref_node : @js_dom.Node?,
) -> @js_dom.Node {
match ref_node {
Some(reference) => move_before_impl(parent, node, reference)
None => move_before_impl_null(parent, node)
}
}
///|
extern "js" fn move_before_impl(
parent : @js_dom.Node,
node : @js_dom.Node,
ref_node : @js_dom.Node,
) -> @js_dom.Node =
#| (parent, node, refNode) => {
#| if (typeof parent.moveBefore === 'function') {
#| try {
#| parent.moveBefore(node, refNode);
#| return node;
#| } catch (e) {
#| // moveBefore may fail on SVG elements or in certain DOM hierarchies
#| // Fall back to insertBefore
#| return parent.insertBefore(node, refNode);
#| }
#| } else {
#| return parent.insertBefore(node, refNode);
#| }
#| }
///|
extern "js" fn move_before_impl_null(
parent : @js_dom.Node,
node : @js_dom.Node,
) -> @js_dom.Node =
#| (parent, node) => {
#| if (typeof parent.moveBefore === 'function') {
#| try {
#| parent.moveBefore(node, null);
#| return node;
#| } catch (e) {
#| // moveBefore may fail on SVG elements or in certain DOM hierarchies
#| // Fall back to insertBefore
#| return parent.insertBefore(node, null);
#| }
#| } else {
#| return parent.insertBefore(node, null);
#| }
#| }
///|
/// Force use of moveBefore (throws if not supported)
pub fn move_before_strict(
parent : @js_dom.Node,
node : @js_dom.Node,
ref_node : @js_dom.Node?,
) -> @js_dom.Node {
match ref_node {
Some(reference) => move_before_strict_impl(parent, node, reference)
None => move_before_strict_impl_null(parent, node)
}
}
///|
extern "js" fn move_before_strict_impl(
parent : @js_dom.Node,
node : @js_dom.Node,
ref_node : @js_dom.Node,
) -> @js_dom.Node =
#| (parent, node, refNode) => {
#| parent.moveBefore(node, refNode);
#| return node;
#| }
///|
extern "js" fn move_before_strict_impl_null(
parent : @js_dom.Node,
node : @js_dom.Node,
) -> @js_dom.Node =
#| (parent, node) => {
#| parent.moveBefore(node, null);
#| return node;
#| }