diff --git a/app/assets/javascripts/admin/addon/components/color-input.js b/app/assets/javascripts/admin/addon/components/color-input.js index c563fedc948..91aeaec6e08 100644 --- a/app/assets/javascripts/admin/addon/components/color-input.js +++ b/app/assets/javascripts/admin/addon/components/color-input.js @@ -22,9 +22,21 @@ export default Component.extend({ return this.onlyHex ? 6 : null; }), + normalize(color) { + if (/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color)) { + if (!color.startsWith("#")) { + color = "#" + color; + } + } + + return color; + }, + @action onHexInput(color) { - this.attrs.onChangeColor && this.attrs.onChangeColor(color || ""); + if (this.attrs.onChangeColor) { + this.attrs.onChangeColor(this.normalize(color || "")); + } }, @observes("hexValue", "brightnessValue", "valid") @@ -32,7 +44,9 @@ export default Component.extend({ const hex = this.hexValue; let text = this.element.querySelector("input.hex-input"); - this.attrs.onChangeColor && this.attrs.onChangeColor(hex); + if (this.attrs.onChangeColor) { + this.attrs.onChangeColor(this.normalize(hex)); + } if (this.valid) { this.styleSelection && diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 6e787d72654..ce7d3b1279f 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -2324,6 +2324,7 @@ en: allow_changing_staged_user_tracking: "Allow a staged user's category and tag notification preferences to be changed by an admin user." errors: + invalid_css_color: "Invalid color. Enter a color name or hex value." invalid_email: "Invalid email address." invalid_username: "There's no user with that username." invalid_group: "There's no group with that name." diff --git a/config/site_settings.yml b/config/site_settings.yml index b01c9fc4268..363aacc249a 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -1064,8 +1064,15 @@ email: email_accent_bg_color: type: color default: "#2F70AC" - email_accent_fg_color: "#FFFFFF" - email_link_color: "#006699" + validator: "CssColorValidator" + email_accent_fg_color: + type: color + default: "#FFFFFF" + validator: "CssColorValidator" + email_link_color: + type: color + default: "#006699" + validator: "CssColorValidator" show_topic_featured_link_in_digest: false email_custom_headers: "Auto-Submitted: auto-generated" email_subject: "[%{site_name}] %{optional_pm}%{optional_cat}%{topic_title}" diff --git a/lib/validators/css_color_validator.rb b/lib/validators/css_color_validator.rb new file mode 100644 index 00000000000..630e9cad57c --- /dev/null +++ b/lib/validators/css_color_validator.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +class CssColorValidator + COLORS = %w{ + aliceblue antiquewhite aqua aquamarine azure beige bisque black + blanchedalmond blue blueviolet brown burlywood cadetblue chartreuse + chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan + darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta + darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen + darkslateblue darkslategray darkslategrey darkturquoise darkviolet + deeppink deepskyblue dimgray dimgrey dodgerblue firebrick floralwhite + forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray green + greenyellow grey honeydew hotpink indianred indigo ivory khaki lavender + lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan + lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon + lightseagreen lightskyblue lightslategray lightslategrey lightsteelblue + lightyellow lime limegreen linen magenta maroon mediumaquamarine + mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue + mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream + mistyrose moccasin navajowhite navy oldlace olive olivedrab orange + orangered orchid palegoldenrod palegreen paleturquoise palevioletred + papayawhip peachpuff peru pink plum powderblue purple red rosybrown + royalblue saddlebrown salmon sandybrown seagreen seashell sienna silver + skyblue slateblue slategray slategrey snow springgreen steelblue tan teal + thistle tomato turquoise violet wheat white whitesmoke yellow yellowgreen + } + + def initialize(opts = {}) + @opts = opts + end + + def valid_value?(val) + !!(val =~ /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/ || COLORS.include?(val&.downcase)) + end + + def error_message + I18n.t("site_settings.errors.invalid_css_color") + end +end diff --git a/spec/components/validators/css_color_validator_spec.rb b/spec/components/validators/css_color_validator_spec.rb new file mode 100644 index 00000000000..db754808b1f --- /dev/null +++ b/spec/components/validators/css_color_validator_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe CssColorValidator do + subject { described_class.new } + + it "validates hex colors" do + expect(subject.valid_value?('#0')).to eq(false) + expect(subject.valid_value?('#00')).to eq(false) + expect(subject.valid_value?('#000')).to eq(true) + expect(subject.valid_value?('#0000')).to eq(false) + expect(subject.valid_value?('#00000')).to eq(false) + expect(subject.valid_value?('#000000')).to eq(true) + end + + it "validates css colors" do + expect(subject.valid_value?('red')).to eq(true) + expect(subject.valid_value?('green')).to eq(true) + expect(subject.valid_value?('blue')).to eq(true) + expect(subject.valid_value?('hello')).to eq(false) + end +end