diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb index ec8c5de8d..b354091af 100644 --- a/app/models/custom_field.rb +++ b/app/models/custom_field.rb @@ -101,7 +101,8 @@ class CustomField < ApplicationRecord 'version_status', 'extensions_allowed', 'full_width_layout', - 'thousands_delimiter' + 'thousands_delimiter', + 'value_mask' ) def copy_from(arg, options={}) diff --git a/app/views/custom_fields/formats/_string.html.erb b/app/views/custom_fields/formats/_string.html.erb index 08aac8eb2..cf22455d3 100644 --- a/app/views/custom_fields/formats/_string.html.erb +++ b/app/views/custom_fields/formats/_string.html.erb @@ -2,3 +2,4 @@

<%= f.check_box :text_formatting, {:label => :setting_text_formatting, :data => {:disables => '#custom_field_url_pattern'}}, 'full', '' %>

<%= f.text_field(:default_value) %>

<%= f.text_field :url_pattern, :size => 50, :label => :label_link_values_to %>

+

<%= f.text_field :value_mask, size: 50, label: 'Value mask' %>

diff --git a/lib/redmine/field_format.rb b/lib/redmine/field_format.rb index e3ebc0398..08e6f5e09 100644 --- a/lib/redmine/field_format.rb +++ b/lib/redmine/field_format.rb @@ -250,7 +250,7 @@ module Redmine casted = cast_value(custom_field, value, customized) if html && custom_field.url_pattern.present? texts_and_urls = Array.wrap(casted).map do |single_value| - text = view.format_object(single_value, html: false).to_s + text = custom_field.value_mask.present? ? value_from_pattern(custom_field, single_value) : view.format_object(single_value, html: false).to_s url = url_from_pattern(custom_field, single_value, customized) [text, url] end @@ -258,6 +258,8 @@ module Redmine view.link_to text, url end sanitize_html links.join(', ') + elsif html && custom_field.value_mask.present? + value_from_pattern(custom_field, single_value) else casted end @@ -267,6 +269,22 @@ module Redmine Redmine::WikiFormatting::HtmlSanitizer.call(html).html_safe end + # Returns a value generated with the custom field Regex pattern + # %m1%, %m2%... => capture groups matches of the custom field regexp if defined + def value_from_pattern(custom_field, value) + val = custom_field.value_mask.to_s.dup + if custom_field.regexp.present? + val.gsub!(%r{%m(\d+)%}) do + m = $1.to_i + if matches ||= value.to_s.match(Regexp.new(custom_field.regexp)) + val = matches[m].to_s + end + end + end + val + end + protected :value_from_pattern + # Returns an URL generated with the custom field URL pattern # and variables substitution: # %value% => the custom field value @@ -396,11 +414,11 @@ module Redmine add 'string' self.searchable_supported = true self.form_partial = 'custom_fields/formats/string' - field_attributes :text_formatting + field_attributes :text_formatting, :value_mask def formatted_value(view, custom_field, value, customized=nil, html=false) if html - if custom_field.url_pattern.present? + if custom_field.url_pattern.present? || custom_field.value_mask.present? super elsif custom_field.text_formatting == 'full' view.textilizable(value, :object => customized)