marathi_typing 0.1.3 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bea1ae0ad19188d8d72b79dd93e2458edcb7815de0b9a2eef7a068467cae9ad2
|
4
|
+
data.tar.gz: 0df203a4cc8a8d1e6b5a62684c38b116ccaa657b80c8cc1419b6b88c5d1d3e4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc082fc3eaaac92ecee8282cda4fb7adbdc8264ab33594f7888bef997f6968e074c207015f12ad918f70685481563ea2113d1f668e57c130583811b021ba8d75
|
7
|
+
data.tar.gz: b24417a8cfc3a182135f0f37144d074f4d8adb43ccd648595e761f532f75c4a01c684f7cf5ab5c6b115ac89168b21846a255f65b93dafdc69a14f2fdb9823132
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import { Controller } from "@hotwired/stimulus"
|
2
2
|
|
3
3
|
export default class extends Controller {
|
4
|
-
static targets = ["input"]
|
5
|
-
timeout = null
|
4
|
+
static targets = ["input"];
|
6
5
|
|
6
|
+
timeout = null
|
7
7
|
|
8
8
|
connect() {
|
9
9
|
|
@@ -14,16 +14,13 @@ export default class extends Controller {
|
|
14
14
|
this.suggestionsTarget = this.buildSuggestionsBox()
|
15
15
|
|
16
16
|
input.addEventListener("keydown", (e) => {
|
17
|
-
|
18
17
|
if (e.key === " ") {
|
19
18
|
this.skipNextSuggestionFetch = true;
|
20
19
|
}
|
21
20
|
});
|
22
21
|
|
23
22
|
input.addEventListener("input", (e) => {
|
24
|
-
|
25
23
|
if (this.skipNextSuggestionFetch) {
|
26
|
-
|
27
24
|
this.skipNextSuggestionFetch = false;
|
28
25
|
return;
|
29
26
|
}
|
@@ -33,13 +30,11 @@ export default class extends Controller {
|
|
33
30
|
input.addEventListener("keyup", (e) => {
|
34
31
|
|
35
32
|
if (e.key === " ") {
|
36
|
-
|
37
33
|
this.selectFirstSuggestion();
|
38
34
|
}
|
39
35
|
});
|
40
36
|
|
41
37
|
document.addEventListener("click", this.handleClickOutside);
|
42
|
-
|
43
38
|
}
|
44
39
|
|
45
40
|
fetchSuggestions(event) {
|
@@ -48,47 +43,54 @@ export default class extends Controller {
|
|
48
43
|
|
49
44
|
clearTimeout(this.timeout)
|
50
45
|
this.timeout = setTimeout(() => {
|
51
|
-
const lastWord = value.split(" ").pop()
|
52
46
|
|
53
|
-
|
47
|
+
const { word: currentWord } = this.getCurrentWordAtCursor(this.inputTarget);
|
48
|
+
|
49
|
+
console.log("currentWord: ", currentWord)
|
50
|
+
|
51
|
+
if (!currentWord || !/^[a-zA-Z]+$/.test(currentWord)) return;
|
52
|
+
|
53
|
+
fetch(`${this.apiUrl}?text=${currentWord}&itc=mr-t-i0-und&num=5&cp=0&cs=1&ie=utf-8&oe=utf-8&app=demopage`)
|
54
54
|
.then(res => res.json())
|
55
55
|
.then(data => {
|
56
56
|
if (data[0] === "SUCCESS") {
|
57
57
|
const suggestions = data[1][0][1]
|
58
|
-
this.showSuggestions(suggestions,
|
58
|
+
this.showSuggestions(suggestions, currentWord)
|
59
59
|
}
|
60
60
|
})
|
61
61
|
}, 300)
|
62
62
|
}
|
63
63
|
|
64
64
|
buildSuggestionsBox() {
|
65
|
-
|
66
|
-
const box = document.createElement("div")
|
65
|
+
const box = document.createElement("div");
|
67
66
|
box.className = "marathi-suggestions";
|
68
67
|
box.style.position = "absolute";
|
69
|
-
box.style.background = "
|
68
|
+
box.style.background = "rgb(239 238 236)";
|
70
69
|
box.style.border = "0px solid #ccc";
|
71
70
|
box.style.zIndex = "9999";
|
72
71
|
box.style.padding = "0px";
|
73
72
|
box.style.color = "black";
|
74
73
|
|
75
|
-
// Get the position
|
74
|
+
// Get the input's position relative to the viewport
|
76
75
|
const rect = this.inputTarget.getBoundingClientRect();
|
77
|
-
const scrollOffset = window.scrollY || window.pageYOffset;
|
78
76
|
|
79
|
-
|
80
|
-
|
77
|
+
// Calculate position relative to the document
|
78
|
+
const scrollTop = window.scrollY || window.pageYOffset;
|
79
|
+
const scrollLeft = window.scrollX || window.pageXOffset;
|
80
|
+
|
81
|
+
// Set position just below the input
|
82
|
+
box.style.top = `${rect.bottom + scrollTop}px`;
|
83
|
+
box.style.left = `${rect.left + scrollLeft}px`;
|
81
84
|
|
82
|
-
|
85
|
+
// Append to body to avoid being affected by parent positioning
|
86
|
+
document.body.appendChild(box);
|
83
87
|
|
84
|
-
return box
|
88
|
+
return box;
|
85
89
|
}
|
86
90
|
|
87
|
-
showSuggestions(suggestions, lastWord) {
|
88
|
-
this.suggestionsTarget.innerHTML = ""
|
89
|
-
this.suggestionsTarget.style.border = "1px solid #ccc";
|
90
|
-
this.suggestionsTarget.style.border = "4px";
|
91
91
|
|
92
|
+
showSuggestions(suggestions, lastWord) {
|
93
|
+
this.showSuggestionsBox();
|
92
94
|
|
93
95
|
suggestions.forEach(suggestion => {
|
94
96
|
const option = document.createElement("div")
|
@@ -108,36 +110,48 @@ export default class extends Controller {
|
|
108
110
|
}
|
109
111
|
|
110
112
|
selectFirstSuggestion() {
|
111
|
-
|
112
113
|
if (!this.suggestionsTarget || this.suggestionsTarget.children.length === 0) return;
|
113
114
|
|
114
115
|
const firstOption = this.suggestionsTarget.querySelector(".marathi-suggestion");
|
115
116
|
|
116
117
|
if (firstOption) {
|
117
118
|
const suggestion = firstOption.textContent;
|
118
|
-
const
|
119
|
-
|
120
|
-
|
119
|
+
const input = this.inputTarget;
|
120
|
+
let { word: currentWord } = this.getCurrentWordAtCursor(input);
|
121
|
+
|
122
|
+
// If space was pressed, caret is after the space => no current word
|
123
|
+
if (!currentWord) {
|
124
|
+
const valueBeforeCursor = input.value.slice(0, input.selectionStart).trimEnd();
|
125
|
+
const words = valueBeforeCursor.split(/\s+/);
|
126
|
+
currentWord = words[words.length - 1] || "";
|
127
|
+
}
|
128
|
+
|
129
|
+
if (!currentWord) return;
|
130
|
+
|
131
|
+
this.selectSuggestion(suggestion, currentWord);
|
121
132
|
}
|
122
133
|
}
|
123
134
|
|
135
|
+
selectSuggestion(selected, originalWord) {
|
136
|
+
const input = this.inputTarget;
|
137
|
+
const { wordStart, wordEnd } = this.getCurrentWordAtCursor(input);
|
124
138
|
|
125
|
-
|
126
|
-
let currentValue = this.inputTarget.value;
|
127
|
-
const trailingSpace = currentValue.endsWith(" ") ? " " : "";
|
139
|
+
if (wordStart == null || wordEnd == null) return;
|
128
140
|
|
129
|
-
|
130
|
-
currentValue = currentValue.trimEnd();
|
141
|
+
const value = input.value;
|
131
142
|
|
132
|
-
//
|
133
|
-
const newValue =
|
143
|
+
// Reconstruct the value with the selected word
|
144
|
+
const newValue = value.slice(0, wordStart) + selected + value.slice(wordEnd);
|
134
145
|
|
135
|
-
//
|
136
|
-
|
146
|
+
// Update the input value and set caret after inserted suggestion
|
147
|
+
input.value = newValue;
|
148
|
+
|
149
|
+
// Move caret to after the inserted suggestion
|
150
|
+
const caretPos = wordStart + selected.length;
|
151
|
+
input.setSelectionRange(caretPos, caretPos);
|
152
|
+
|
153
|
+
this.hideSuggestions();
|
137
154
|
|
138
|
-
this.suggestionsTarget.innerHTML = "";
|
139
|
-
this.suggestionsTarget.style.border = "0";
|
140
|
-
this.suggestionsTarget.style.padding = "0";
|
141
155
|
}
|
142
156
|
|
143
157
|
handleClickOutside = (event) => {
|
@@ -145,12 +159,65 @@ export default class extends Controller {
|
|
145
159
|
const isClickInsideSuggestions = this.suggestionsTarget?.contains(event.target);
|
146
160
|
|
147
161
|
if (!isClickInsideInput && !isClickInsideSuggestions) {
|
148
|
-
this.
|
149
|
-
this.suggestionsTarget.style.border = "0";
|
150
|
-
this.suggestionsTarget.style.padding = "0";
|
162
|
+
this.hideSuggestions();
|
151
163
|
}
|
152
164
|
};
|
153
165
|
|
154
166
|
|
155
|
-
|
167
|
+
getCurrentWordAtCursor(input) {
|
168
|
+
const value = input.value;
|
169
|
+
let cursorPos = input.selectionStart;
|
170
|
+
|
171
|
+
// If cursor is just after a space, move it back to find previous word
|
172
|
+
if (cursorPos > 0 && value[cursorPos - 1] === " ") {
|
173
|
+
cursorPos--;
|
174
|
+
}
|
175
|
+
|
176
|
+
// Skip any Devanagari characters while going backwards
|
177
|
+
let wordStart = cursorPos;
|
178
|
+
while (
|
179
|
+
wordStart > 0 &&
|
180
|
+
value[wordStart - 1].match(/[a-zA-Z0-9]/) // Only count English letters and numbers
|
181
|
+
) {
|
182
|
+
wordStart--;
|
183
|
+
}
|
184
|
+
|
185
|
+
// Skip Devanagari going forward too
|
186
|
+
let wordEnd = cursorPos;
|
187
|
+
while (
|
188
|
+
wordEnd < value.length &&
|
189
|
+
value[wordEnd].match(/[a-zA-Z0-9]/)
|
190
|
+
) {
|
191
|
+
wordEnd++;
|
192
|
+
}
|
193
|
+
|
194
|
+
|
195
|
+
let word = value.slice(wordStart, wordEnd);
|
196
|
+
|
197
|
+
return { word, wordStart, wordEnd };
|
198
|
+
}
|
199
|
+
|
200
|
+
hideSuggestions() {
|
201
|
+
this.suggestionsTarget.innerHTML = "";
|
202
|
+
this.suggestionsTarget.style.border = "0";
|
203
|
+
this.suggestionsTarget.style.padding = "0";
|
204
|
+
}
|
205
|
+
|
206
|
+
showSuggestionsBox() {
|
207
|
+
|
208
|
+
const rect = this.inputTarget.getBoundingClientRect();
|
209
|
+
|
210
|
+
// Calculate position relative to the document
|
211
|
+
const scrollTop = window.scrollY || window.pageYOffset;
|
212
|
+
const scrollLeft = window.scrollX || window.pageXOffset;
|
213
|
+
|
214
|
+
// Set position just below the input
|
215
|
+
this.suggestionsTarget.style.top = `${rect.bottom + scrollTop}px`;
|
216
|
+
this.suggestionsTarget.style.left = `${rect.left + scrollLeft}px`;
|
217
|
+
|
218
|
+
this.suggestionsTarget.innerHTML = "";
|
219
|
+
this.suggestionsTarget.style.border = "1px solid #0a0a0a";
|
220
|
+
this.suggestionsTarget.style.padding = "4px";
|
221
|
+
}
|
156
222
|
|
223
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marathi_typing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ajit Dhanje
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-04-
|
11
|
+
date: 2025-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|