griffincss-ui 0.24.0-dev → 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.
@@ -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
- G.defineWidget('range', function (el) {
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 = num(input.getAttribute('min'), 0);
62
- var span = num(input.getAttribute('max'), 100) - min;
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 update(event) {
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) emit();
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 {