katalyst-tables 3.5.5 → 3.6.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 +4 -4
- data/app/assets/builds/katalyst/tables.esm.js +197 -24
- data/app/assets/builds/katalyst/tables.js +197 -24
- data/app/assets/builds/katalyst/tables.min.js +1 -1
- data/app/assets/builds/katalyst/tables.min.js.map +1 -1
- data/app/assets/stylesheets/katalyst/tables/_query.scss +37 -3
- data/app/components/katalyst/tables/cells/currency_component.rb +1 -1
- data/app/components/katalyst/tables/query/input_component.html.erb +6 -1
- data/app/components/katalyst/tables/query/input_component.rb +5 -1
- data/app/components/katalyst/tables/query/modal_component.html.erb +2 -2
- data/app/components/katalyst/tables/query/modal_component.rb +7 -2
- data/app/components/katalyst/tables/query/suggestion_component.rb +21 -1
- data/app/components/katalyst/tables/query_component.rb +1 -0
- data/app/javascript/tables/query_controller.js +91 -11
- data/app/javascript/tables/query_input_controller.js +105 -12
- data/app/models/concerns/katalyst/tables/collection/core.rb +1 -1
- data/config/locales/tables.en.yml +2 -2
- metadata +3 -3
@@ -24,6 +24,49 @@ export default class QueryInputController extends Controller {
|
|
24
24
|
this.highlightTarget.appendChild(token.render());
|
25
25
|
});
|
26
26
|
}
|
27
|
+
|
28
|
+
replaceToken(e) {
|
29
|
+
let tokenToAdd = e.detail.token.toString();
|
30
|
+
|
31
|
+
// wrap in quotes if it contains a spaces or special characters
|
32
|
+
if (/\s/.exec(tokenToAdd)) {
|
33
|
+
tokenToAdd = `"${tokenToAdd}"`;
|
34
|
+
}
|
35
|
+
|
36
|
+
const indexPosition = e.detail.position;
|
37
|
+
let caretPosition = indexPosition + tokenToAdd.length;
|
38
|
+
let sliceStart = indexPosition;
|
39
|
+
let sliceEnd = indexPosition;
|
40
|
+
|
41
|
+
// detect if position has a token already, if so, replace it
|
42
|
+
const existingToken = new Parser()
|
43
|
+
.parse(this.queryValue)
|
44
|
+
.tokenAtPosition(indexPosition);
|
45
|
+
if (existingToken) {
|
46
|
+
// We don't want to include the trailing space as we are replacing an existing value
|
47
|
+
tokenToAdd = tokenToAdd.trim();
|
48
|
+
|
49
|
+
// Slice up to the beginning of the tokens value (not the initial caret position)
|
50
|
+
sliceStart = existingToken.startOfValue();
|
51
|
+
|
52
|
+
// Slice after the end of the tokens value
|
53
|
+
sliceEnd = existingToken.endOfValue();
|
54
|
+
|
55
|
+
// The end position of the newly added token
|
56
|
+
caretPosition = sliceStart + tokenToAdd.length;
|
57
|
+
}
|
58
|
+
|
59
|
+
// Replace any text within sliceStart and sliceEnd with tokenToAdd
|
60
|
+
this.inputTarget.value =
|
61
|
+
this.queryValue.slice(0, sliceStart) +
|
62
|
+
tokenToAdd +
|
63
|
+
this.queryValue.slice(sliceEnd);
|
64
|
+
|
65
|
+
// Re focus the input at the end of the newly added token
|
66
|
+
this.update();
|
67
|
+
this.inputTarget.focus();
|
68
|
+
this.inputTarget.setSelectionRange(caretPosition, caretPosition);
|
69
|
+
}
|
27
70
|
}
|
28
71
|
|
29
72
|
class Parser {
|
@@ -57,13 +100,13 @@ class Parser {
|
|
57
100
|
skipWhitespace(query) {
|
58
101
|
if (!query.scan(/\s+/)) return;
|
59
102
|
|
60
|
-
return new Token(query.matched());
|
103
|
+
return new Token(query.matched(), query.position);
|
61
104
|
}
|
62
105
|
|
63
106
|
takeUntagged(query) {
|
64
107
|
if (!query.scan(/\S+/)) return;
|
65
108
|
|
66
|
-
return new Untagged(query.matched());
|
109
|
+
return new Untagged(query.matched(), query.position);
|
67
110
|
}
|
68
111
|
|
69
112
|
takeTagged(query) {
|
@@ -75,13 +118,13 @@ class Parser {
|
|
75
118
|
const value =
|
76
119
|
this.takeArrayValue(query) || this.takeSingleValue(query) || new Token();
|
77
120
|
|
78
|
-
return new Tagged(key, separator, value);
|
121
|
+
return new Tagged(key, separator, value, query.position);
|
79
122
|
}
|
80
123
|
|
81
124
|
takeArrayValue(query) {
|
82
125
|
if (!query.scan(/\[\s*/)) return;
|
83
126
|
|
84
|
-
const start = new Token(query.matched());
|
127
|
+
const start = new Token(query.matched(), query.position);
|
85
128
|
const values = (this.values = []);
|
86
129
|
|
87
130
|
while (!query.isEos()) {
|
@@ -90,17 +133,17 @@ class Parser {
|
|
90
133
|
}
|
91
134
|
|
92
135
|
query.scan(/\s*]/);
|
93
|
-
const end = new Token(query.matched());
|
136
|
+
const end = new Token(query.matched(), query.position);
|
94
137
|
|
95
138
|
this.values = null;
|
96
139
|
|
97
|
-
return new
|
140
|
+
return new ArrayToken(start, values, end);
|
98
141
|
}
|
99
142
|
|
100
143
|
takeDelimiter(query) {
|
101
144
|
if (!query.scan(/\s*,\s*/)) return;
|
102
145
|
|
103
|
-
return new Token(query.matched());
|
146
|
+
return new Token(query.matched(), query.position);
|
104
147
|
}
|
105
148
|
|
106
149
|
takeSingleValue(query) {
|
@@ -110,24 +153,49 @@ class Parser {
|
|
110
153
|
takeQuotedValue(query) {
|
111
154
|
if (!query.scan(/"([^"]*)"/)) return;
|
112
155
|
|
113
|
-
return new Value(query.matched());
|
156
|
+
return new Value(query.matched(), query.position);
|
114
157
|
}
|
115
158
|
|
116
159
|
takeUnquotedValue(query) {
|
117
160
|
if (!query.scan(/[^ \],]*/)) return;
|
118
161
|
|
119
|
-
return new Value(query.matched());
|
162
|
+
return new Value(query.matched(), query.position);
|
163
|
+
}
|
164
|
+
|
165
|
+
tokenAtPosition(position) {
|
166
|
+
return this.tokens
|
167
|
+
.filter((t) => t instanceof Tagged || t instanceof Untagged)
|
168
|
+
.find((t) => t.range.includes(position));
|
120
169
|
}
|
121
170
|
}
|
122
171
|
|
123
172
|
class Token {
|
124
|
-
constructor(value = "") {
|
173
|
+
constructor(value = "", position) {
|
125
174
|
this.value = value;
|
175
|
+
this.length = this.value.length;
|
176
|
+
this.start = position - this.length;
|
177
|
+
this.end = this.start + this.length;
|
178
|
+
this.range = this.arrayRange(this.start, this.end);
|
126
179
|
}
|
127
180
|
|
128
181
|
render() {
|
129
182
|
return document.createTextNode(this.value);
|
130
183
|
}
|
184
|
+
|
185
|
+
arrayRange(start, stop) {
|
186
|
+
return Array.from(
|
187
|
+
{ length: stop - start + 1 },
|
188
|
+
(value, index) => start + index,
|
189
|
+
);
|
190
|
+
}
|
191
|
+
|
192
|
+
startOfValue() {
|
193
|
+
return this.start;
|
194
|
+
}
|
195
|
+
|
196
|
+
endOfValue() {
|
197
|
+
return this.end;
|
198
|
+
}
|
131
199
|
}
|
132
200
|
|
133
201
|
class Value extends Token {
|
@@ -141,12 +209,16 @@ class Value extends Token {
|
|
141
209
|
}
|
142
210
|
|
143
211
|
class Tagged extends Token {
|
144
|
-
constructor(key, separator, value) {
|
212
|
+
constructor(key, separator, value, position) {
|
145
213
|
super();
|
146
214
|
|
147
215
|
this.key = key;
|
148
216
|
this.separator = separator;
|
149
217
|
this.value = value;
|
218
|
+
this.length = key.length + separator.length + value.value.length;
|
219
|
+
this.start = position - this.length;
|
220
|
+
this.end = this.start + this.length;
|
221
|
+
this.range = this.arrayRange(this.start, this.end);
|
150
222
|
}
|
151
223
|
|
152
224
|
render() {
|
@@ -163,6 +235,14 @@ class Tagged extends Token {
|
|
163
235
|
|
164
236
|
return span;
|
165
237
|
}
|
238
|
+
|
239
|
+
startOfValue() {
|
240
|
+
return this.value.startOfValue();
|
241
|
+
}
|
242
|
+
|
243
|
+
endOfValue() {
|
244
|
+
return this.value.endOfValue();
|
245
|
+
}
|
166
246
|
}
|
167
247
|
|
168
248
|
class Untagged extends Token {
|
@@ -174,13 +254,18 @@ class Untagged extends Token {
|
|
174
254
|
}
|
175
255
|
}
|
176
256
|
|
177
|
-
class
|
257
|
+
class ArrayToken extends Token {
|
178
258
|
constructor(start, values, end) {
|
179
259
|
super();
|
180
260
|
|
181
261
|
this.start = start;
|
182
262
|
this.values = values;
|
183
263
|
this.end = end;
|
264
|
+
this.range = this.arrayRange(start.start, end.range[end.length]);
|
265
|
+
this.length =
|
266
|
+
start.length +
|
267
|
+
values.reduce((length, value) => length + value.length, 0) +
|
268
|
+
end.length;
|
184
269
|
}
|
185
270
|
|
186
271
|
render() {
|
@@ -198,6 +283,14 @@ class Array extends Token {
|
|
198
283
|
|
199
284
|
return array;
|
200
285
|
}
|
286
|
+
|
287
|
+
startOfValue() {
|
288
|
+
return this.start.start;
|
289
|
+
}
|
290
|
+
|
291
|
+
endOfValue() {
|
292
|
+
return this.end.end;
|
293
|
+
}
|
201
294
|
}
|
202
295
|
|
203
296
|
class StringScanner {
|
@@ -29,7 +29,7 @@ module Katalyst
|
|
29
29
|
using Type::Helpers::Extensions
|
30
30
|
|
31
31
|
def attribute(name, type = nil, default: (no_default = true), **)
|
32
|
-
type = type.is_a?(Symbol) ? resolve_type_name(type, **) : type || Type::Value.new
|
32
|
+
type = type.is_a?(Symbol) ? resolve_type_name(type, **) : type || Type::Value.new(**)
|
33
33
|
|
34
34
|
default = type.default_value if no_default
|
35
35
|
|
@@ -12,5 +12,5 @@ en:
|
|
12
12
|
errors:
|
13
13
|
attributes:
|
14
14
|
query:
|
15
|
-
unknown_key: "The
|
16
|
-
no_untagged_search: "'%{input}' isn't searchable
|
15
|
+
unknown_key: "The search option '%{input}' isn’t valid. Please check your input."
|
16
|
+
no_untagged_search: "'%{input}' isn't searchable. Please choose a valid search option."
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: katalyst-tables
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Katalyst Interactive
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: katalyst-html-attributes
|
@@ -190,7 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
190
190
|
- !ruby/object:Gem::Version
|
191
191
|
version: '0'
|
192
192
|
requirements: []
|
193
|
-
rubygems_version: 3.5.
|
193
|
+
rubygems_version: 3.5.16
|
194
194
|
signing_key:
|
195
195
|
specification_version: 4
|
196
196
|
summary: HTML table generator for Rails views
|