cdek 0.3.13 → 0.3.16
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/CHANGELOG.md +55 -0
- data/README.md +3 -1
- data/app/helpers/cdek/widget_helper.rb +4 -1
- data/lib/cdek/version.rb +1 -1
- data/lib/generators/cdek/install/templates/cdek_widget_controller.js +30 -18
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1dd8710b9122c71addd999aab3d16759f3a919916a11e3d1715d88483d6aa21b
|
|
4
|
+
data.tar.gz: 50b97380e716f8b23c4d75165552caff3c93856b814a3f64b2ac725e6a61ff02
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b4adea92e439961fce478880f1792bb9790809bdf1073e3bc1ba45a4468652558f59278bae279bd0bf40643876bcf9ea96e14f9c6c7e4f779d150baa299b444b
|
|
7
|
+
data.tar.gz: be21d7a9b78b4bdefc1c624742b6a52e5de70228b93497571731ff714379f936f035792fa5dad2daa7963096195eab58e7bcdb86a54add254df46f24e3dde87d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,60 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.16
|
|
4
|
+
|
|
5
|
+
* Полная изоляция инстансов виджета между открытиями карты. Singleton-гард
|
|
6
|
+
0.3.14 (один живой инстанс) оказался недостаточным: `@cdek-it/widget@3`
|
|
7
|
+
держит ГЛОБАЛЬНЫЙ pinia-стор на уровне модуля, а `destroy()` размонтирует
|
|
8
|
+
Vue-приложение, но не очищает этот стор и не снимает подписки, заведённые
|
|
9
|
+
в бутстрапе виджета (вне дерева компонентов). После смены города
|
|
10
|
+
(пересоздания модалки) подписки уничтоженного инстанса оставались на общем
|
|
11
|
+
сторе и, реагируя на запись нового инстанса, перезапрашивали офисы и
|
|
12
|
+
пере-центрировали карту на ПРЕЖНИЙ город — точки нового города уходили
|
|
13
|
+
«за границы» и пропадали навсегда (в server-логах — `widget_service` по
|
|
14
|
+
старому городу сразу после нового).
|
|
15
|
+
* Решение: шаблон `cdek_widget_controller.js` теперь перед каждым монтажом
|
|
16
|
+
удаляет `window.CDEKWidget` и заново выполняет бандл, поэтому каждый виджет
|
|
17
|
+
получает свежий модуль со своим стором, а подписки прежнего инстанса висят
|
|
18
|
+
на осиротевшем сторе и на новый виджет не влияют. Повторное выполнение
|
|
19
|
+
бандла безопасно: Yandex Maps (ymaps3) грузится идемпотентно, дублирование
|
|
20
|
+
`<style>` безвредно, custom elements не регистрируются. Прежний
|
|
21
|
+
`ensureWidgetScript` (один общий `_scriptPromise`) заменён на
|
|
22
|
+
`loadFreshWidgetScript`.
|
|
23
|
+
* Шаблон генератора снова пишет координаты выбранного ПВЗ (`office.location`
|
|
24
|
+
→ строка `"lon lat"`) в скрытое поле `order_cdek_point_coors`. Поддержка
|
|
25
|
+
`fieldCoors` была в host-копиях ≤0.3.12, но потерялась при переносе фиксов
|
|
26
|
+
0.3.13/0.3.14 в шаблон — из-за этого после синхронизации контроллера
|
|
27
|
+
хост-приложение переставало получать координаты пункта и не могло
|
|
28
|
+
отрисовать карту заказа. Значение `fieldCoors` (по умолчанию
|
|
29
|
+
`order_cdek_point_coors`) и его data-атрибут `cdek_widget_field_coors_value`
|
|
30
|
+
добавлены и в шаблон, и в `cdek_widget_tag` (новый необязательный параметр
|
|
31
|
+
`field_coors:`), консистентно с остальными `field_*`.
|
|
32
|
+
* Шаблон: после асинхронной загрузки скрипта виджета монтирование
|
|
33
|
+
выполняется только если контроллер ещё подключён
|
|
34
|
+
(`if (this._connected) this._mountWidget()`). Раньше промис загрузки мог
|
|
35
|
+
доехать уже после `disconnect()` (быстрое закрытие/переоткрытие модалки),
|
|
36
|
+
и виджет монтировался в уже отсоединённый узел.
|
|
37
|
+
* Совокупно с 0.3.13 (центрирование карты по координатам вместо асинхронного
|
|
38
|
+
геокодинга названия) и 0.3.14 (ровно один живой инстанс) это полностью
|
|
39
|
+
убирает «мелькание» и пропадание точек ПВЗ при открытии карты после смены
|
|
40
|
+
города. Хост-приложениям, сгенерировавшим контроллер на ≤0.3.15, нужно
|
|
41
|
+
перегенерировать его (`bin/rails generate cdek:install`) или внести правку
|
|
42
|
+
вручную из шаблона.
|
|
43
|
+
|
|
44
|
+
## 0.3.14
|
|
45
|
+
|
|
46
|
+
* Шаблон генератора `cdek_widget_controller.js` теперь держит ровно один
|
|
47
|
+
живой инстанс виджета на странице: предыдущий уничтожается синхронно
|
|
48
|
+
перед монтированием нового. `@cdek-it/widget` — Vue-приложение с
|
|
49
|
+
глобальным стором, поэтому два одновременно живых инстанса делили стор
|
|
50
|
+
и конфликтовали — при смене города (пересоздание модалки) старый инстанс
|
|
51
|
+
перезапрашивал офисы и пере-центрировал карту на прежний город (точки
|
|
52
|
+
выбранного города мелькали и пропадали). Добавлены module-level
|
|
53
|
+
`_activeWidget` и `destroyWidget()`; `disconnect` и `_mountWidget`
|
|
54
|
+
переведены на них. Хост-приложениям, сгенерировавшим контроллер на
|
|
55
|
+
≤0.3.13, нужно перегенерировать его (`bin/rails generate cdek:install`)
|
|
56
|
+
или внести правку вручную.
|
|
57
|
+
|
|
3
58
|
## 0.3.13
|
|
4
59
|
|
|
5
60
|
* Виджет ПВЗ больше не откатывает центр карты на Москву при выборе
|
data/README.md
CHANGED
|
@@ -115,9 +115,11 @@ suggestions = Cdek.city_suggestions("мос")
|
|
|
115
115
|
* `#order_cdek_point_name`
|
|
116
116
|
* `#order_cdek_point_address`
|
|
117
117
|
* `#order_cdek_city_code`
|
|
118
|
+
* `#order_cdek_point_coors` — координаты ПВЗ строкой `"долгота широта"`
|
|
119
|
+
(из `office.location`), чтобы хост мог отрисовать карту заказа.
|
|
118
120
|
|
|
119
121
|
DOM-id переопределяются именованными аргументами `field_code`,
|
|
120
|
-
`field_name`, `field_address`, `field_city_code` хелпера.
|
|
122
|
+
`field_name`, `field_address`, `field_city_code`, `field_coors` хелпера.
|
|
121
123
|
|
|
122
124
|
5. Также диспатчится событие `cdek-widget:chosen` с `detail.office` —
|
|
123
125
|
можно слушать в собственных Stimulus-контроллерах.
|
|
@@ -43,6 +43,7 @@ module Cdek
|
|
|
43
43
|
field_name: "order_cdek_point_name",
|
|
44
44
|
field_address: "order_cdek_point_address",
|
|
45
45
|
field_city_code: "order_cdek_city_code",
|
|
46
|
+
field_coors: "order_cdek_point_coors",
|
|
46
47
|
label_selector: "[data-cdek-widget-label]",
|
|
47
48
|
address_selector: "#order_cdek_point_address_view",
|
|
48
49
|
height: "600px")
|
|
@@ -62,6 +63,7 @@ module Cdek
|
|
|
62
63
|
field_name: field_name,
|
|
63
64
|
field_address: field_address,
|
|
64
65
|
field_city_code: field_city_code,
|
|
66
|
+
field_coors: field_coors,
|
|
65
67
|
label_selector: label_selector,
|
|
66
68
|
address_selector: address_selector
|
|
67
69
|
)
|
|
@@ -95,7 +97,7 @@ module Cdek
|
|
|
95
97
|
def cdek_widget_data(api_key:, default_city:, default_coords:, sender_city:, sender_city_code:,
|
|
96
98
|
goods_json:,
|
|
97
99
|
service_path:, script_url:, modal_id:,
|
|
98
|
-
field_code:, field_name:, field_address:, field_city_code:,
|
|
100
|
+
field_code:, field_name:, field_address:, field_city_code:, field_coors:,
|
|
99
101
|
label_selector:, address_selector:)
|
|
100
102
|
{
|
|
101
103
|
controller: "cdek-widget",
|
|
@@ -112,6 +114,7 @@ module Cdek
|
|
|
112
114
|
cdek_widget_field_name_value: field_name,
|
|
113
115
|
cdek_widget_field_address_value: field_address,
|
|
114
116
|
cdek_widget_field_city_code_value: field_city_code,
|
|
117
|
+
cdek_widget_field_coors_value: field_coors,
|
|
115
118
|
cdek_widget_label_selector_value: label_selector,
|
|
116
119
|
cdek_widget_address_selector_value: address_selector
|
|
117
120
|
}
|
data/lib/cdek/version.rb
CHANGED
|
@@ -26,22 +26,27 @@ import { Controller } from "@hotwired/stimulus"
|
|
|
26
26
|
// виджет будет открыт без расчётных packages, чтобы не считать доставку
|
|
27
27
|
// по выдуманным размерам.
|
|
28
28
|
|
|
29
|
-
let
|
|
29
|
+
let _activeWidget = null
|
|
30
30
|
|
|
31
|
-
function
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
function destroyWidget(widget) {
|
|
32
|
+
if (!widget) return
|
|
33
|
+
try {
|
|
34
|
+
if (typeof widget.destroy === "function") widget.destroy()
|
|
35
|
+
else if (typeof widget.close === "function") widget.close()
|
|
36
|
+
} catch (_) { /* виджет мог не домонтироваться — это ок */ }
|
|
37
|
+
if (_activeWidget === widget) _activeWidget = null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function loadFreshWidgetScript(url) {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
try { delete window.CDEKWidget } catch (_) { window.CDEKWidget = undefined }
|
|
37
43
|
const s = document.createElement("script")
|
|
38
44
|
s.src = url
|
|
39
45
|
s.async = true
|
|
40
46
|
s.onload = () => resolve()
|
|
41
|
-
s.onerror = () =>
|
|
47
|
+
s.onerror = () => reject(new Error("Не удалось загрузить скрипт виджета СДЭК"))
|
|
42
48
|
document.head.appendChild(s)
|
|
43
49
|
})
|
|
44
|
-
return _scriptPromise
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
function setFieldValue(id, value) {
|
|
@@ -86,6 +91,7 @@ export default class extends Controller {
|
|
|
86
91
|
fieldName: { type: String, default: "order_cdek_point_name" },
|
|
87
92
|
fieldAddress: { type: String, default: "order_cdek_point_address" },
|
|
88
93
|
fieldCityCode: { type: String, default: "order_cdek_city_code" },
|
|
94
|
+
fieldCoors: { type: String, default: "order_cdek_point_coors" },
|
|
89
95
|
labelSelector: { type: String, default: "[data-cdek-widget-label]" },
|
|
90
96
|
addressSelector: { type: String, default: "#order_cdek_point_address_view" }
|
|
91
97
|
}
|
|
@@ -101,13 +107,8 @@ export default class extends Controller {
|
|
|
101
107
|
window.clearTimeout(this._mountTimer)
|
|
102
108
|
this._mountTimer = null
|
|
103
109
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (typeof this._widget.destroy === "function") this._widget.destroy()
|
|
107
|
-
else if (typeof this._widget.close === "function") this._widget.close()
|
|
108
|
-
} catch (_) { /* no-op */ }
|
|
109
|
-
this._widget = null
|
|
110
|
-
}
|
|
110
|
+
destroyWidget(this._widget)
|
|
111
|
+
this._widget = null
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
_mountWhenReady() {
|
|
@@ -118,8 +119,8 @@ export default class extends Controller {
|
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
this._mounting = true
|
|
121
|
-
|
|
122
|
-
.then(() => this._mountWidget())
|
|
122
|
+
loadFreshWidgetScript(this.scriptUrlValue)
|
|
123
|
+
.then(() => { if (this._connected) this._mountWidget() })
|
|
123
124
|
.catch((err) => this._showError(err && err.message ? err.message : "ошибка"))
|
|
124
125
|
.finally(() => { this._mounting = false })
|
|
125
126
|
}
|
|
@@ -193,8 +194,13 @@ export default class extends Controller {
|
|
|
193
194
|
widgetOptions.goods = goods
|
|
194
195
|
}
|
|
195
196
|
|
|
197
|
+
// Гасим любой предыдущий инстанс ДО создания нового — иначе два виджета
|
|
198
|
+
// дерутся за глобальный стор (старый город перезапрашивается, карта прыгает).
|
|
199
|
+
destroyWidget(_activeWidget)
|
|
200
|
+
|
|
196
201
|
try {
|
|
197
202
|
this._widget = new window.CDEKWidget(widgetOptions)
|
|
203
|
+
_activeWidget = this._widget
|
|
198
204
|
} catch (err) {
|
|
199
205
|
this._showError(err && err.message ? err.message : "ошибка инициализации виджета")
|
|
200
206
|
}
|
|
@@ -207,10 +213,16 @@ export default class extends Controller {
|
|
|
207
213
|
const address = office.address || office.address_full || ""
|
|
208
214
|
const cityCode = office.city_code || ""
|
|
209
215
|
|
|
216
|
+
const loc = Array.isArray(office.location) ? office.location : []
|
|
217
|
+
const lon = Number(loc[0])
|
|
218
|
+
const lat = Number(loc[1])
|
|
219
|
+
const coors = (Number.isFinite(lon) && Number.isFinite(lat)) ? `${lon} ${lat}` : ""
|
|
220
|
+
|
|
210
221
|
setFieldValue(this.fieldCodeValue, code)
|
|
211
222
|
setFieldValue(this.fieldNameValue, name)
|
|
212
223
|
setFieldValue(this.fieldAddressValue, address)
|
|
213
224
|
setFieldValue(this.fieldCityCodeValue, cityCode)
|
|
225
|
+
setFieldValue(this.fieldCoorsValue, coors)
|
|
214
226
|
|
|
215
227
|
const label = name ? (code ? `${name} (${code})` : name) : "не выбран"
|
|
216
228
|
setText(this.labelSelectorValue, label)
|