griffincss-ui 0.23.1 → 0.25.0-dev
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.
- package/dist/griffincss-ui-scoped.css +1 -1
- package/dist/griffincss-ui.css +1 -1
- package/dist/griffincss-ui.js +1 -1
- package/dist/griffinjs-combobox.js +1 -1
- package/dist/griffinjs-combobox.js.map +1 -1
- package/dist/griffinjs-core.js +1 -1
- package/dist/griffinjs-datetime.js +1 -1
- package/dist/griffinjs-datetime.js.map +1 -1
- package/dist/griffinjs-fields.css +1 -1
- package/dist/griffinjs-fields.js +1 -1
- package/dist/griffinjs-fields.js.map +1 -1
- package/dist/griffinjs-mask.js +1 -1
- package/dist/griffinjs-mask.js.map +1 -1
- package/dist/griffinjs-number.js +3 -0
- package/dist/griffinjs-number.js.map +1 -0
- package/dist/griffinjs-phone.js +1 -1
- package/dist/griffinjs-phone.js.map +1 -1
- package/dist/griffinjs-range.js +1 -1
- package/dist/griffinjs-range.js.map +1 -1
- package/dist/griffinjs.js +1 -1
- package/dist/griffinjs.js.map +1 -1
- package/package.json +3 -3
- package/scss/_button.scss +21 -0
- package/scss/_choice.scss +90 -0
- package/scss/_steps.scss +6 -2
- package/scss/griffincss-ui-scoped.scss +4 -2
- package/scss/griffincss-ui.scss +9 -2
- package/scss/griffinjs/fields/_datetime.scss +7 -0
- package/scss/griffinjs/fields/_number.scss +12 -0
- package/scss/griffinjs/fields/fields.scss +1 -0
- package/src/griffincss-ui.js +2 -2
- package/src/griffinjs/core/griffinjs-core.js +2 -2
- package/src/griffinjs/fields/datetime.js +103 -6
- package/src/griffinjs/fields/mask.js +28 -7
- package/src/griffinjs/fields/number.js +327 -0
- package/src/griffinjs/fields/phone.js +17 -3
- package/src/griffinjs/widgets/combobox.js +15 -2
- package/src/griffinjs/widgets/range.js +81 -7
|
@@ -15,8 +15,10 @@
|
|
|
15
15
|
* зовётся иначе, чем виджет: data-gr-mask на позиции списка ядро приняло бы
|
|
16
16
|
* за виджет и попыталось бы надеть маску на <option>. Пустой <select> заполняется
|
|
17
17
|
* из таблицы griffinjs-countries.js, если она подключена; без неё виджет
|
|
18
|
-
* предупреждает и работает как поле без маски.
|
|
19
|
-
*
|
|
18
|
+
* предупреждает и работает как поле без маски. Начальная страна списка
|
|
19
|
+
* из таблицы — параметр country; без него первой стоит первая по алфавиту
|
|
20
|
+
* языка страницы, и виджет предупреждает об этом в консоли. Данные
|
|
21
|
+
* со своим темпом обновления библиотека вместе с кодом не сопровождает.
|
|
20
22
|
*
|
|
21
23
|
* Имя страны и флаг — у платформы: Intl.DisplayNames в языке страницы
|
|
22
24
|
* (lang документа) и пара региональных индикаторов из двух букв ISO.
|
|
@@ -34,6 +36,13 @@
|
|
|
34
36
|
* два поля: код и национальный номер; целиком он в value() и в событии
|
|
35
37
|
* griffin:change.
|
|
36
38
|
*
|
|
39
|
+
* Проверка приходит от маски и вместе со страной: недобранный номер
|
|
40
|
+
* не проходит checkValidity(), и смена кода пересчитывает полноту —
|
|
41
|
+
* девяти знаков хватает Беларуси и мало России. Проверяется ДЛИНА номера
|
|
42
|
+
* по маске выбранной страны, а не тип номера и не диапазон оператора:
|
|
43
|
+
* libphonenumber в замену не входит. value() при этом отражает набранное,
|
|
44
|
+
* даже неполное, — полнота отдаётся признаком complete в griffin:change.
|
|
45
|
+
*
|
|
37
46
|
* База без скрипта: type="tel" и <select> кодов в .gr-input-group —
|
|
38
47
|
* обе части платформенные.
|
|
39
48
|
*/
|
|
@@ -129,6 +138,11 @@
|
|
|
129
138
|
select.appendChild(option);
|
|
130
139
|
created.push(option);
|
|
131
140
|
}
|
|
141
|
+
|
|
142
|
+
// Без country первой стоит первая по алфавиту языка страницы —
|
|
143
|
+
// на русской это Австралия, +61. Угадывать страну за автора виджет
|
|
144
|
+
// не берётся: ошибся бы тише, чем сейчас. Но и молчать не должен.
|
|
145
|
+
if (!o.country) G.warn('телефон: страна не задана — выбрана первая по алфавиту; укажите country');
|
|
132
146
|
}
|
|
133
147
|
|
|
134
148
|
if (!options().length) {
|
|
@@ -184,7 +198,7 @@
|
|
|
184
198
|
function emit() {
|
|
185
199
|
var c = info(current());
|
|
186
200
|
|
|
187
|
-
G.emit('griffin:change', el, { iso: c.iso, code: c.code, value: value() });
|
|
201
|
+
G.emit('griffin:change', el, { iso: c.iso, code: c.code, value: value(), complete: mask ? mask.complete() : true });
|
|
188
202
|
}
|
|
189
203
|
|
|
190
204
|
// Полный номер с плюсом: страна — по самому длинному коду, который
|
|
@@ -39,6 +39,13 @@
|
|
|
39
39
|
* удаление тега или Backspace в пустом поле снимает выбор. Значение всегда
|
|
40
40
|
* в <select> — форма отправляет его как без скрипта; о смене он сообщает
|
|
41
41
|
* событием change.
|
|
42
|
+
*
|
|
43
|
+
* Свободные теги (Этап 42f) — флаг free рядом с multiple: Enter на непустом
|
|
44
|
+
* поле без активной позиции создаёт <option selected> со значением, равным
|
|
45
|
+
* тексту (ключевые слова, адреса писем). Дубликата по значению нет —
|
|
46
|
+
* существующая позиция просто выбирается. На сервер значение уходит
|
|
47
|
+
* текстом, проверять его — там. Без multiple флаг смысла не имеет: текст
|
|
48
|
+
* поля и есть значение, — и пропускается с предупреждением.
|
|
42
49
|
*/
|
|
43
50
|
(function (G) {
|
|
44
51
|
'use strict';
|
|
@@ -54,6 +61,7 @@
|
|
|
54
61
|
highlight: true,
|
|
55
62
|
cache: true,
|
|
56
63
|
multiple: false, // выбранное — теги, значение — в <select multiple>
|
|
64
|
+
free: false, // Enter без позиции — новый тег из текста (только с multiple)
|
|
57
65
|
remove: 'Убрать {label}'
|
|
58
66
|
};
|
|
59
67
|
|
|
@@ -137,6 +145,7 @@
|
|
|
137
145
|
var choice = o.multiple ? el.querySelector('select[multiple]') : null;
|
|
138
146
|
|
|
139
147
|
if (o.multiple && !choice) throw new Error('для multiple нужен <select multiple> внутри');
|
|
148
|
+
if (o.free && !choice) { G.warn('комбобокс: free без multiple смысла не имеет — флаг пропущен'); o.free = false; }
|
|
140
149
|
|
|
141
150
|
var list = el.querySelector('[role="listbox"]');
|
|
142
151
|
var created = false;
|
|
@@ -452,8 +461,12 @@
|
|
|
452
461
|
activate(key === 'Home' ? 0 : items.length - 1, true);
|
|
453
462
|
event.preventDefault();
|
|
454
463
|
} else if (key === 'Enter') {
|
|
455
|
-
|
|
456
|
-
|
|
464
|
+
var text = input.value.trim();
|
|
465
|
+
|
|
466
|
+
if (opened && active >= 0) select(active);
|
|
467
|
+
else if (o.free && text) { add(text, text); input.value = ''; close(); }
|
|
468
|
+
else return;
|
|
469
|
+
|
|
457
470
|
event.preventDefault();
|
|
458
471
|
} else if (key === 'Escape') {
|
|
459
472
|
if (!opened) return;
|
|
@@ -22,6 +22,20 @@
|
|
|
22
22
|
* Второе дело скрипта в паре — порядок значений: тот, кого потянули
|
|
23
23
|
* за чужую границу, толкает вторую ручку перед собой. Пересечься им
|
|
24
24
|
* нельзя — отрезок между ручками вывернулся бы наизнанку.
|
|
25
|
+
*
|
|
26
|
+
* Третье — связка с числовыми полями (Этап 42a):
|
|
27
|
+
*
|
|
28
|
+
* <div class="gr-range-pair" data-gr-range="fields: #price-min, #price-max">
|
|
29
|
+
*
|
|
30
|
+
* Селекторов столько же, сколько ползунков. Движение ручки пишет число
|
|
31
|
+
* в своё поле (после наведения порядка); ввод в поле двигает ручку
|
|
32
|
+
* с зажимом по min/max, а порядок наводится только на change — «1»
|
|
33
|
+
* по пути к «1000» иначе толкнул бы вторую ручку. Форму отправляют поля:
|
|
34
|
+
* name — у них, у ползунков его нет, иначе в GET уехали бы четыре
|
|
35
|
+
* параметра. Правда — в полях: страница вернулась с ними, а атрибуты
|
|
36
|
+
* value ползунков остались начальными, поэтому на монтаже ручки встают
|
|
37
|
+
* по полям; пустое поле — ручка на своём краю. Само поле от монтажа
|
|
38
|
+
* не заполняется: «фильтр не задан» остаётся пустым.
|
|
25
39
|
*/
|
|
26
40
|
(function (G) {
|
|
27
41
|
'use strict';
|
|
@@ -50,20 +64,59 @@
|
|
|
50
64
|
return num(current, num(input.getAttribute('min'), 0));
|
|
51
65
|
}
|
|
52
66
|
|
|
53
|
-
|
|
67
|
+
function edge(input, name, fallback) {
|
|
68
|
+
return num(input.getAttribute(name), fallback);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
G.defineWidget('range', function (el, opts) {
|
|
54
72
|
var single = el.tagName === 'INPUT';
|
|
55
73
|
var inputs = single ? [el] : [].slice.call(el.querySelectorAll('input[type="range"]'));
|
|
56
74
|
var listeners = G.listeners();
|
|
75
|
+
var fields = [];
|
|
57
76
|
|
|
58
77
|
if (!inputs.length) throw new Error('внутри нет ни одного <input type="range">');
|
|
59
78
|
|
|
60
79
|
function doneOf(input) {
|
|
61
|
-
var min =
|
|
62
|
-
var span =
|
|
80
|
+
var min = edge(input, 'min', 0);
|
|
81
|
+
var span = edge(input, 'max', 100) - min;
|
|
63
82
|
|
|
64
83
|
return round(span > 0 ? (valueOf(input) - min) / span : 0);
|
|
65
84
|
}
|
|
66
85
|
|
|
86
|
+
// Число из поля — в ползунок: пустое поле ставит ручку на свой край
|
|
87
|
+
// (нижняя граница не задана — от min, верхняя — до max), число зажимается.
|
|
88
|
+
function pull(i) {
|
|
89
|
+
var input = inputs[i];
|
|
90
|
+
var min = edge(input, 'min', 0);
|
|
91
|
+
var max = edge(input, 'max', 100);
|
|
92
|
+
var value = fields[i].value;
|
|
93
|
+
|
|
94
|
+
input.value = value === '' ? (i ? max : min) : Math.max(min, Math.min(max, num(value, min)));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Значения ручек — в поля, кроме того, откуда пришёл ввод: оно уже
|
|
98
|
+
// содержит то, что человек написал, и переписывать его под рукой нельзя.
|
|
99
|
+
function push(except) {
|
|
100
|
+
for (var i = 0; i < fields.length; i++) if (fields[i] !== except) fields[i].value = valueOf(inputs[i]);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function typed(event) {
|
|
104
|
+
var field = event.target;
|
|
105
|
+
var i = fields.indexOf(field);
|
|
106
|
+
|
|
107
|
+
pull(i);
|
|
108
|
+
|
|
109
|
+
// Пока число не дописано, ручки могут стоять наоборот: отрезок между
|
|
110
|
+
// ними на это время вырождается в точку, и это лучше толчка второй ручки.
|
|
111
|
+
if (event.type === 'change') {
|
|
112
|
+
order(inputs[i]);
|
|
113
|
+
push(field);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
paint();
|
|
117
|
+
emit();
|
|
118
|
+
}
|
|
119
|
+
|
|
67
120
|
// Порядок значений в паре. Толкает именно вторую ручку, а не возвращает
|
|
68
121
|
// первую: человек ведёт ту, за которую взялся, и остановка под пальцем
|
|
69
122
|
// читалась бы как поломка.
|
|
@@ -79,20 +132,26 @@
|
|
|
79
132
|
else to.value = from.value;
|
|
80
133
|
}
|
|
81
134
|
|
|
82
|
-
function
|
|
83
|
-
order(event && event.target);
|
|
84
|
-
|
|
135
|
+
function paint() {
|
|
85
136
|
if (inputs.length > 1) {
|
|
86
137
|
el.style.setProperty(FROM, doneOf(inputs[0]));
|
|
87
138
|
el.style.setProperty(TO, doneOf(inputs[1]));
|
|
88
139
|
} else {
|
|
89
140
|
inputs[0].style.setProperty(PROP, doneOf(inputs[0]));
|
|
90
141
|
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function update(event) {
|
|
145
|
+
order(event && event.target);
|
|
146
|
+
paint();
|
|
91
147
|
|
|
92
148
|
// Событие — после наведения порядка, и только на живое движение ручки.
|
|
93
149
|
// Подпись рядом с парой иначе показала бы значения ДО толчка: свой
|
|
94
150
|
// обработчик на ползунке отработает раньше нашего, стоящего на обёртке.
|
|
95
|
-
if (event)
|
|
151
|
+
if (event) {
|
|
152
|
+
push();
|
|
153
|
+
emit();
|
|
154
|
+
}
|
|
96
155
|
}
|
|
97
156
|
|
|
98
157
|
function emit() {
|
|
@@ -107,6 +166,21 @@
|
|
|
107
166
|
// и второй ручке отдельная подписка не нужна.
|
|
108
167
|
listeners.add(el, 'input', update);
|
|
109
168
|
|
|
169
|
+
if (opts && opts.fields) {
|
|
170
|
+
var selectors = String(opts.fields).split(',');
|
|
171
|
+
|
|
172
|
+
for (var f = 0; f < inputs.length; f++) {
|
|
173
|
+
var field = document.querySelector(selectors[f] || '#');
|
|
174
|
+
|
|
175
|
+
if (!field) throw new Error('поле «' + selectors[f] + '» не найдено');
|
|
176
|
+
|
|
177
|
+
fields.push(field);
|
|
178
|
+
pull(f);
|
|
179
|
+
listeners.add(field, 'input', typed);
|
|
180
|
+
listeners.add(field, 'change', typed);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
110
184
|
update();
|
|
111
185
|
|
|
112
186
|
return {
|