rails_modal_manager 1.0.45 → 1.0.46

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: 35bbae9104923aaa6bc1fa87eacd8616c2ef0aaf538ed1210fb369c3f25e89e2
4
- data.tar.gz: 34ba022c5adac89ff47c3f505215acef624056da6f48afaec02bc42e611e587e
3
+ metadata.gz: 7dec9a40ef3da3620d41315569b51f9b0a3ac6a291bdd81edf77ca6271858464
4
+ data.tar.gz: 719e56407709affe6b21f781ad92cc5496f3ed1c13de711b6f4cbc3769915910
5
5
  SHA512:
6
- metadata.gz: f94273a89dcd52dba439b464196f7c3db208a28405c01f582227e81bb3c709f236074d6a5bca7c6dcdbf53dcf822357d47da9ae643aa23463f25a5d000b55d35
7
- data.tar.gz: 2c8f6ffd4bfced2dcf0ae66a5f8b0f39b63d58fa490f5bbdc7e114f3cbd88810d6c73c054a435e5a3a041d5e3adc7ff67f4e323305f45ed3bb367b2e9748a278
6
+ metadata.gz: 41af209ea06bad87c813444fe5a4e7ba074d685709d9f1dbf916e5dfbd983120d2445de1436bec01ee7b9d3b675084887824010e7ffce4704df4b0c4d74b3757
7
+ data.tar.gz: 14ed339f8138e4e4586f4b13d4fd078e570752bd92f2e7367d2d8c3b128dde332c12f755e7343be703e8810bf5f5f73abe623fbb25ccc740452befa6fc3bca65
@@ -297,7 +297,12 @@ export default class extends Controller {
297
297
  const modal = this.element.closest('.rmm-modal')
298
298
  if (!modal) return
299
299
 
300
- // Abort all pending AJAX requests from all submenu controllers
300
+ // Invalidate any pending AJAX responses + abort network requests
301
+ const contentContainer = modal.querySelector('.rmm-tab-content')
302
+ if (contentContainer) {
303
+ // Increment shared counter to invalidate all pending responses
304
+ contentContainer.dataset.rmmRequestId = (parseInt(contentContainer.dataset.rmmRequestId || '0', 10) + 1)
305
+ }
301
306
  modal.querySelectorAll('[data-controller*="rmm-submenu"]').forEach(el => {
302
307
  const ctrl = this.application.getControllerForElementAndIdentifier(el, 'rmm-submenu')
303
308
  if (ctrl && ctrl.currentAbortController) {
@@ -53,6 +53,19 @@ export default class extends Controller {
53
53
  }
54
54
  }
55
55
 
56
+ /**
57
+ * Increment the shared request counter on the content container.
58
+ * Called synchronously from selectItem/forceReloadActive BEFORE async loadAjaxContent.
59
+ * This ensures any pending async response is immediately invalidated.
60
+ */
61
+ _incrementRequestId() {
62
+ const modal = this.element.closest('.rmm-modal')
63
+ if (!modal) return
64
+ const container = modal.querySelector('.rmm-tab-content')
65
+ if (!container) return
66
+ container.dataset.rmmRequestId = (parseInt(container.dataset.rmmRequestId || '0', 10) + 1)
67
+ }
68
+
56
69
  selectItem(e) {
57
70
  const item = e.currentTarget
58
71
  const itemId = item.dataset.itemId
@@ -74,6 +87,8 @@ export default class extends Controller {
74
87
 
75
88
  // Handle content switching based on load mode
76
89
  if (this.loadModeValue === 'ajax') {
90
+ // Synchronously invalidate any pending requests BEFORE starting new one
91
+ this._incrementRequestId()
77
92
  this.loadAjaxContent(item)
78
93
  } else {
79
94
  this.switchPanel(item)
@@ -98,6 +113,8 @@ export default class extends Controller {
98
113
  const activeItem = this.element.querySelector('.rmm-submenu-item.rmm-active')
99
114
  if (activeItem) {
100
115
  if (this.loadModeValue === 'ajax') {
116
+ // Synchronously invalidate any pending requests
117
+ this._incrementRequestId()
101
118
  this.loadAjaxContent(activeItem)
102
119
  } else {
103
120
  this.switchPanel(activeItem)
@@ -141,8 +158,8 @@ export default class extends Controller {
141
158
 
142
159
  /**
143
160
  * AJAX mode: Load content from URL
144
- * Uses AbortController to cancel previous pending requests and
145
- * validates response against current active item to prevent race conditions.
161
+ * Uses AbortController to cancel pending network requests and
162
+ * a shared request counter (on the DOM) to discard stale responses.
146
163
  */
147
164
  async loadAjaxContent(item) {
148
165
  const url = item.dataset.url
@@ -158,13 +175,14 @@ export default class extends Controller {
158
175
  // Check cache
159
176
  if (this.cacheAjaxValue && this.ajaxCache.has(url)) {
160
177
  contentContainer.innerHTML = this.ajaxCache.get(url)
178
+ contentContainer.classList.remove('rmm-tab-loading')
161
179
  this.dispatch('contentLoaded', {
162
180
  detail: { modalId: this.modalIdValue, itemId: item.dataset.itemId, fromCache: true }
163
181
  })
164
182
  return
165
183
  }
166
184
 
167
- // Abort previous pending request from this controller
185
+ // Abort previous pending request from this controller instance
168
186
  if (this.currentAbortController) {
169
187
  this.currentAbortController.abort()
170
188
  }
@@ -172,10 +190,8 @@ export default class extends Controller {
172
190
  const abortController = new AbortController()
173
191
  this.currentAbortController = abortController
174
192
 
175
- // Global request counter on the shared content container
176
- // This ensures cross-controller coordination (e.g., when switching sidebar groups)
177
- const requestId = (parseInt(contentContainer.dataset.rmmRequestId || '0', 10) + 1)
178
- contentContainer.dataset.rmmRequestId = requestId
193
+ // Read the request ID that was set synchronously by selectItem/forceReloadActive
194
+ const requestId = parseInt(contentContainer.dataset.rmmRequestId || '0', 10)
179
195
 
180
196
  // Show loading state
181
197
  contentContainer.classList.add('rmm-tab-loading')
@@ -196,8 +212,7 @@ export default class extends Controller {
196
212
 
197
213
  const html = await response.text()
198
214
 
199
- // Validate: only update if this is still the latest request
200
- // Uses the shared counter on the DOM element, not instance-level counter
215
+ // Validate: discard if a newer request has been initiated
201
216
  if (parseInt(contentContainer.dataset.rmmRequestId, 10) !== requestId) {
202
217
  return
203
218
  }
@@ -220,6 +235,11 @@ export default class extends Controller {
220
235
  return
221
236
  }
222
237
 
238
+ // Also discard errors from stale requests
239
+ if (parseInt(contentContainer.dataset.rmmRequestId, 10) !== requestId) {
240
+ return
241
+ }
242
+
223
243
  console.error('RMM Submenu: Failed to load content', error)
224
244
  contentContainer.innerHTML = `
225
245
  <div class="rmm-tab-error">
@@ -263,6 +283,7 @@ export default class extends Controller {
263
283
  if (url) {
264
284
  this.ajaxCache.delete(url)
265
285
  }
286
+ this._incrementRequestId()
266
287
  this.loadAjaxContent(activeItem)
267
288
  }
268
289
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsModalManager
4
- VERSION = "1.0.45"
4
+ VERSION = "1.0.46"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_modal_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.45
4
+ version: 1.0.46
5
5
  platform: ruby
6
6
  authors:
7
7
  - reshacs