Skip to content

Commit d4417cb

Browse files
Improve editOnClick
1 parent ea76f9f commit d4417cb

File tree

4 files changed

+103
-61
lines changed

4 files changed

+103
-61
lines changed

dist/mix-manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"/powergrid.js": "/powergrid.js?id=65133044a69064bc2c32606995a58abe",
2+
"/powergrid.js": "/powergrid.js?id=d79ad6b36ca796706eac797c614deb5d",
33
"/bootstrap5.css": "/bootstrap5.css?id=a27af22343149104b2aa3283d8fd502b",
44
"/tailwind.css": "/tailwind.css?id=924477e2afcb2cb56aa392e266ee56ca"
55
}

dist/powergrid.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/js/components/pg-editable.js

+100-58
Original file line numberDiff line numberDiff line change
@@ -12,38 +12,54 @@ export default (params) => ({
1212
hashError: true,
1313
showEditable: false,
1414
editableInput: '',
15+
1516
init() {
1617
if (this.content.length === 0 && this.fallback) {
1718
this.content = this.htmlSpecialChars(this.fallback);
1819
}
1920

20-
this.hash = this.dataField + '-' + this.id
21+
this.hash = this.dataField + '-' + this.id;
22+
23+
window.addEventListener('toggle-' + this.hash, () => {
24+
this.observe(
25+
() => document.getElementById('clickable-' + this.hash),
26+
(clickableElement) => {
27+
clickableElement.click();
28+
this.observe(
29+
() => document.getElementById('editable-' + this.hash),
30+
(editableElement) => {
31+
this.setFocusToEnd(editableElement);
32+
}
33+
);
34+
}
35+
);
36+
});
2137

2238
this.$watch('editable', (value) => {
2339
if (value) {
24-
let showEditable = false
25-
this.showEditable = false
40+
let showEditable = false;
41+
this.showEditable = false;
2642
this.content = this.htmlSpecialChars(this.content);
2743
this.oldContent = this.content;
28-
this.hashError = this.store().notContains(this.hash)
29-
30-
setTimeout(() => {
31-
const editableElement = document.getElementById('editable-' + this.hash)
32-
33-
if (this.store().getTextContent(this.hash) && editableElement) {
34-
editableElement.textContent = this.store().getTextContent(this.hash)
44+
this.hashError = this.store().notContains(this.hash);
45+
46+
this.observe(
47+
() => document.getElementById('editable-' + this.hash),
48+
(editableElement) => {
49+
if (this.store().getTextContent(this.hash)) {
50+
editableElement.textContent = this.store().getTextContent(this.hash);
51+
}
3552
}
36-
}, 220)
53+
);
3754

3855
if (this.hashError) {
39-
const pendingHash = this.store().get(this.hash)
40-
const clickableElement = document.getElementById('clickable-' + pendingHash)
41-
56+
const pendingHash = this.store().get(this.hash);
57+
const clickableElement = document.getElementById('clickable-' + pendingHash);
4258
if (clickableElement) {
43-
clickableElement.click()
59+
clickableElement.click();
4460
}
4561
} else {
46-
showEditable = true
62+
showEditable = true;
4763
}
4864

4965
this.editableInput = `
@@ -62,78 +78,104 @@ export default (params) => ({
6278
</div>`;
6379

6480
this.$nextTick(() => setTimeout(() => {
65-
this.showEditable = showEditable
66-
this.focus()
67-
}, 150))
81+
this.showEditable = showEditable;
82+
this.focus();
83+
}, 150));
6884
}
69-
})
85+
});
7086

7187
this.content = this.htmlSpecialChars(this.content);
7288
},
7389

7490
store() {
75-
return window.editOnClickValidation
91+
return window.editOnClickValidation;
7692
},
7793

7894
save() {
79-
this.store().clear()
80-
this.store().set(this.hash, this.$el.textContent)
81-
82-
setTimeout(() => {
83-
document.getElementById('clickable-' + this.hash).textContent =
84-
this.$el.textContent
85-
}, 230)
86-
87-
setTimeout(() => {
88-
window.addEventListener('pg:editable-close-'+this.id, () => {
89-
this.store().clear()
90-
this.editable = false;
91-
this.showEditable = false;
92-
})
93-
94-
if(!this.store().has(this.hash)) {
95-
this.store().set(this.hash, this.$el.textContent)
95+
this.store().clear();
96+
this.store().set(this.hash, this.$el.textContent);
9697

98+
this.observe(
99+
() => document.getElementById('clickable-' + this.hash),
100+
(clickableElement) => {
101+
clickableElement.textContent = this.$el.textContent;
97102
}
103+
);
98104

99-
this.$wire.dispatch('pg:editable-' + this.$wire.tableName, {
100-
id: this.id,
101-
value: this.$el.textContent,
102-
field: this.dataField
103-
})
105+
window.addEventListener('pg:editable-close-' + this.id, () => {
106+
this.store().clear();
107+
this.editable = false;
108+
this.showEditable = false;
109+
});
104110

105-
this.oldContent = this.store().getTextContent(this.hash)
111+
if (!this.store().has(this.hash)) {
112+
this.store().set(this.hash, this.$el.textContent);
113+
}
114+
115+
this.$wire.dispatch('pg:editable-' + this.$wire.tableName, {
116+
id: this.id,
117+
value: this.$el.textContent,
118+
field: this.dataField
119+
});
106120

107-
this.$nextTick(() => setTimeout(() => {
108-
this.focus()
109-
setTimeout(() => this.$el.setAttribute('value', ''), 200)
110-
}, 100))
121+
this.oldContent = this.store().getTextContent(this.hash);
111122

112-
}, 100)
123+
this.$nextTick(() => {
124+
this.focus();
125+
this.$el.setAttribute('value', '');
126+
});
113127

114-
this.content = this.htmlSpecialChars(this.$el.textContent)
128+
this.content = this.htmlSpecialChars(this.$el.textContent);
115129
},
116130

117131
focus() {
118-
const selection = window.getSelection();
119-
const range = document.createRange();
120-
selection.removeAllRanges();
121-
range.selectNodeContents(this.$el);
122-
range.collapse(false);
123-
selection.addRange(range);
124-
this.$el.focus();
132+
this.setFocusToEnd(this.$el);
125133
},
126134

127135
cancel() {
136+
this.store().clear();
128137
this.$refs.editable.textContent = this.oldContent;
129138
this.content = this.oldContent;
130139
this.editable = false;
131140
this.showEditable = false;
141+
142+
if (this.$refs.error) {
143+
this.$refs.error.innerHTML = '';
144+
}
132145
},
133146

134147
htmlSpecialChars(string) {
135148
const el = document.createElement('div');
136149
el.innerHTML = string;
137150
return el.textContent;
151+
},
152+
153+
observe(elementFinder, action) {
154+
const observer = new MutationObserver((mutationsList, observer) => {
155+
for (let mutation of mutationsList) {
156+
if (mutation.type === 'childList') {
157+
const element = elementFinder();
158+
if (element) {
159+
action(element);
160+
observer.disconnect();
161+
break;
162+
}
163+
}
164+
}
165+
});
166+
167+
observer.observe(document.body, { childList: true, subtree: true });
168+
},
169+
170+
setFocusToEnd(element) {
171+
const selection = window.getSelection();
172+
const range = document.createRange();
173+
range.selectNodeContents(element);
174+
range.collapse(false);
175+
176+
selection.removeAllRanges();
177+
selection.addRange(range);
178+
179+
element.focus();
138180
}
139-
})
181+
});

resources/views/components/editable.blade.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
</template>
7777
@if ($showErrorBag)
7878
@error($field . '.' . $row->{$this->realPrimaryKey})
79-
<div class="text-sm text-red-800 p-1 transition-all duration-200">
79+
<div x-ref="error" class="text-sm text-red-800 p-1 transition-all duration-200">
8080
{{ str($message)->replace($field . '.' . $row->{$this->realPrimaryKey}, $field) }}
8181
</div>
8282
@enderror

0 commit comments

Comments
 (0)