github.com/letsencrypt/boulder@v0.20251208.0/sfe/forms/fields.go (about)

     1  package forms
     2  
     3  import (
     4  	"fmt"
     5  	"html/template"
     6  	"strings"
     7  )
     8  
     9  type Field interface {
    10  	// RenderForm returns the HTML representation of the field.
    11  	RenderField() template.HTML
    12  }
    13  
    14  type InputField struct {
    15  	// displayName is the name displayed in the form UI.
    16  	displayName string
    17  
    18  	// name is the name of the field when submitted in the form. It is required
    19  	// and must be unique within the form.
    20  	name string
    21  
    22  	// description is a short description displayed below the field. It is
    23  	// required.
    24  	description string
    25  
    26  	// required indicates whether the field is required.
    27  	required bool
    28  }
    29  
    30  var _ Field = (*InputField)(nil)
    31  
    32  func NewInputField(displayName, name, description string, required bool) *InputField {
    33  	return &InputField{
    34  		displayName: displayName,
    35  		name:        name,
    36  		description: description,
    37  		required:    required,
    38  	}
    39  }
    40  
    41  func (field InputField) RenderField() template.HTML {
    42  	var reqAttr string
    43  	if field.required {
    44  		reqAttr = `required="required"`
    45  	}
    46  	fieldHTML := fmt.Sprintf(`
    47  <div class="form-field">
    48  	<label for="%[1]s">%[2]s</label>
    49  	<small class="field-description">%[3]s</small><br>
    50  	<input type="text" id="%[1]s" name="%[1]s" %[4]s>
    51  	<div class="error-message"></div>
    52  </div>`, field.name, field.displayName, field.description, reqAttr)
    53  	return template.HTML(fieldHTML) //nolint:gosec // G203: html produced by html/template; no raw user HTML is injected.
    54  }
    55  
    56  type DropdownField struct {
    57  	// displayName is the name displayed in the form UI.
    58  	displayName string
    59  
    60  	// name is the name of the field when submitted in the form. It is required
    61  	// and must be unique within the form.
    62  	name string
    63  
    64  	// description is a short description displayed below the field. It is
    65  	// required.
    66  	description string
    67  
    68  	// options is the list of options available in the dropdown.
    69  	options []string
    70  
    71  	// required indicates whether the field is required.
    72  	required bool
    73  }
    74  
    75  var _ Field = (*DropdownField)(nil)
    76  
    77  func NewDropdownField(displayName, name, description string, options []string, required bool) Field {
    78  	return &DropdownField{
    79  		displayName: displayName,
    80  		name:        name,
    81  		description: description,
    82  		options:     options,
    83  		required:    required,
    84  	}
    85  }
    86  
    87  func (field DropdownField) RenderField() template.HTML {
    88  	var reqAttr string
    89  	if field.required {
    90  		reqAttr = `required="required"`
    91  	}
    92  	var b strings.Builder
    93  	b.WriteString(fmt.Sprintf(`
    94  <div class="form-field">
    95  	<label for="%[1]s">%[2]s</label>
    96  	<small class="field-description">%[3]s</small><br>
    97  	<select id="%[1]s" name="%[1]s" %[4]s>
    98  		<option value="" selected></option>`, field.name, field.displayName, field.description, reqAttr))
    99  	for _, o := range field.options {
   100  		b.WriteString(fmt.Sprintf(`<option value="%[1]s">%[1]s</option>`, o))
   101  	}
   102  	b.WriteString(`</select>
   103  	<div class="error-message"></div>
   104  </div>`)
   105  	return template.HTML(b.String()) //nolint:gosec // G203: html produced by html/template; no raw user HTML is injected.
   106  }
   107  
   108  type TextareaField struct {
   109  	// displayName is the name displayed in the form UI.
   110  	displayName string
   111  
   112  	// name is the name of the field when submitted in the form. It is required
   113  	// and must be unique within the form.
   114  	name string
   115  
   116  	// description is a short description displayed below the field. It is
   117  	// required.
   118  	description string
   119  
   120  	// rows is the number of lines to show in the textarea. Optional and
   121  	// defaults to 4.
   122  	rows int
   123  
   124  	// required indicates whether the field is required.
   125  	required bool
   126  }
   127  
   128  var _ Field = (*TextareaField)(nil)
   129  
   130  func NewTextareaField(displayName, name, description string, rows int, required bool) *TextareaField {
   131  	return &TextareaField{
   132  		displayName: displayName,
   133  		name:        name,
   134  		description: description,
   135  		rows:        rows,
   136  		required:    required,
   137  	}
   138  }
   139  
   140  func (field TextareaField) RenderField() template.HTML {
   141  	numRows := field.rows
   142  	if numRows <= 0 {
   143  		numRows = 4
   144  	}
   145  	var reqAttr string
   146  	if field.required {
   147  		reqAttr = `required="required"`
   148  	}
   149  	fieldHTML := fmt.Sprintf(`
   150  <div class="form-field">
   151  	<label for="%[1]s">%[2]s</label>
   152  	<small class="field-description">%[3]s</small><br>
   153  	<textarea id="%[1]s" name="%[1]s" rows="%[4]d" %[5]s></textarea>
   154  	<div class="error-message"></div>
   155  </div>`, field.name, field.displayName, field.description, numRows, reqAttr)
   156  	return template.HTML(fieldHTML) //nolint:gosec // G203: html produced by html/template; no raw user HTML is injected.
   157  }
   158  
   159  type CheckboxField struct {
   160  	// displayName is the name displayed in the form UI.
   161  	displayName string
   162  
   163  	// name is the name of the field when submitted in the form. It is required
   164  	// and must be unique within the form.
   165  	name string
   166  
   167  	// text is the text displayed to the right of the checkbox. It is required.
   168  	text string
   169  
   170  	// required indicates whether the checkbox must be checked.
   171  	required bool
   172  }
   173  
   174  var _ Field = (*CheckboxField)(nil)
   175  
   176  func NewCheckboxField(displayName, name, text string, required bool) *CheckboxField {
   177  	return &CheckboxField{
   178  		displayName: displayName,
   179  		name:        name,
   180  		text:        text,
   181  		required:    required,
   182  	}
   183  }
   184  
   185  func (field CheckboxField) RenderField() template.HTML {
   186  	var reqAttr string
   187  	if field.required {
   188  		reqAttr = `required="required"`
   189  	}
   190  	fieldHTML := fmt.Sprintf(` 
   191  <div class="highlight form-field checkbox-field" id="%[1]s-wrapper">
   192  	<label for="%[1]s">%[2]s</label>
   193  	<div class="checkbox-row">
   194  		<input type="checkbox" id="%[1]s" name="%[1]s" %[4]s>
   195  		<span class="checkbox-text">%[3]s</span>
   196  	</div>
   197  	<div class="error-message"></div>
   198  </div>`, field.name, field.displayName, field.text, reqAttr)
   199  	return template.HTML(fieldHTML) //nolint:gosec // G203: html produced by html/template; no raw user HTML is injected.
   200  }