rails_modal_manager 1.0.53 → 1.0.55

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: f5ea3c9a0f748719fffb7a377e31eb8ffa82aa92a51fe5e57d0c9e766757f6bd
4
- data.tar.gz: 299fa546552e45abccac98ddd60d258b8b24d8a5ffe3b4e8c8e5647df5b63003
3
+ metadata.gz: e0cf503bb2cd8309b4682f5fa03fbac83853d251624a0e695110dd7ca984b1e5
4
+ data.tar.gz: eb75b69501205a841d2fa1220f2510bea5e96ffb169f19307dedb968efc6edbb
5
5
  SHA512:
6
- metadata.gz: 577924acb8554d70314b4380100d2f6c72ffed2216fb43f78c6197007508e833b35c11f527644cf8ca3e2115cfd06328bb3fa74b7c4eb648336ba3a94587f779
7
- data.tar.gz: f56d2917b83eab179ec1a54e9cf3654e0c81e3e3fe778d0982279d13c18e859dd069f1d7bf73238c0771ddea72d1dbe0b6d189db039bfc0892ad7bfce414b877
6
+ metadata.gz: 9f09c9cfdecc894a959360eb1f4ee4f8a36841b1d19e9e2922803e2d017a4ff810de075ac7a7e8c3ce9fe7d0ff6c8059f84a9252a2c80e0435278eed42f33153
7
+ data.tar.gz: 595f2da63377cde83786907e7c8adb78620ba965ad8cae92e605b072492291bc2ca7ce1f8a2cc3181254eb3c765db1f0457a840588fb22591e1ce96f522aba31
@@ -72,12 +72,41 @@ export default class extends Controller {
72
72
  // Subscribe to store changes
73
73
  this.unsubscribe = modalStore.subscribe(() => this.handleStoreChange())
74
74
 
75
+ // v1.0.54+: Bind `data-rmm-onclick` on footer buttons rendered by the ERB partial.
76
+ // Matches the binding path in setModalFooter() so footer buttons declared via the
77
+ // footer_buttons: [{ onclick: "..." }] option work regardless of whether the footer
78
+ // was rendered by the server ERB or replaced dynamically by setModalFooter.
79
+ this._bindFooterOnclicks()
80
+
75
81
  // Check if should be open on connect
76
82
  if (this.openValue) {
77
83
  this.open()
78
84
  }
79
85
  }
80
86
 
87
+ /**
88
+ * Bind data-rmm-onclick attributes on footer buttons as real click listeners.
89
+ * Idempotent: each button bound only once (tracked via _rmmOnclickBound flag).
90
+ * Called on connect; setModalFooter() handles its own buttons when it replaces the footer.
91
+ */
92
+ _bindFooterOnclicks() {
93
+ const footer = this.element.querySelector(".rmm-footer")
94
+ if (!footer) return
95
+ footer.querySelectorAll("[data-rmm-onclick]").forEach((btn) => {
96
+ if (btn._rmmOnclickBound) return
97
+ btn._rmmOnclickBound = true
98
+ const code = btn.getAttribute("data-rmm-onclick")
99
+ btn.addEventListener("click", function() {
100
+ try {
101
+ // `this` inside onclick code refers to the clicked button element
102
+ new Function(code).call(this)
103
+ } catch (e) {
104
+ console.warn("[rmm-footer] onclick handler error:", e)
105
+ }
106
+ })
107
+ })
108
+ }
109
+
81
110
  // Getter for effective modal ID (fallback to element.id if modalIdValue is empty)
82
111
  get effectiveModalId() {
83
112
  return this.modalIdValue || this.element.id
@@ -23,17 +23,24 @@ function renderButtonHtml(btn) {
23
23
  const classes = ["rmm-btn", `rmm-btn-${btn.variant || "secondary"}`]
24
24
  if (btn.loading) classes.push("rmm-btn-loading")
25
25
 
26
- const attrs = [`class="${classes.join(" ")}"`]
26
+ const type = btn.type || "button"
27
+ const attrs = [`type="${escapeHtml(type)}"`, `class="${classes.join(" ")}"`]
28
+ // v1.0.55+: button[form="..."] HTML5 attribute — submit a form that lives outside the button
29
+ if (btn.form) attrs.push(`form="${escapeHtml(btn.form)}"`)
27
30
  if (btn.disabled || btn.loading) attrs.push("disabled")
28
31
  if (btn.action) attrs.push(`data-action="${escapeHtml(btn.action)}"`)
29
- // v1.0.53+: onclick `data-rmm-onclick` 속성에 저장하고 setModalFooter
30
- // 렌더 직후 실제 click listener 로 바인딩. innerHTML 로 박힌 inline `onclick`
31
- // 은 일부 환경(CSP, 특정 브라우저 파싱) 에서 핸들러로 등록되지 않는 경우가 있어
32
- // 이 방식으로 확실히 동작시킴.
32
+ // DEPRECATED in v1.0.55. Kept for backward compatibility prefer type+form or action.
33
33
  if (btn.onclick) attrs.push(`data-rmm-onclick="${escapeHtml(btn.onclick)}"`)
34
+ // v1.0.55+: extra data-* attributes (e.g. data: { rmm_loading_label: "저장 중..." })
35
+ if (btn.data && typeof btn.data === "object") {
36
+ Object.entries(btn.data).forEach(([k, v]) => {
37
+ const key = String(k).replace(/_/g, "-")
38
+ attrs.push(`data-${escapeHtml(key)}="${escapeHtml(v)}"`)
39
+ })
40
+ }
34
41
  if (btn.id) attrs.push(`data-button-id="${escapeHtml(btn.id)}"`)
35
42
 
36
- return `<button type="button" ${attrs.join(" ")}>${escapeHtml(btn.label || "")}</button>`
43
+ return `<button ${attrs.join(" ")}>${escapeHtml(btn.label || "")}</button>`
37
44
  }
38
45
 
39
46
  /**
@@ -1,16 +1,43 @@
1
1
  <%#
2
- Rails Modal Manager - Footer Component
2
+ Rails Modal Manager - Footer Component (v1.0.55+)
3
3
 
4
4
  Locals:
5
5
  modal_id: String - The modal ID
6
6
  message: String - Footer message (optional)
7
- buttons: Array - Footer buttons [{id:, label:, variant:, disabled:, loading:, action:}]
8
- variant: primary, secondary, danger, success, warning
7
+ buttons: Array - Footer buttons [{id:, label:, variant:, type:, form:, action:, disabled:, loading:, data:, onclick:}]
8
+
9
+ Button option fields:
10
+ id: String - Button identifier (rendered as data-button-id)
11
+ label: String - Button text
12
+ variant: String - primary, secondary, success, danger, warning (default: secondary)
13
+ type: String - "button" (default) or "submit"
14
+ With "submit" + form, the browser submits the form natively.
15
+ form: String - id of a form to submit when this button is clicked
16
+ (HTML5 button[form] attribute). Pairs with type: "submit".
17
+ action: String - Stimulus data-action (e.g. "click->my-controller#save")
18
+ disabled: Boolean - Render as disabled
19
+ loading: Boolean - DEPRECATED in 1.0.55. Was rmm-btn-loading class but its CSS
20
+ made the label transparent; prefer label-swap via data-rmm-loading-label.
21
+ data: Hash - Extra data-* attributes (e.g. { rmm_loading_label: "저장 중..." })
22
+ Keys are dasherized: rmm_loading_label → data-rmm-loading-label
23
+ onclick: String - DEPRECATED in 1.0.55. Inline JavaScript code string. Use type+form
24
+ or action: instead. Kept for backward compatibility.
25
+
26
+ Recommended pattern (form submission):
27
+ { id: "save", label: "저장", variant: "primary",
28
+ type: "submit", form: "my-form-id",
29
+ data: { rmm_loading_label: "저장 중..." } }
9
30
  %>
10
31
  <%
11
32
  modal_id ||= ""
12
33
  message ||= nil
13
34
  buttons ||= []
35
+
36
+ # Helper: dasherize hash keys → data-* attribute pairs string
37
+ data_attr_string = ->(data_hash) {
38
+ return "" unless data_hash.is_a?(Hash)
39
+ data_hash.map { |k, v| %(data-#{k.to_s.tr('_', '-')}="#{ERB::Util.html_escape(v)}") }.join(" ")
40
+ }
14
41
  %>
15
42
  <div class="rmm-footer">
16
43
  <div class="rmm-footer-left">
@@ -25,11 +52,15 @@
25
52
  btn_classes = ["rmm-btn"]
26
53
  btn_classes << "rmm-btn-#{btn[:variant] || 'secondary'}"
27
54
  btn_classes << "rmm-btn-loading" if btn[:loading]
55
+ btn_type = btn[:type].presence || "button"
28
56
  %>
29
- <button type="button"
57
+ <button type="<%= btn_type %>"
30
58
  class="<%= btn_classes.join(' ') %>"
59
+ <% if btn[:form].present? %>form="<%= btn[:form] %>"<% end %>
31
60
  <% if btn[:disabled] || btn[:loading] %>disabled<% end %>
32
61
  <% if btn[:action] %>data-action="<%= btn[:action] %>"<% end %>
62
+ <% if btn[:onclick] %>data-rmm-onclick="<%= btn[:onclick] %>"<% end %>
63
+ <%= data_attr_string.call(btn[:data]).html_safe if btn[:data] %>
33
64
  data-button-id="<%= btn[:id] %>">
34
65
  <%= btn[:label] %>
35
66
  </button>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsModalManager
4
- VERSION = "1.0.53"
4
+ VERSION = "1.0.55"
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.53
4
+ version: 1.0.55
5
5
  platform: ruby
6
6
  authors:
7
7
  - reshacs