lsa_tdx_feedback 1.0.1 → 1.0.3
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 +26 -2
- data/Gemfile.lock +59 -57
- data/README.md +167 -0
- data/app/assets/javascripts/lsa_tdx_feedback.js +105 -21
- data/app/assets/stylesheets/lsa_tdx_feedback.css +1 -1
- data/lib/lsa_tdx_feedback/version.rb +1 -1
- 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: 2688de4eb43f66ca59ebecee11a93685a13b03b6f28dd49138748503b8266828
|
|
4
|
+
data.tar.gz: 780e62b78b1a4fca899e8a90dcbf9956189fef71c4008fe5d5b84eec807716a0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b2934aef5a781f0454893c482f0bdea846c2cf6fed171d5677c0ce55dee93581221eff9c12b6345f5be8f61bc92493b87bb3a7e33a57244eca1eb9065d5f13de
|
|
7
|
+
data.tar.gz: ad7a6d864c9bee29a5cb311eebf4ad040bd57cd5db2505344fc16f9f4e7ef11344509cd42f6043e2bee3a746698d4d44630f4765d9c9355f841239639f83b5c5
|
data/CHANGELOG.md
CHANGED
|
@@ -7,9 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Added
|
|
11
|
+
- **Documentation**: Added Rails 8 authentication setup instructions to README
|
|
12
|
+
- Step-by-step guide for generating Rails 8.1.1's built-in authentication system
|
|
13
|
+
- Instructions for creating `current_user` helper method to match Devise pattern
|
|
14
|
+
- Examples for protecting actions and excluding authentication for specific controllers
|
|
15
|
+
- Documentation on using `allow_unauthenticated_access` for public pages
|
|
16
|
+
|
|
17
|
+
## [1.0.3] - 2025-12-08
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **Turbo Drive Compatibility**: Fixed feedback button not working after Turbo navigation
|
|
21
|
+
- Added proper event listener cleanup to prevent duplicate handlers
|
|
22
|
+
- Added support for `turbo:load` and `turbo:frame-load` events
|
|
23
|
+
- Re-initializes feedback functionality on each Turbo navigation
|
|
24
|
+
- Prevents memory leaks by properly removing old event listeners before attaching new ones
|
|
25
|
+
- Maintains backward compatibility with traditional page loads
|
|
26
|
+
|
|
27
|
+
## [1.0.2] - 2025-01-27
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- **Accessibility Improvement**: Updated button background color for better accessibility in lsa-tdx-feedback-trigger-btn
|
|
31
|
+
|
|
32
|
+
## [1.0.1] - 2025-09-23
|
|
33
|
+
|
|
10
34
|
### Fixed
|
|
11
35
|
- **TDX API Integration Issues**: Resolved HTTP 422 errors when creating tickets
|
|
12
|
-
- Fixed invalid Classification value
|
|
36
|
+
- Fixed invalid Classification value
|
|
13
37
|
- Updated configuration validation to handle both string and integer values for `default_classification`
|
|
14
38
|
- Simplified ticket payload structure to include only essential fields
|
|
15
39
|
- Fixed string interpolation in `build_description` method
|
|
@@ -24,7 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
24
48
|
- ResponsibleGroupID, AccountID
|
|
25
49
|
- Improved error handling and debugging capabilities
|
|
26
50
|
|
|
27
|
-
## [
|
|
51
|
+
## [1.0.0] - 2025-09-23
|
|
28
52
|
|
|
29
53
|
### Added
|
|
30
54
|
- Initial release of FeedbackGem
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
lsa_tdx_feedback (1.0.
|
|
4
|
+
lsa_tdx_feedback (1.0.2)
|
|
5
5
|
httparty (~> 0.22)
|
|
6
6
|
rails (>= 6.0)
|
|
7
7
|
redis (>= 4.0)
|
|
@@ -9,29 +9,29 @@ PATH
|
|
|
9
9
|
GEM
|
|
10
10
|
remote: https://rubygems.org/
|
|
11
11
|
specs:
|
|
12
|
-
actioncable (8.0.
|
|
13
|
-
actionpack (= 8.0.
|
|
14
|
-
activesupport (= 8.0.
|
|
12
|
+
actioncable (8.0.3)
|
|
13
|
+
actionpack (= 8.0.3)
|
|
14
|
+
activesupport (= 8.0.3)
|
|
15
15
|
nio4r (~> 2.0)
|
|
16
16
|
websocket-driver (>= 0.6.1)
|
|
17
17
|
zeitwerk (~> 2.6)
|
|
18
|
-
actionmailbox (8.0.
|
|
19
|
-
actionpack (= 8.0.
|
|
20
|
-
activejob (= 8.0.
|
|
21
|
-
activerecord (= 8.0.
|
|
22
|
-
activestorage (= 8.0.
|
|
23
|
-
activesupport (= 8.0.
|
|
18
|
+
actionmailbox (8.0.3)
|
|
19
|
+
actionpack (= 8.0.3)
|
|
20
|
+
activejob (= 8.0.3)
|
|
21
|
+
activerecord (= 8.0.3)
|
|
22
|
+
activestorage (= 8.0.3)
|
|
23
|
+
activesupport (= 8.0.3)
|
|
24
24
|
mail (>= 2.8.0)
|
|
25
|
-
actionmailer (8.0.
|
|
26
|
-
actionpack (= 8.0.
|
|
27
|
-
actionview (= 8.0.
|
|
28
|
-
activejob (= 8.0.
|
|
29
|
-
activesupport (= 8.0.
|
|
25
|
+
actionmailer (8.0.3)
|
|
26
|
+
actionpack (= 8.0.3)
|
|
27
|
+
actionview (= 8.0.3)
|
|
28
|
+
activejob (= 8.0.3)
|
|
29
|
+
activesupport (= 8.0.3)
|
|
30
30
|
mail (>= 2.8.0)
|
|
31
31
|
rails-dom-testing (~> 2.2)
|
|
32
|
-
actionpack (8.0.
|
|
33
|
-
actionview (= 8.0.
|
|
34
|
-
activesupport (= 8.0.
|
|
32
|
+
actionpack (8.0.3)
|
|
33
|
+
actionview (= 8.0.3)
|
|
34
|
+
activesupport (= 8.0.3)
|
|
35
35
|
nokogiri (>= 1.8.5)
|
|
36
36
|
rack (>= 2.2.4)
|
|
37
37
|
rack-session (>= 1.0.1)
|
|
@@ -39,35 +39,35 @@ GEM
|
|
|
39
39
|
rails-dom-testing (~> 2.2)
|
|
40
40
|
rails-html-sanitizer (~> 1.6)
|
|
41
41
|
useragent (~> 0.16)
|
|
42
|
-
actiontext (8.0.
|
|
43
|
-
actionpack (= 8.0.
|
|
44
|
-
activerecord (= 8.0.
|
|
45
|
-
activestorage (= 8.0.
|
|
46
|
-
activesupport (= 8.0.
|
|
42
|
+
actiontext (8.0.3)
|
|
43
|
+
actionpack (= 8.0.3)
|
|
44
|
+
activerecord (= 8.0.3)
|
|
45
|
+
activestorage (= 8.0.3)
|
|
46
|
+
activesupport (= 8.0.3)
|
|
47
47
|
globalid (>= 0.6.0)
|
|
48
48
|
nokogiri (>= 1.8.5)
|
|
49
|
-
actionview (8.0.
|
|
50
|
-
activesupport (= 8.0.
|
|
49
|
+
actionview (8.0.3)
|
|
50
|
+
activesupport (= 8.0.3)
|
|
51
51
|
builder (~> 3.1)
|
|
52
52
|
erubi (~> 1.11)
|
|
53
53
|
rails-dom-testing (~> 2.2)
|
|
54
54
|
rails-html-sanitizer (~> 1.6)
|
|
55
|
-
activejob (8.0.
|
|
56
|
-
activesupport (= 8.0.
|
|
55
|
+
activejob (8.0.3)
|
|
56
|
+
activesupport (= 8.0.3)
|
|
57
57
|
globalid (>= 0.3.6)
|
|
58
|
-
activemodel (8.0.
|
|
59
|
-
activesupport (= 8.0.
|
|
60
|
-
activerecord (8.0.
|
|
61
|
-
activemodel (= 8.0.
|
|
62
|
-
activesupport (= 8.0.
|
|
58
|
+
activemodel (8.0.3)
|
|
59
|
+
activesupport (= 8.0.3)
|
|
60
|
+
activerecord (8.0.3)
|
|
61
|
+
activemodel (= 8.0.3)
|
|
62
|
+
activesupport (= 8.0.3)
|
|
63
63
|
timeout (>= 0.4.0)
|
|
64
|
-
activestorage (8.0.
|
|
65
|
-
actionpack (= 8.0.
|
|
66
|
-
activejob (= 8.0.
|
|
67
|
-
activerecord (= 8.0.
|
|
68
|
-
activesupport (= 8.0.
|
|
64
|
+
activestorage (8.0.3)
|
|
65
|
+
actionpack (= 8.0.3)
|
|
66
|
+
activejob (= 8.0.3)
|
|
67
|
+
activerecord (= 8.0.3)
|
|
68
|
+
activesupport (= 8.0.3)
|
|
69
69
|
marcel (~> 1.0)
|
|
70
|
-
activesupport (8.0.
|
|
70
|
+
activesupport (8.0.3)
|
|
71
71
|
base64
|
|
72
72
|
benchmark (>= 0.3)
|
|
73
73
|
bigdecimal
|
|
@@ -104,7 +104,7 @@ GEM
|
|
|
104
104
|
factory_bot_rails (6.5.1)
|
|
105
105
|
factory_bot (~> 6.5)
|
|
106
106
|
railties (>= 6.1.0)
|
|
107
|
-
globalid (1.
|
|
107
|
+
globalid (1.3.0)
|
|
108
108
|
activesupport (>= 6.1)
|
|
109
109
|
hashdiff (1.2.1)
|
|
110
110
|
httparty (0.23.1)
|
|
@@ -174,7 +174,7 @@ GEM
|
|
|
174
174
|
stringio
|
|
175
175
|
public_suffix (6.0.2)
|
|
176
176
|
racc (1.8.1)
|
|
177
|
-
rack (3.2.
|
|
177
|
+
rack (3.2.3)
|
|
178
178
|
rack-session (2.1.1)
|
|
179
179
|
base64 (>= 0.1.0)
|
|
180
180
|
rack (>= 3.0.0)
|
|
@@ -182,20 +182,20 @@ GEM
|
|
|
182
182
|
rack (>= 1.3)
|
|
183
183
|
rackup (2.2.1)
|
|
184
184
|
rack (>= 3)
|
|
185
|
-
rails (8.0.
|
|
186
|
-
actioncable (= 8.0.
|
|
187
|
-
actionmailbox (= 8.0.
|
|
188
|
-
actionmailer (= 8.0.
|
|
189
|
-
actionpack (= 8.0.
|
|
190
|
-
actiontext (= 8.0.
|
|
191
|
-
actionview (= 8.0.
|
|
192
|
-
activejob (= 8.0.
|
|
193
|
-
activemodel (= 8.0.
|
|
194
|
-
activerecord (= 8.0.
|
|
195
|
-
activestorage (= 8.0.
|
|
196
|
-
activesupport (= 8.0.
|
|
185
|
+
rails (8.0.3)
|
|
186
|
+
actioncable (= 8.0.3)
|
|
187
|
+
actionmailbox (= 8.0.3)
|
|
188
|
+
actionmailer (= 8.0.3)
|
|
189
|
+
actionpack (= 8.0.3)
|
|
190
|
+
actiontext (= 8.0.3)
|
|
191
|
+
actionview (= 8.0.3)
|
|
192
|
+
activejob (= 8.0.3)
|
|
193
|
+
activemodel (= 8.0.3)
|
|
194
|
+
activerecord (= 8.0.3)
|
|
195
|
+
activestorage (= 8.0.3)
|
|
196
|
+
activesupport (= 8.0.3)
|
|
197
197
|
bundler (>= 1.15.0)
|
|
198
|
-
railties (= 8.0.
|
|
198
|
+
railties (= 8.0.3)
|
|
199
199
|
rails-dom-testing (2.3.0)
|
|
200
200
|
activesupport (>= 5.0.0)
|
|
201
201
|
minitest
|
|
@@ -203,13 +203,14 @@ GEM
|
|
|
203
203
|
rails-html-sanitizer (1.6.2)
|
|
204
204
|
loofah (~> 2.21)
|
|
205
205
|
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
|
206
|
-
railties (8.0.
|
|
207
|
-
actionpack (= 8.0.
|
|
208
|
-
activesupport (= 8.0.
|
|
206
|
+
railties (8.0.3)
|
|
207
|
+
actionpack (= 8.0.3)
|
|
208
|
+
activesupport (= 8.0.3)
|
|
209
209
|
irb (~> 1.13)
|
|
210
210
|
rackup (>= 1.0.0)
|
|
211
211
|
rake (>= 12.2)
|
|
212
212
|
thor (~> 1.0, >= 1.2.2)
|
|
213
|
+
tsort (>= 0.2)
|
|
213
214
|
zeitwerk (~> 2.6)
|
|
214
215
|
rainbow (3.1.1)
|
|
215
216
|
rake (13.3.0)
|
|
@@ -218,7 +219,7 @@ GEM
|
|
|
218
219
|
psych (>= 4.0.0)
|
|
219
220
|
redis (5.4.1)
|
|
220
221
|
redis-client (>= 0.22.0)
|
|
221
|
-
redis-client (0.
|
|
222
|
+
redis-client (0.26.0)
|
|
222
223
|
connection_pool
|
|
223
224
|
regexp_parser (2.11.3)
|
|
224
225
|
reline (0.6.2)
|
|
@@ -283,6 +284,7 @@ GEM
|
|
|
283
284
|
stringio (3.1.7)
|
|
284
285
|
thor (1.4.0)
|
|
285
286
|
timeout (0.4.3)
|
|
287
|
+
tsort (0.2.0)
|
|
286
288
|
tzinfo (2.0.6)
|
|
287
289
|
concurrent-ruby (~> 1.0)
|
|
288
290
|
unicode-display_width (3.2.0)
|
data/README.md
CHANGED
|
@@ -238,6 +238,173 @@ class ApplicationController < ActionController::Base
|
|
|
238
238
|
end
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
+
## Rails 8 Authentication Setup
|
|
242
|
+
|
|
243
|
+
If you're using Rails 8.1.1's built-in authentication system, here's how to set it up and create a `current_user` helper method similar to Devise.
|
|
244
|
+
|
|
245
|
+
### Step 1: Generate the Authentication System
|
|
246
|
+
|
|
247
|
+
Run the Rails generator:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
bin/rails generate authentication
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
This creates:
|
|
254
|
+
|
|
255
|
+
- User model
|
|
256
|
+
- Session model
|
|
257
|
+
- Current class (for per-request attributes)
|
|
258
|
+
- Controllers (SessionsController, PasswordsController)
|
|
259
|
+
- Views for login/password reset
|
|
260
|
+
- Migrations
|
|
261
|
+
|
|
262
|
+
### Step 2: Run Migrations
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
bin/rails db:migrate
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Step 3: Add current_user initializer for Rails 8 internal controllers
|
|
269
|
+
Creating an initializer to make current_user available to all controllers, including Rails internals:
|
|
270
|
+
|
|
271
|
+
```ruby
|
|
272
|
+
# config/initializers/current_user.rb
|
|
273
|
+
# Make current_user available to all controllers, including Rails internal controllers
|
|
274
|
+
# This is needed for gems like lsa_tdx_feedback that call current_user on all controllers
|
|
275
|
+
ActionController::Base.class_eval do
|
|
276
|
+
helper_method :current_user
|
|
277
|
+
|
|
278
|
+
private
|
|
279
|
+
|
|
280
|
+
def current_user
|
|
281
|
+
# Use Current.user if available (set by ApplicationController)
|
|
282
|
+
return Current.user if Current.user
|
|
283
|
+
|
|
284
|
+
# For controllers that don't inherit from ApplicationController,
|
|
285
|
+
# try to find the session manually
|
|
286
|
+
return nil unless respond_to?(:cookies, true)
|
|
287
|
+
|
|
288
|
+
begin
|
|
289
|
+
session_id = cookies.signed[:session_id] if cookies.signed
|
|
290
|
+
return nil unless session_id
|
|
291
|
+
|
|
292
|
+
session = Session.find_by(id: session_id)
|
|
293
|
+
session&.user
|
|
294
|
+
rescue => e
|
|
295
|
+
# If anything goes wrong (e.g., database not available), return nil
|
|
296
|
+
Rails.logger.debug("Error in current_user: #{e.message}") if defined?(Rails.logger)
|
|
297
|
+
nil
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
This makes `current_user` available in all controllers and views, including Rails internals like ActionController::Base.
|
|
304
|
+
|
|
305
|
+
### Step 3A: Create an initializer (config/initializers/lsa_tdx_feedback.rb) that skips authentication for the feedback controller, since feedback forms should be public
|
|
306
|
+
|
|
307
|
+
```ruby
|
|
308
|
+
# Configure lsa_tdx_feedback gem to allow unauthenticated access
|
|
309
|
+
# Feedback forms should be accessible without authentication
|
|
310
|
+
Rails.application.config.to_prepare do
|
|
311
|
+
if defined?(LsaTdxFeedback::FeedbackController)
|
|
312
|
+
LsaTdxFeedback::FeedbackController.class_eval do
|
|
313
|
+
# Skip authentication for feedback submissions
|
|
314
|
+
# Use raise: false to prevent errors if the before_action doesn't exist
|
|
315
|
+
skip_before_action :require_authentication, raise: false
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
rescue => e
|
|
319
|
+
Rails.logger.warn("Could not configure LsaTdxFeedback: #{e.message}") if defined?(Rails.logger)
|
|
320
|
+
end
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
and update request_authentication in the Authentication concern ( app/controllers/concerns/authentication.rb ) to use main_app.new_session_path so it works when called from engine controllers.
|
|
324
|
+
|
|
325
|
+
```ruby
|
|
326
|
+
# Update request_authentication in the Authentication concern to use main_app.new_session_path so it works when called from engine controllers.
|
|
327
|
+
...
|
|
328
|
+
redirect_to main_app.new_session_path # around line 34 in the Authentication concern
|
|
329
|
+
...
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
### Step 4: Protect Actions (Optional)
|
|
334
|
+
|
|
335
|
+
To require authentication for specific actions:
|
|
336
|
+
|
|
337
|
+
```ruby
|
|
338
|
+
class SomeController < ApplicationController
|
|
339
|
+
before_action :require_authentication
|
|
340
|
+
|
|
341
|
+
private
|
|
342
|
+
|
|
343
|
+
def require_authentication
|
|
344
|
+
redirect_to new_session_path unless current_user
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Excluding Authentication for Specific Controllers
|
|
350
|
+
|
|
351
|
+
If you need to exclude authentication for specific controllers or actions (e.g., a public home page), use the `allow_unauthenticated_access` method provided by the Authentication concern:
|
|
352
|
+
|
|
353
|
+
```ruby
|
|
354
|
+
class HomeController < ApplicationController
|
|
355
|
+
allow_unauthenticated_access only: [:index]
|
|
356
|
+
|
|
357
|
+
def index
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
This skips authentication only for the `index` action. The Authentication concern uses `skip_before_action :require_authentication` under the hood.
|
|
363
|
+
|
|
364
|
+
**Alternative options:**
|
|
365
|
+
|
|
366
|
+
If you want to skip authentication for all actions in the HomeController:
|
|
367
|
+
|
|
368
|
+
```ruby
|
|
369
|
+
class HomeController < ApplicationController
|
|
370
|
+
allow_unauthenticated_access
|
|
371
|
+
|
|
372
|
+
def index
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Or if you want to skip for multiple specific actions:
|
|
378
|
+
|
|
379
|
+
```ruby
|
|
380
|
+
class HomeController < ApplicationController
|
|
381
|
+
allow_unauthenticated_access only: [:index, :show]
|
|
382
|
+
|
|
383
|
+
def index
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
The `only:` option limits it to specific actions, while omitting it skips authentication for all actions in that controller.
|
|
389
|
+
|
|
390
|
+
### How It Works
|
|
391
|
+
|
|
392
|
+
- `Current` is an `ActiveSupport::CurrentAttributes` class that stores per-request attributes
|
|
393
|
+
- After login, `Current.user` is set to the authenticated user
|
|
394
|
+
- `current_user` wraps `Current.user` for Devise-like usage
|
|
395
|
+
- Works with authorization libraries like Pundit that expect `current_user`
|
|
396
|
+
|
|
397
|
+
### Routes
|
|
398
|
+
|
|
399
|
+
The generator adds routes like:
|
|
400
|
+
|
|
401
|
+
- `new_session_path` - login page
|
|
402
|
+
- `session_path` - create/destroy session
|
|
403
|
+
- `new_password_path` - password reset request
|
|
404
|
+
- etc.
|
|
405
|
+
|
|
406
|
+
After running the generator, you can use `current_user` in controllers and views just like with Devise.
|
|
407
|
+
|
|
241
408
|
## TDX API Configuration
|
|
242
409
|
|
|
243
410
|
### Required TDX Settings
|
|
@@ -1,21 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LsaTdxFeedback JavaScript - Self-contained feedback modal functionality
|
|
3
|
+
* Turbo Drive compatible
|
|
3
4
|
*/
|
|
4
5
|
(function() {
|
|
5
6
|
'use strict';
|
|
6
7
|
|
|
7
|
-
// Ensure we don't initialize multiple times
|
|
8
|
-
if (window.LsaTdxFeedback && window.LsaTdxFeedback.initialized) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
8
|
var LsaTdxFeedback = {
|
|
13
9
|
initialized: false,
|
|
14
10
|
modal: null,
|
|
15
11
|
form: null,
|
|
12
|
+
handlers: {
|
|
13
|
+
triggerClick: null,
|
|
14
|
+
closeClick: null,
|
|
15
|
+
cancelClick: null,
|
|
16
|
+
backdropClick: null,
|
|
17
|
+
formSubmit: null,
|
|
18
|
+
escapeKey: null
|
|
19
|
+
},
|
|
16
20
|
|
|
17
21
|
init: function() {
|
|
18
|
-
if (
|
|
22
|
+
// Clean up existing listeners if already initialized (for Turbo navigation)
|
|
23
|
+
if (this.initialized) {
|
|
24
|
+
this.cleanup();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Reset state for re-initialization
|
|
28
|
+
this.initialized = false;
|
|
29
|
+
this.modal = null;
|
|
30
|
+
this.form = null;
|
|
19
31
|
|
|
20
32
|
// Wait for DOM to be ready
|
|
21
33
|
if (document.readyState === 'loading') {
|
|
@@ -27,6 +39,52 @@
|
|
|
27
39
|
this.initialized = true;
|
|
28
40
|
},
|
|
29
41
|
|
|
42
|
+
cleanup: function() {
|
|
43
|
+
// Remove all event listeners before re-initializing
|
|
44
|
+
var self = this;
|
|
45
|
+
|
|
46
|
+
if (this.handlers.triggerClick) {
|
|
47
|
+
var triggerBtn = document.getElementById('lsa-tdx-feedback-trigger');
|
|
48
|
+
if (triggerBtn) {
|
|
49
|
+
triggerBtn.removeEventListener('click', this.handlers.triggerClick);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (this.modal) {
|
|
54
|
+
var closeBtn = this.modal.querySelector('.lsa-tdx-feedback-close-btn');
|
|
55
|
+
var cancelBtn = this.modal.querySelector('.lsa-tdx-feedback-cancel-btn');
|
|
56
|
+
var backdrop = this.modal.querySelector('.lsa-tdx-feedback-modal-backdrop');
|
|
57
|
+
|
|
58
|
+
if (closeBtn && this.handlers.closeClick) {
|
|
59
|
+
closeBtn.removeEventListener('click', this.handlers.closeClick);
|
|
60
|
+
}
|
|
61
|
+
if (cancelBtn && this.handlers.cancelClick) {
|
|
62
|
+
cancelBtn.removeEventListener('click', this.handlers.cancelClick);
|
|
63
|
+
}
|
|
64
|
+
if (backdrop && this.handlers.backdropClick) {
|
|
65
|
+
backdrop.removeEventListener('click', this.handlers.backdropClick);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (this.form && this.handlers.formSubmit) {
|
|
70
|
+
this.form.removeEventListener('submit', this.handlers.formSubmit);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (this.handlers.escapeKey) {
|
|
74
|
+
document.removeEventListener('keydown', this.handlers.escapeKey);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Clear handler references
|
|
78
|
+
this.handlers = {
|
|
79
|
+
triggerClick: null,
|
|
80
|
+
closeClick: null,
|
|
81
|
+
cancelClick: null,
|
|
82
|
+
backdropClick: null,
|
|
83
|
+
formSubmit: null,
|
|
84
|
+
escapeKey: null
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
|
|
30
88
|
bindEvents: function() {
|
|
31
89
|
var self = this;
|
|
32
90
|
|
|
@@ -42,10 +100,11 @@
|
|
|
42
100
|
// Trigger button
|
|
43
101
|
var triggerBtn = document.getElementById('lsa-tdx-feedback-trigger');
|
|
44
102
|
if (triggerBtn) {
|
|
45
|
-
|
|
103
|
+
this.handlers.triggerClick = function(e) {
|
|
46
104
|
e.preventDefault();
|
|
47
105
|
self.showModal();
|
|
48
|
-
}
|
|
106
|
+
};
|
|
107
|
+
triggerBtn.addEventListener('click', this.handlers.triggerClick);
|
|
49
108
|
}
|
|
50
109
|
|
|
51
110
|
// Close buttons
|
|
@@ -54,39 +113,44 @@
|
|
|
54
113
|
var backdrop = this.modal.querySelector('.lsa-tdx-feedback-modal-backdrop');
|
|
55
114
|
|
|
56
115
|
if (closeBtn) {
|
|
57
|
-
|
|
116
|
+
this.handlers.closeClick = function(e) {
|
|
58
117
|
e.preventDefault();
|
|
59
118
|
self.hideModal();
|
|
60
|
-
}
|
|
119
|
+
};
|
|
120
|
+
closeBtn.addEventListener('click', this.handlers.closeClick);
|
|
61
121
|
}
|
|
62
122
|
|
|
63
123
|
if (cancelBtn) {
|
|
64
|
-
|
|
124
|
+
this.handlers.cancelClick = function(e) {
|
|
65
125
|
e.preventDefault();
|
|
66
126
|
self.hideModal();
|
|
67
|
-
}
|
|
127
|
+
};
|
|
128
|
+
cancelBtn.addEventListener('click', this.handlers.cancelClick);
|
|
68
129
|
}
|
|
69
130
|
|
|
70
131
|
if (backdrop) {
|
|
71
|
-
|
|
132
|
+
this.handlers.backdropClick = function(e) {
|
|
72
133
|
if (e.target === backdrop) {
|
|
73
134
|
self.hideModal();
|
|
74
135
|
}
|
|
75
|
-
}
|
|
136
|
+
};
|
|
137
|
+
backdrop.addEventListener('click', this.handlers.backdropClick);
|
|
76
138
|
}
|
|
77
139
|
|
|
78
140
|
// Form submission
|
|
79
|
-
this.
|
|
141
|
+
this.handlers.formSubmit = function(e) {
|
|
80
142
|
e.preventDefault();
|
|
81
143
|
self.submitFeedback();
|
|
82
|
-
}
|
|
144
|
+
};
|
|
145
|
+
this.form.addEventListener('submit', this.handlers.formSubmit);
|
|
83
146
|
|
|
84
147
|
// Escape key to close modal
|
|
85
|
-
|
|
86
|
-
if (e.key === 'Escape' && self.modal.style.display !== 'none') {
|
|
148
|
+
this.handlers.escapeKey = function(e) {
|
|
149
|
+
if (e.key === 'Escape' && self.modal && self.modal.style.display !== 'none') {
|
|
87
150
|
self.hideModal();
|
|
88
151
|
}
|
|
89
|
-
}
|
|
152
|
+
};
|
|
153
|
+
document.addEventListener('keydown', this.handlers.escapeKey);
|
|
90
154
|
},
|
|
91
155
|
|
|
92
156
|
showModal: function() {
|
|
@@ -226,6 +290,26 @@
|
|
|
226
290
|
// Export to global scope
|
|
227
291
|
window.LsaTdxFeedback = LsaTdxFeedback;
|
|
228
292
|
|
|
229
|
-
//
|
|
230
|
-
|
|
293
|
+
// Initialize on DOM ready (for traditional page loads)
|
|
294
|
+
if (document.readyState === 'loading') {
|
|
295
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
296
|
+
LsaTdxFeedback.init();
|
|
297
|
+
});
|
|
298
|
+
} else {
|
|
299
|
+
// DOM already loaded
|
|
300
|
+
LsaTdxFeedback.init();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Initialize on Turbo navigation (for Turbo Drive)
|
|
304
|
+
document.addEventListener('turbo:load', function() {
|
|
305
|
+
LsaTdxFeedback.init();
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
// Also handle turbo:frame-load for Turbo Frames (optional)
|
|
309
|
+
document.addEventListener('turbo:frame-load', function(e) {
|
|
310
|
+
// Only re-initialize if the frame contains our elements
|
|
311
|
+
if (e.target.querySelector && e.target.querySelector('#lsa-tdx-feedback-trigger')) {
|
|
312
|
+
LsaTdxFeedback.init();
|
|
313
|
+
}
|
|
314
|
+
});
|
|
231
315
|
})();
|