swal_rails 0.3.1.beta1
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 +7 -0
- data/Appraisals +43 -0
- data/CHANGELOG.md +73 -0
- data/LICENSE.txt +21 -0
- data/README.md +973 -0
- data/Rakefile +12 -0
- data/app/assets/javascripts/swal_rails/chain.js +38 -0
- data/app/assets/javascripts/swal_rails/confirm.js +93 -0
- data/app/assets/javascripts/swal_rails/controllers/swal_controller.js +54 -0
- data/app/assets/javascripts/swal_rails/flash.js +24 -0
- data/app/assets/javascripts/swal_rails/index.js +62 -0
- data/app/assets/stylesheets/swal_rails/index.css +5 -0
- data/config/importmap.rb +9 -0
- data/config/locales/swal_rails.en.yml +19 -0
- data/config/locales/swal_rails.fr.yml +19 -0
- data/gemfiles/rails_7_2.gemfile +25 -0
- data/gemfiles/rails_8_0.gemfile +25 -0
- data/gemfiles/rails_8_1.gemfile +25 -0
- data/gemfiles/rails_8_1_sprockets.gemfile +25 -0
- data/lib/generators/swal_rails/install/install_generator.rb +138 -0
- data/lib/generators/swal_rails/install/templates/initializer.rb +33 -0
- data/lib/generators/swal_rails/locales/locales_generator.rb +19 -0
- data/lib/swal_rails/configuration.rb +88 -0
- data/lib/swal_rails/engine.rb +55 -0
- data/lib/swal_rails/helpers.rb +96 -0
- data/lib/swal_rails/version.rb +6 -0
- data/lib/swal_rails.rb +25 -0
- data/vendor/javascript/sweetalert2/LICENSE +22 -0
- data/vendor/javascript/sweetalert2/sweetalert2.all.js +4814 -0
- data/vendor/javascript/sweetalert2/sweetalert2.all.min.js +6 -0
- data/vendor/javascript/sweetalert2/sweetalert2.esm.all.js +4805 -0
- data/vendor/javascript/sweetalert2/sweetalert2.esm.all.min.js +6 -0
- data/vendor/javascript/sweetalert2/sweetalert2.esm.js +4804 -0
- data/vendor/javascript/sweetalert2/sweetalert2.esm.min.js +5 -0
- data/vendor/javascript/sweetalert2/sweetalert2.js +4813 -0
- data/vendor/javascript/sweetalert2/sweetalert2.min.js +5 -0
- data/vendor/stylesheets/sweetalert2/LICENSE +22 -0
- data/vendor/stylesheets/sweetalert2/sweetalert2.css +1233 -0
- data/vendor/stylesheets/sweetalert2/sweetalert2.min.css +1 -0
- data/vendor/stylesheets/sweetalert2/themes/bootstrap-4.css +167 -0
- data/vendor/stylesheets/sweetalert2/themes/bootstrap-5.css +173 -0
- data/vendor/stylesheets/sweetalert2/themes/borderless.css +46 -0
- data/vendor/stylesheets/sweetalert2/themes/bulma.css +94 -0
- data/vendor/stylesheets/sweetalert2/themes/material-ui.css +183 -0
- data/vendor/stylesheets/sweetalert2/themes/minimal.css +40 -0
- metadata +124 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwalRails
|
|
4
|
+
# Holds runtime configuration for the gem.
|
|
5
|
+
#
|
|
6
|
+
# A default is created on first access; override via an initializer:
|
|
7
|
+
#
|
|
8
|
+
# SwalRails.configure do |config|
|
|
9
|
+
# config.confirm_mode = :turbo_override
|
|
10
|
+
# config.flash_map[:notice] = { icon: "success", toast: true }
|
|
11
|
+
# end
|
|
12
|
+
class Configuration
|
|
13
|
+
CONFIRM_MODES = %i[off data_attribute turbo_override both].freeze
|
|
14
|
+
|
|
15
|
+
attr_accessor :default_options,
|
|
16
|
+
:flash_keys_as_meta,
|
|
17
|
+
:respect_reduced_motion,
|
|
18
|
+
:expose_window_swal
|
|
19
|
+
attr_reader :confirm_mode, :flash_map, :i18n_scope
|
|
20
|
+
|
|
21
|
+
def initialize
|
|
22
|
+
@confirm_mode = :data_attribute
|
|
23
|
+
@flash_keys_as_meta = true
|
|
24
|
+
@respect_reduced_motion = true
|
|
25
|
+
@expose_window_swal = true
|
|
26
|
+
@i18n_scope = "swal_rails"
|
|
27
|
+
@default_options = {
|
|
28
|
+
buttonsStyling: true,
|
|
29
|
+
reverseButtons: false,
|
|
30
|
+
focusConfirm: true,
|
|
31
|
+
returnFocus: true
|
|
32
|
+
}
|
|
33
|
+
@flash_map = default_flash_map
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def confirm_mode=(value)
|
|
37
|
+
value = value.to_sym
|
|
38
|
+
raise ArgumentError, "confirm_mode must be one of #{CONFIRM_MODES.inspect}, got #{value.inspect}" unless CONFIRM_MODES.include?(value)
|
|
39
|
+
|
|
40
|
+
@confirm_mode = value
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def i18n_scope=(value)
|
|
44
|
+
@i18n_scope = value.to_s
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Replace the full flash map. Prefer editing individual keys via `flash_map[:key] = ...`.
|
|
48
|
+
def flash_map=(value)
|
|
49
|
+
raise ArgumentError, "flash_map must be a Hash" unless value.is_a?(Hash)
|
|
50
|
+
|
|
51
|
+
@flash_map = value.each_with_object({}) { |(k, v), h| h[k.to_sym] = v }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Snapshot safe for serialization into a meta tag / JSON.
|
|
55
|
+
def to_client_payload
|
|
56
|
+
{
|
|
57
|
+
confirmMode: confirm_mode,
|
|
58
|
+
respectReducedMotion: respect_reduced_motion,
|
|
59
|
+
exposeWindowSwal: expose_window_swal,
|
|
60
|
+
defaultOptions: default_options,
|
|
61
|
+
flashMap: flash_map,
|
|
62
|
+
i18n: i18n_payload
|
|
63
|
+
}
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def default_flash_map
|
|
69
|
+
{
|
|
70
|
+
notice: { icon: "success", toast: true, position: "top-end", timer: 3000, timerProgressBar: true, showConfirmButton: false },
|
|
71
|
+
success: { icon: "success", toast: true, position: "top-end", timer: 3000, timerProgressBar: true, showConfirmButton: false },
|
|
72
|
+
alert: { icon: "error", toast: false, timer: nil },
|
|
73
|
+
error: { icon: "error", toast: false, timer: nil },
|
|
74
|
+
warning: { icon: "warning", toast: true, position: "top-end", timer: 4000, timerProgressBar: true, showConfirmButton: false },
|
|
75
|
+
info: { icon: "info", toast: true, position: "top-end", timer: 3000, timerProgressBar: true, showConfirmButton: false }
|
|
76
|
+
}
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def i18n_payload
|
|
80
|
+
return {} unless defined?(I18n)
|
|
81
|
+
|
|
82
|
+
%i[confirm_button_text cancel_button_text deny_button_text close_button_aria_label].each_with_object({}) do |key, h|
|
|
83
|
+
translation = I18n.t("#{i18n_scope}.#{key}", default: nil)
|
|
84
|
+
h[key] = translation if translation
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/engine"
|
|
4
|
+
|
|
5
|
+
module SwalRails
|
|
6
|
+
class Engine < ::Rails::Engine
|
|
7
|
+
isolate_namespace SwalRails
|
|
8
|
+
|
|
9
|
+
config.swal_rails = SwalRails.configuration
|
|
10
|
+
|
|
11
|
+
initializer "swal_rails.assets" do |app|
|
|
12
|
+
if app.config.respond_to?(:assets)
|
|
13
|
+
app.config.assets.paths << root.join("vendor/javascript/sweetalert2").to_s
|
|
14
|
+
app.config.assets.paths << root.join("vendor/stylesheets/sweetalert2").to_s
|
|
15
|
+
app.config.assets.paths << root.join("app/assets/javascripts").to_s
|
|
16
|
+
app.config.assets.paths << root.join("app/assets/stylesheets").to_s
|
|
17
|
+
app.config.assets.precompile += %w[
|
|
18
|
+
sweetalert2.js sweetalert2.min.js
|
|
19
|
+
sweetalert2.all.js sweetalert2.all.min.js
|
|
20
|
+
sweetalert2.esm.js sweetalert2.esm.min.js
|
|
21
|
+
sweetalert2.esm.all.js sweetalert2.esm.all.min.js
|
|
22
|
+
sweetalert2.css sweetalert2.min.css
|
|
23
|
+
themes/bootstrap-4.css themes/bootstrap-5.css
|
|
24
|
+
themes/borderless.css themes/bulma.css
|
|
25
|
+
themes/material-ui.css themes/minimal.css
|
|
26
|
+
swal_rails/index.js swal_rails/confirm.js swal_rails/flash.js swal_rails/chain.js
|
|
27
|
+
swal_rails/controllers/swal_controller.js
|
|
28
|
+
]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
initializer "swal_rails.importmap", before: "importmap" do |app|
|
|
33
|
+
next unless app.config.respond_to?(:importmap)
|
|
34
|
+
|
|
35
|
+
app.config.importmap.paths << root.join("config/importmap.rb")
|
|
36
|
+
app.config.importmap.cache_sweepers << root.join("app/assets/javascripts")
|
|
37
|
+
app.config.importmap.cache_sweepers << root.join("vendor/javascript")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
initializer "swal_rails.helpers" do
|
|
41
|
+
ActiveSupport.on_load(:action_controller_base) do
|
|
42
|
+
helper SwalRails::Helpers
|
|
43
|
+
end
|
|
44
|
+
ActiveSupport.on_load(:action_view) do
|
|
45
|
+
include SwalRails::Helpers
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
initializer "swal_rails.i18n" do
|
|
50
|
+
config.i18n.load_path += Dir[root.join("config/locales/*.yml").to_s]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
require "swal_rails/helpers"
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwalRails
|
|
4
|
+
# View helpers exposed to ActionView and ActionController.
|
|
5
|
+
#
|
|
6
|
+
# Place `swal_rails_meta_tags` in your layout `<head>` to emit:
|
|
7
|
+
# - the global client config (once per request)
|
|
8
|
+
# - the per-request flash payload
|
|
9
|
+
module Helpers
|
|
10
|
+
# Emits the two meta tags the JS runtime reads on boot.
|
|
11
|
+
def swal_rails_meta_tags
|
|
12
|
+
safe_join([swal_config_meta_tag, swal_flash_meta_tag].compact, "\n")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def swal_config_meta_tag
|
|
16
|
+
payload = SwalRails.configuration.to_client_payload
|
|
17
|
+
tag.meta(name: "swal-config", content: payload.to_json)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def swal_flash_meta_tag
|
|
21
|
+
return unless SwalRails.configuration.flash_keys_as_meta
|
|
22
|
+
return if flash.blank?
|
|
23
|
+
|
|
24
|
+
payload = build_flash_payload
|
|
25
|
+
return if payload.empty?
|
|
26
|
+
|
|
27
|
+
tag.meta(name: "swal-flash", content: payload.to_json)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Rails idiom: `flash[:notice] = model.errors.full_messages` — expand arrays
|
|
31
|
+
# into one entry per message so each fires its own Swal.
|
|
32
|
+
#
|
|
33
|
+
# Also accepts per-request option overrides:
|
|
34
|
+
# flash[:notice] = "Saved" # string shortcut
|
|
35
|
+
# flash[:notice] = { text: "Saved", icon: "star", timer: 5000 } # full SA2 options
|
|
36
|
+
def build_flash_payload
|
|
37
|
+
flash.to_h.flat_map do |key, message|
|
|
38
|
+
flash_messages(message).filter_map do |m|
|
|
39
|
+
next if m.blank?
|
|
40
|
+
|
|
41
|
+
options = m.is_a?(Hash) ? m.symbolize_keys : { text: m.to_s }
|
|
42
|
+
{ key: key.to_s, options: options }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Arrays expand into one entry per element. A Hash is a single entry —
|
|
48
|
+
# don't let `Array(hash)` destructure it into key/value pairs.
|
|
49
|
+
def flash_messages(message)
|
|
50
|
+
message.is_a?(Array) ? message : [message]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Generates an inline `<script>` that fires a single Swal.
|
|
54
|
+
#
|
|
55
|
+
# Usage: `<%= swal_tag(title: "Hi", icon: "info") %>`
|
|
56
|
+
# Under a strict CSP: `<%= swal_tag({ title: "Hi" }, nonce: true) %>`
|
|
57
|
+
#
|
|
58
|
+
# When `nonce: true` is passed and ActionView's CSP helper is available,
|
|
59
|
+
# Rails substitutes the per-request nonce so the tag survives a
|
|
60
|
+
# `script-src 'self' 'nonce-…'` policy.
|
|
61
|
+
def swal_tag(options = {}, html_options = {})
|
|
62
|
+
# json_escape neutralizes `</script>`, `<!--`, U+2028 and U+2029 —
|
|
63
|
+
# the four sequences that can break out of a <script> block.
|
|
64
|
+
payload = ERB::Util.json_escape(options.to_json)
|
|
65
|
+
tag_options = { type: "module" }.merge(html_options)
|
|
66
|
+
tag_options.delete(:nonce) if tag_options[:nonce] == true && !respond_to?(:content_security_policy_nonce, true)
|
|
67
|
+
javascript_tag(<<~JS.strip, **tag_options)
|
|
68
|
+
import Swal from "sweetalert2";
|
|
69
|
+
Swal.fire(#{payload});
|
|
70
|
+
JS
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Fires a multi-step confirm chain inline on page load.
|
|
74
|
+
#
|
|
75
|
+
# Usage: `<%= swal_chain_tag([{ title: "Sure?" }, { title: "Really?" }]) %>`
|
|
76
|
+
# Under a strict CSP: `<%= swal_chain_tag(steps, nonce: true) %>`
|
|
77
|
+
#
|
|
78
|
+
# Same XSS hardening and CSP nonce handling as `swal_tag`. Each step is
|
|
79
|
+
# a full SweetAlert2 options Hash; `onConfirmed:` / `onDenied:` keys
|
|
80
|
+
# declare nested sub-chains for conditional branching.
|
|
81
|
+
def swal_chain_tag(steps, html_options = {})
|
|
82
|
+
# Array(hash) destructures a Hash into [[k, v], ...] pairs — wrap
|
|
83
|
+
# single Hash steps manually so shorthand `swal_chain_tag(title: "Hi")`
|
|
84
|
+
# produces `[{"title":"Hi"}]`, not `[["title","Hi"]]`.
|
|
85
|
+
steps = [steps] unless steps.is_a?(Array)
|
|
86
|
+
payload = ERB::Util.json_escape(steps.to_json)
|
|
87
|
+
tag_options = { type: "module" }.merge(html_options)
|
|
88
|
+
tag_options.delete(:nonce) if tag_options[:nonce] == true && !respond_to?(:content_security_policy_nonce, true)
|
|
89
|
+
javascript_tag(<<~JS.strip, **tag_options)
|
|
90
|
+
import Swal from "sweetalert2";
|
|
91
|
+
import { chainDialogs } from "swal_rails/chain";
|
|
92
|
+
chainDialogs(Swal, #{payload});
|
|
93
|
+
JS
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
data/lib/swal_rails.rb
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "swal_rails/version"
|
|
4
|
+
|
|
5
|
+
module SwalRails
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
def configuration
|
|
10
|
+
@configuration ||= Configuration.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def configure
|
|
14
|
+
yield configuration
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def reset_configuration!
|
|
18
|
+
@configuration = Configuration.new
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
require_relative "swal_rails/configuration"
|
|
24
|
+
require_relative "swal_rails/helpers"
|
|
25
|
+
require_relative "swal_rails/engine" if defined?(Rails::Engine)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014 Tristan Edwards & Limon Monte
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|