Skip to content

Commit 9175682

Browse files
committed
Add element#remove and element#duplicate actions
New actions for DOM manipulation: - `element#remove`: remove elements with optional delay (data-delay); - `element#duplicate`: clone and insert elements using data-prepend or data-append. Examples: ```html <button data-action="element#remove" data-target="#item">Remove</button> <button data-action="element#remove" data-target="#item" data-delay="2000">Remove after 2s</button> <button data-action="element#duplicate" data-target="#template" data-append="#container">Add item</button> ```
1 parent cd72419 commit 9175682

File tree

4 files changed

+256
-0
lines changed

4 files changed

+256
-0
lines changed

src/actions/element.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import ActionBase from "./base";
2+
import debounce from "./../helpers/debounce";
3+
4+
class Element extends ActionBase {
5+
constructor(currentElement, options = {}) {
6+
super(currentElement, options);
7+
8+
this.value = options.value;
9+
}
10+
11+
remove() {
12+
const delay = this.currentElement.dataset.delay;
13+
14+
const removeElements = () => {
15+
this.targets.forEach((target) => target.remove());
16+
};
17+
18+
if (delay) {
19+
debounce(removeElements, parseInt(delay));
20+
} else {
21+
removeElements();
22+
}
23+
}
24+
25+
duplicate() {
26+
const target = this.targets[0];
27+
if (!target) return;
28+
29+
const container = this.#container;
30+
if (!container) return;
31+
32+
const clonedElement = this.#cloneTarget(target);
33+
34+
this.#isPrepend
35+
? container.prepend(clonedElement)
36+
: container.append(clonedElement);
37+
}
38+
39+
// private
40+
41+
get #container() {
42+
const selector = this.currentElement.dataset.prepend || this.currentElement.dataset.append;
43+
44+
return selector ? document.querySelector(selector) : null;
45+
}
46+
47+
get #isPrepend() {
48+
return !!this.currentElement.dataset.prepend;
49+
}
50+
51+
#cloneTarget(target) {
52+
return target.tagName === "TEMPLATE"
53+
? target.content.cloneNode(true)
54+
: target.cloneNode(true);
55+
}
56+
}
57+
58+
export const action =
59+
(method) =>
60+
(element, options = {}) => {
61+
const instance = new Element(element, options);
62+
63+
return instance[method]();
64+
};
65+
66+
export default {
67+
remove: action("remove"),
68+
duplicate: action("duplicate")
69+
};

src/actions/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import clipboardActions from "./clipboard";
44
import confirmActions from "./confirm";
55
import dataAttributeActions from "./data_attribute";
66
import dialogActions from "./dialog";
7+
import elementActions from "./element";
78
import formActions from "./form";
89
import intersectionActions from "./intersection";
910
import reloadActions from "./reload";
@@ -17,6 +18,7 @@ export const actions = {
1718
confirm: confirmActions,
1819
dataAttribute: dataAttributeActions,
1920
dialog: dialogActions,
21+
element: elementActions,
2022
form: formActions,
2123
intersection: intersectionActions,
2224
reload: reloadActions,

test/element.html

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<title>Attractive.js - Element Tests</title>
5+
<link rel="stylesheet" href="./styles.css" />
6+
<script src="../dist/attractive.js"></script>
7+
</head>
8+
<body>
9+
<h1>Element</h1>
10+
<p><a href="index.html">← Back to test index</a></p>
11+
12+
<div class="test-section">
13+
<h2>Remove element (self)</h2>
14+
15+
<button data-action="element#remove">
16+
Remove this button (click me)
17+
</button>
18+
</div>
19+
20+
<div class="test-section">
21+
<h2>Remove element with target</h2>
22+
23+
<button data-action="element#remove" data-target="#removable-item">
24+
Remove target element
25+
</button>
26+
27+
<p id="removable-item" style="padding: 1rem; background: #ffebee;">
28+
This element will be removed when the button is clicked.
29+
</p>
30+
</div>
31+
32+
<div class="test-section">
33+
<h2>Remove element with delay</h2>
34+
35+
<button
36+
data-action="element#remove"
37+
data-target="#delayed-item"
38+
data-delay="2000"
39+
>
40+
Remove after 2 seconds
41+
</button>
42+
43+
<p id="delayed-item" style="padding: 1rem; background: #fff3e0;">
44+
This element will be removed 2 seconds after clicking the button.
45+
</p>
46+
</div>
47+
48+
<div class="test-section">
49+
<h2>Remove multiple elements</h2>
50+
51+
<button data-action="element#remove" data-target=".removable-card">
52+
Remove all cards
53+
</button>
54+
55+
<div style="display: flex; gap: 1rem; margin-top: 1rem;">
56+
<div
57+
class="removable-card"
58+
style="padding: 1rem; background: #e3f2fd; border-radius: 4px;"
59+
>
60+
Card 1
61+
</div>
62+
<div
63+
class="removable-card"
64+
style="padding: 1rem; background: #e3f2fd; border-radius: 4px;"
65+
>
66+
Card 2
67+
</div>
68+
<div
69+
class="removable-card"
70+
style="padding: 1rem; background: #e3f2fd; border-radius: 4px;"
71+
>
72+
Card 3
73+
</div>
74+
</div>
75+
</div>
76+
77+
<div class="test-section">
78+
<h2>Duplicate element - Append</h2>
79+
80+
<button
81+
data-action="element#duplicate"
82+
data-target="#source-item"
83+
data-append="#append-container"
84+
>
85+
Duplicate and append
86+
</button>
87+
88+
<div
89+
id="source-item"
90+
style="padding: 1rem; background: #e8f5e9; border-radius: 4px; margin: 1rem 0;"
91+
>
92+
<strong>Source Item</strong> - This will be duplicated
93+
</div>
94+
95+
<div
96+
id="append-container"
97+
style="padding: 1rem; background: #f5f5f5; border-radius: 4px; min-height: 3rem;"
98+
>
99+
<p style="margin: 0 0 0.5rem 0; font-weight: bold;">
100+
Append Container:
101+
</p>
102+
</div>
103+
</div>
104+
105+
<div class="test-section">
106+
<h2>Duplicate element - Prepend</h2>
107+
108+
<button
109+
data-action="element#duplicate"
110+
data-target="#source-item-2"
111+
data-prepend="#prepend-container"
112+
>
113+
Duplicate and prepend
114+
</button>
115+
116+
<div
117+
id="source-item-2"
118+
style="padding: 1rem; background: #f3e5f5; border-radius: 4px; margin: 1rem 0;"
119+
>
120+
<strong>Source Item 2</strong> - This will be duplicated
121+
</div>
122+
123+
<div
124+
id="prepend-container"
125+
style="padding: 1rem; background: #f5f5f5; border-radius: 4px; min-height: 3rem;"
126+
>
127+
<p style="margin: 0 0 0.5rem 0; font-weight: bold;">
128+
Prepend Container:
129+
</p>
130+
</div>
131+
</div>
132+
133+
<div class="test-section">
134+
<h2>Duplicate from template</h2>
135+
136+
<button
137+
data-action="element#duplicate"
138+
data-target="#card-template"
139+
data-append="#cards-container"
140+
>
141+
Add new card
142+
</button>
143+
144+
<template id="card-template">
145+
<div
146+
style="padding: 1rem; background: #fff9c4; border-radius: 4px; margin-bottom: 0.5rem;"
147+
>
148+
<strong>New Card</strong>
149+
<p style="margin: 0.5rem 0 0 0;">
150+
This card was created from a template.
151+
</p>
152+
</div>
153+
</template>
154+
155+
<div
156+
id="cards-container"
157+
style="padding: 1rem; background: #f5f5f5; border-radius: 4px; min-height: 3rem;"
158+
>
159+
<p style="margin: 0 0 0.5rem 0; font-weight: bold;">Cards:</p>
160+
</div>
161+
</div>
162+
163+
<div class="test-section">
164+
<h2>Duplicate self</h2>
165+
166+
<div
167+
data-action="element#duplicate"
168+
data-append="#self-duplicate-container"
169+
style="padding: 1rem; background: #fce4ec; border-radius: 4px; cursor: pointer; display: inline-block;"
170+
>
171+
Click me to duplicate myself!
172+
</div>
173+
174+
<div
175+
id="self-duplicate-container"
176+
style="padding: 1rem; background: #f5f5f5; border-radius: 4px; margin-top: 1rem; min-height: 3rem;"
177+
>
178+
<p style="margin: 0 0 0.5rem 0; font-weight: bold;">
179+
Duplicates will appear here:
180+
</p>
181+
</div>
182+
</div>
183+
</body>
184+
</html>

test/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ <h1>Attractive.js test suite</h1>
1414
<li><a href="confirm.html">Confirm</a></li>
1515
<li><a href="data_attribute.html">Data Attribute</a></li>
1616
<li><a href="dialog.html">Dialog</a></li>
17+
<li><a href="element.html">Element</a></li>
1718
<li><a href="form.html">Form</a></li>
1819
<li><a href="intersection.html">Intersection</a></li>
1920
<li><a href="reload.html">Reload</a></li>

0 commit comments

Comments
 (0)