Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F12660652
sortable.stimulus.ts
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
4 KB
Referenced Files
None
Subscribers
None
sortable.stimulus.ts
View Options
/* eslint-disable @typescript-eslint/no-for-in-array */
/* eslint-disable @typescript-eslint/consistent-type-assertions */
import
{
Controller
}
from
"stimulus"
;
async
function
sleep
(
time
:
number
)
{
return
new
Promise
((
resolve
)
=>
{
setTimeout
(
resolve
,
time
);
});
}
export
default
class
Sortable
extends
Controller
{
dragged_element
:
HTMLDivElement
|
null
=
null
;
clearDoubleHoles
()
{
this
.
element
.
querySelectorAll
(
".ready-to-drop"
)
.
forEach
((
e
:
HTMLDivElement
)
=>
e
.
classList
.
remove
(
"ready-to-drop"
));
}
getNthElement
(
n
:
number
)
:
HTMLDivElement
|
null
{
return
this
.
element
.
querySelector
(
`.sortable__element:nth-child(
${
n
}
)`
);
}
setIndex
(
node
:
HTMLDivElement
,
index
:
number
)
{
node
.
setAttribute
(
"data-index"
,
String
(
index
));
node
.
style
.
setProperty
(
"--index"
,
String
(
index
));
}
setupHoleListeners
(
hole
:
HTMLDivElement
)
{
hole
.
addEventListener
(
"dragenter"
,
(
event
)
=>
{
event
.
dataTransfer
.
dropEffect
=
"move"
;
if
(
!
this
.
dragged_element
)
{
return
;
}
(
event
.
target
as
HTMLDivElement
).
classList
.
add
(
"ready-to-drop"
);
event
.
preventDefault
();
});
hole
.
addEventListener
(
"dragover"
,
(
event
)
=>
{
event
.
dataTransfer
.
dropEffect
=
"move"
;
if
(
!
this
.
dragged_element
)
{
return
;
}
event
.
preventDefault
();
});
hole
.
addEventListener
(
"dragleave"
,
(
event
)
=>
{
(
event
.
target
as
HTMLDivElement
).
classList
.
remove
(
"ready-to-drop"
);
event
.
preventDefault
();
});
hole
.
addEventListener
(
"drop"
,
(
event
)
=>
{
const
target
=
event
.
target
as
HTMLDivElement
;
target
.
classList
.
remove
(
"ready-to-drop"
);
const
index_of_dropped_element
=
parseInt
(
this
.
dragged_element
.
getAttribute
(
"data-index"
)
);
const
index_of_drop_target
=
parseInt
(
target
.
getAttribute
(
"data-index"
));
const
nodes_of_dropped_element_index
=
this
.
element
.
querySelectorAll
(
`[data-index="
${
index_of_dropped_element
}
"]`
);
const
nodes_of_target_index
=
this
.
element
.
querySelectorAll
(
`[data-index="
${
index_of_drop_target
}
"]`
);
let
last_node_of_target_index
=
nodes_of_target_index
[
nodes_of_target_index
.
length
-
1
];
for
(
const
node
of
Array
.
from
(
nodes_of_dropped_element_index
))
{
last_node_of_target_index
.
after
(
node
);
this
.
setIndex
(
node
as
HTMLDivElement
,
index_of_drop_target
);
last_node_of_target_index
=
node
;
}
const
next_to_correct
=
nodes_of_dropped_element_index
[
0
].
previousSibling
;
const
children
=
Array
.
from
(
next_to_correct
.
parentNode
.
childNodes
);
const
children_to_correct
=
children
.
slice
(
2
);
for
(
const
dom_index
in
children_to_correct
)
{
const
index
=
Math
.
max
(
Math
.
floor
(
parseInt
(
dom_index
)
/
3
),
0
);
this
.
setIndex
(
children_to_correct
[
dom_index
]
as
HTMLDivElement
,
index
);
}
event
.
preventDefault
();
});
}
connect
()
{
this
.
element
.
querySelectorAll
(
".sortable__element"
).
forEach
((
element
)
=>
{
element
.
addEventListener
(
"dragstart"
,
(
e
:
DragEvent
)
=>
{
e
.
dataTransfer
.
effectAllowed
=
"move"
;
const
target
=
e
.
target
as
HTMLDivElement
;
this
.
dragged_element
=
target
;
setTimeout
(()
=>
{
// https://stackoverflow.com/a/20733870/1467284
target
.
classList
.
add
(
"is-dragged"
);
},
0
);
});
element
.
addEventListener
(
"dragend"
,
(
e
:
DragEvent
)
=>
{
const
target
=
e
.
target
as
HTMLDivElement
;
this
.
dragged_element
=
null
;
target
.
classList
.
remove
(
"is-dragged"
);
});
});
this
.
element
.
querySelectorAll
(
".edge-detector"
)
.
forEach
((
detector
:
HTMLDivElement
)
=>
{
let
is_hovered
=
false
;
detector
.
addEventListener
(
"dragenter"
,
(
e
)
=>
{
e
.
preventDefault
();
const
target
=
e
.
target
as
HTMLDivElement
;
const
step
=
parseInt
(
target
.
getAttribute
(
"data-step"
));
is_hovered
=
true
;
void
(
async
()
=>
{
while
(
is_hovered
&&
this
.
dragged_element
)
{
window
.
scrollTo
(
window
.
scrollX
,
window
.
scrollY
+
step
);
// eslint-disable-next-line no-await-in-loop
await
sleep
(
16
);
}
})();
});
detector
.
addEventListener
(
"dragover "
,
(
e
)
=>
{
// necessary for drag events;
e
.
preventDefault
();
});
detector
.
addEventListener
(
"dragleave"
,
(
e
)
=>
{
e
.
preventDefault
();
is_hovered
=
false
;
});
});
this
.
element
.
querySelectorAll
(
".sortable__hole"
)
.
forEach
((
dropElement
:
HTMLDivElement
)
=>
this
.
setupHoleListeners
(
dropElement
)
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-java
Expires
Fri, Nov 28, 15:41 (13 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1080449
Default Alt Text
sortable.stimulus.ts (4 KB)
Attached To
Mode
rPLAY Sealious playground
Attached
Detach File
Event Timeline
Log In to Comment