Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,6 @@ ext/widget_renderer/Makefile
ext/widget_renderer/*.dylib
# Keep the prebuilt Linux .so for Cloud Foundry deployment
!ext/widget_renderer/libwidget_renderer.so

# Certificate files (avoid accidental commits of sensitive keys/certs)
*.pem
53 changes: 32 additions & 21 deletions app/models/form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -358,28 +358,14 @@ def touchpoints_js_string
end

# Always use ERB template rendering for now to avoid Rust compilation issues
controller = ApplicationController.new

# Set up a mock request with default URL options to avoid "undefined method 'host' for nil" errors
# This is necessary because the ERB templates use root_url which requires request context
# Try action_controller first, fall back to action_mailer if not set
default_options = Rails.application.config.action_controller.default_url_options ||
Rails.application.config.action_mailer.default_url_options ||
{}
host = default_options[:host] || 'localhost'
port = default_options[:port] || 3000
protocol = default_options[:protocol] || (port == 443 ? 'https' : 'http')

# Create a mock request
mock_request = ActionDispatch::Request.new(
'rack.url_scheme' => protocol,
'HTTP_HOST' => "#{host}#{":#{port}" if port != 80 && port != 443}",
'SERVER_NAME' => host,
'SERVER_PORT' => port.to_s,
)
controller_with_request = build_controller_with_mock_request
controller_with_request.render_to_string(partial: 'components/widget/fba', formats: :js, locals: { form: self })
end

controller.request = mock_request
controller.render_to_string(partial: 'components/widget/fba', formats: :js, locals: { form: self })
# Renders the widget CSS partial for use with the Rust widget renderer
def render_widget_css
controller_with_request = build_controller_with_mock_request
controller_with_request.render_to_string(partial: 'components/widget/widget', formats: :css, locals: { form: self })
end

# Renders the widget CSS partial for use with the Rust widget renderer
Expand Down Expand Up @@ -1076,6 +1062,31 @@ def self.forms_whose_retention_period_has_passed

private

# Builds an ApplicationController instance with a mock request for rendering partials
# This is necessary because ERB templates use URL helpers which require request context
def build_controller_with_mock_request
controller = ApplicationController.new

# Set up a mock request with default URL options
# Try action_controller first, fall back to action_mailer if not set
default_options = Rails.application.config.action_controller.default_url_options ||
Rails.application.config.action_mailer.default_url_options ||
{}
host = default_options[:host] || 'localhost'
port = default_options[:port] || 3000
protocol = default_options[:protocol] || (port == 443 ? 'https' : 'http')

mock_request = ActionDispatch::Request.new(
'rack.url_scheme' => protocol,
'HTTP_HOST' => "#{host}#{":#{port}" if port != 80 && port != 443}",
'SERVER_NAME' => host,
'SERVER_PORT' => port.to_s,
)

controller.request = mock_request
controller
end

def set_uuid
self.uuid ||= SecureRandom.uuid
self.short_uuid ||= self.uuid[0..7]
Expand Down
2 changes: 0 additions & 2 deletions ext/widget_renderer/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ def ensure_rust

puts "Current directory: #{Dir.pwd}"
puts "Using cargo executable: #{cargo_bin}"
puts "Cleaning previous build artifacts..."
system("#{cargo_bin} clean 2>&1")
puts "Running cargo build --release..."
system("#{cargo_bin} build --release 2>&1") or abort 'Failed to build Rust extension'

Expand Down
32 changes: 26 additions & 6 deletions ext/widget_renderer/src/template_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,18 @@ impl TemplateRenderer {
""
};

let modal_class = if form.kind == "recruitment" {
"fba-usa-modal fba-usa-modal--lg".to_string()
let modal_class = if form.load_css {
if form.kind == "recruitment" {
"fba-usa-modal fba-usa-modal--lg".to_string()
} else {
"fba-usa-modal".to_string()
}
} else {
"fba-usa-modal".to_string()
if form.kind == "recruitment" {
"usa-modal usa-modal--lg".to_string()
} else {
"usa-modal".to_string()
}
};

let turnstile_check = if form.enable_turnstile {
Expand Down Expand Up @@ -859,9 +867,10 @@ function FBAform(d, N) {{
let question_params = self.render_question_params(form);
let html_body = self.render_html_body(form).replace("`", "\\`");
let html_body_no_modal = self.render_html_body_no_modal(form).replace("`", "\\`");
// Escape the CSS for JavaScript string - escape backslashes, quotes, and newlines
// Escape the CSS for JavaScript string - escape backslashes, backticks, quotes, and newlines
let escaped_css = form.css
.replace("\\", "\\\\")
.replace("`", "\\`")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "");
Expand Down Expand Up @@ -945,8 +954,19 @@ window.touchpointForm{uuid}.init(touchpointFormOptions{uuid});
if (fbaModalElement) {{
if (fbaUswds.Modal) fbaUswds.Modal.on(fbaModalElement);
}}
// Ensure the custom button is also initialized if it exists
const customButtonEl = document.getElementById('{element_selector}');
// Ensure the modal button is also initialized if it exists (for 'modal' delivery method)
const fbaButton = document.querySelector('#fba-button');
if (fbaButton) {{
if (fbaUswds.Modal) {{
fbaUswds.Modal.on(fbaButton);
fbaButton.classList.add('fba-initialized');
}} else {{
console.error("Touchpoints Error: fbaUswds.Modal is not defined");
}}
}}
// Ensure the custom button is also initialized if it exists (for 'custom-button-modal' delivery method)
const customButtonSelector = '{element_selector}';
const customButtonEl = (customButtonSelector && customButtonSelector.length > 0) ? document.getElementById(customButtonSelector) : null;
if (customButtonEl && ('{delivery_method}' === 'custom-button-modal')) {{
if (fbaUswds.Modal) {{
fbaUswds.Modal.on(customButtonEl);
Expand Down
3 changes: 2 additions & 1 deletion spec/features/admin/forms_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -450,10 +450,11 @@
find('.survey-title-input').set('Updated Form Title')
find('.survey-title-input').native.send_key :tab
expect(page).to have_content('form title saved')
# Wait for AJAX save to complete before refreshing
wait_for_ajax
# and persists after refresh
visit questions_admin_form_path(form)
wait_for_builder
wait_for_builder
expect(find('.survey-title-input').value).to eq('Updated Form Title')
end

Expand Down
Loading