Привет, разработчик!

Для того чтобы верстать быстрее и легче поддерживать проект мы сделали jade-миксин для элементов форм. На вид это большая колбаса кода:

mixin form_element(config)
	//- default values
	- config.class_array = config.class_array || {}
	- config.class_array.block_class_mod = config.class_array.block_class_mod || ''
	- config.class_array.class_mod = config.class_array.class_mod || ''
	- config.class_array.elem_class = config.class_array.elem_class || ''
	- config.add_class = config.add_class || ''
	- config.placeholder = config.placeholder || ''
	if !config.id
		- config.id = config.title.replace(/\s/g, '_').replace(/[.,:;(){}/?!@#$%&*]/g, '')
	else
		- config.id = config.id.replace(/\s/g, '_').replace(/[.,:;(){}/?!@#$%&*]/g, '')
	if config.type === 'text' || config.type === 'password' || config.type === 'email' || config.type === 'textarea' || config.type === 'select' || config.type === 'file'
		dl.form_cell(class=config.class_array.block_class_mod)
			dt.form_c_hline(class=config.class_array.class_mod)
				label(for=config.id) #{config.title}
			dd.form_c_f_w(class=config.class_array.class_mod)
				if config.type === 'text' || config.type === 'password' || config.type === 'email'
					if config.value
						input.f_c_field(value=config.value type=config.type id=config.id class='#{config.class_array.elem_class} #{config.add_class}' placeholder=config.placeholder)
						block
					else
						input.f_c_field(type=config.type id=config.id class='#{config.class_array.elem_class} #{config.add_class}' placeholder=config.placeholder)
						block
				if config.type === 'textarea'
					textarea.f_c_field(type=config.type id=config.id class='#{config.class_array.elem_class} #{config.add_class}' placeholder=config.placeholder) #{config.value}
					block
				if config.type === 'file'
					input.f_c_field(type=config.type id=config.id class='#{config.class_array.elem_class} #{config.add_class}' placeholder=config.placeholder)
					.f_c_field_file_field
						span.f_c_field_file_text #{config.title}
						span.f_c_field_file_butt Choose File
				if config.type === 'select'
					select.f_c_field(id=config.id class='#{config.class_array.elem_class} #{config.add_class}' data-placeholder=config.placeholder)
						each option in config.options
							option(value=option)= option
					block
	if config.type === 'checkbox' || config.type === 'radio'
		label.lbl_rb_ch_block(class=config.class_array.block_class_mod)
			if config.checked
				input.lbl_inp_rb_ch(name=config.name type=config.type class='#{config.class_array.elem_class} #{config.add_class}' checked='checked')
			else
				input.lbl_inp_rb_ch(name=config.name type=config.type class='#{config.class_array.elem_class} #{config.add_class}')
			span.lbl_rb_ch_text(class=config.class_mod) #{config.title}

Однако на самом деле это очень простой в использовании миксин. С помощью него мы можем делать следующие виды элементов форм:

  • input(type=”text”)
  • input(type=”password”)
  • input(type=”email”)
  • input(type=”checkbox”)
  • input(type=”radio”)
  • select
  • textarea

Один из примеров вызова:

+form_element({
    type:'text',
    class_array:default_field,
    title:'some title',
    id:'some'
})

Давайте сначала посмотрим как работает миксин.

Обратите внимание, что миксин имееет один параметр - config. Это объект, который будет содержать наши опции. В начале мы объявляем значения по умолчанию. Эти значения будут в дальнейшем использованы в миксине. Если значение не заданно - мы заменяем его на пустую строку:

//- default values
- config.class_array = config.class_array || {}
- config.class_array.block_class_mod = config.class_array.block_class_mod || ''
- config.class_array.class_mod = config.class_array.class_mod || ''
- config.class_array.elem_class = config.class_array.elem_class || ''
- config.add_class = config.add_class || ''
- config.placeholder = config.placeholder || ''

Далее редактируем идентификатор нашего поля. Если он не задан - будет равен параметру title.

if !config.id
		- config.id = config.title.replace(/\s/g, '_').replace(/[.,:;(){}/?!@#$%&*]/g, '')
	else
		- config.id = config.id.replace(/\s/g, '_').replace(/[.,:;(){}/?!@#$%&*]/g, '')

Суть данной операции - привести id поля в валидный вид. Давайте рассмотрим эти трансформации на примере(было➞стало):

'some text of id''some_text_of_id'
'#some-?text of id?''some-text_of_id'

Далее миксин разделяется на 2 основные части в зависимости от вида поля. Если это input(type=”text”),input(type=”password”),input(type=”email”),select,textarea мы будем использовать структуру dl,dt,dd:

<dl>
    <dt>
        <label for="some">Title of form element</label>
    </dt>
    <dd>
        <input type="text" id="some">
    </dd>
</dl>

Мы используем эту структуру, потому что она наиболее семантична. Более подробно она описана в статье на xiper.net Для добавления классов-модификаторов в миксине есть параметр class_array(массив классов). Вот как добавляется класс в миксине:

dt.form_c_hline(class=config.class_array.class_mod)

А вот пример вызова вместе с определением массива классов.

- var default_field = {block_class_mod:'form_cell_v1_mod',class_mod:'form_v1_mod', elem_class:'default_mod'}

+form_element({
    type:'text',
    class_array:default_field,
    title:'some title',
    id:'#some'
})

Это нужно для того, чтобы создать несколько видов полей и потом смело их переиспользовать. Например у вас на сайте 3 вида полей(например input(type=”text”)). Вы просто создаете 3 таких массива и используете их:

- var default_field = {block_class_mod:'form_cell_v1_mod',class_mod:'form_v1_mod', elem_class:'default_mod'}
- var default_field = {block_class_mod:'form_cell_v2_mod',class_mod:'form_v2_mod', elem_class:'second_mod'}
- var default_field = {block_class_mod:'form_cell_v3_mod',class_mod:'form_v3_mod', elem_class:'third_mod'}

Далее рассмотрим следующий участок кода:

if config.type === 'text' || config.type === 'password' || config.type === 'email'
    if config.value
        input.f_c_field(value=config.value type=config.type id=config.id class='#{config.class_array.elem_class} #{config.add_class}' placeholder=config.placeholder)
        block
    else
        input.f_c_field(type=config.type id=config.id class='#{config.class_array.elem_class} #{config.add_class}' placeholder=config.placeholder)
        block
if config.type === 'textarea'
    textarea.f_c_field(type=config.type id=config.id class='#{config.class_array.elem_class} #{config.add_class}' placeholder=config.placeholder) #{config.value}
    block

Разделение идет по типу поля, а также по параметру value. Обратите внимание на выражение ‘block’, это позволяет вставлять любые элементы после поля. Пример, ссылку:

+form_element({
	type:'text',
	class_array:default_field,
	title:'some title',
	id:'#some'
})
    a(href="#") some link after input

В результате получаем следующий html:

<dl class="form_cell form_cell_v1_mod">
    <dt class="form_c_hline form_v1_mod">
        <label for="some">some title</label>
    </dt>
    <dd class="form_c_f_w form_v1_mod">
        <input type="text" id="some" placeholder="" class="f_c_field default_mod ">
        <a href="#">some link after input</a>
    </dd>
</dl>

После инпута вставилась ссылка. Для input(type=”file”) используется следующая структура:

if config.type === 'file'
	input.f_c_field(type=config.type id=config.id class='#{config.class_array.elem_class} #{config.add_class}' placeholder=config.placeholder)
	.f_c_field_file_field
		span.f_c_field_file_text #{config.title}
		span.f_c_field_file_butt Choose File

Все просто, может изменяться в зависимости от макета. Для селекта используется следующая структура:

if config.type === 'select'
    select.f_c_field(id=config.id class='#{config.class_array.elem_class} #{config.add_class}' data-placeholder=config.placeholder)
        each option in config.options
            option(value=option)= option
    block

Т.е. для селекта в вызове миксина нужно передать массив опций.Пример вызова:

+form_element({
    type: 'select',
    class_array: default_field,
    title: 'some title',
    id: 'id',
    options: ['Option 1', 'Option 2', 'Option 3']
})

Структура для чекбоксов и радио-кнопок такова

if config.type === 'checkbox' || config.type === 'radio'
    label.lbl_rb_ch_block(class=config.class_array.block_class_mod)
        if config.checked
            input.lbl_inp_rb_ch(name=config.name type=config.type class='#{config.class_array.elem_class} #{config.add_class}' checked='checked')
        else
            input.lbl_inp_rb_ch(name=config.name type=config.type class='#{config.class_array.elem_class} #{config.add_class}')
        span.lbl_rb_ch_text(class=config.class_mod) #{config.title}

Эту структуру наиболее легко стилизовать. Здесь разделение идет по параметру ‘checked’. На этом разбор миксина завершен.

Примеры вызова

input(type=”text”)

jade:

+form_element({
    type:'text',
    class_array:default_field,
    title:'some title',
    id:'#some'
})

html:

<dl class="form_cell form_cell_v1_mod">
  <dt class="form_c_hline form_v1_mod">
    <label for="some">some title</label>
  </dt>
  <dd class="form_c_f_w form_v1_mod">
    <input type="text" id="some" placeholder="" class="f_c_field default_mod ">
  </dd>
</dl>

input(type=”password”)

jade:

+form_element({
	type:'password',
	class_array:default_field,
	title:'some title',
	id:'#some'
})

html:

<dl class="form_cell form_cell_v1_mod">
  <dt class="form_c_hline form_v1_mod">
    <label for="some">some title</label>
  </dt>
  <dd class="form_c_f_w form_v1_mod">
    <input type="password" id="some" placeholder="" class="f_c_field default_mod ">
  </dd>
</dl>

input(type=”email”)

jade:

+form_element({
	type:'email',
	class_array:default_field,
	title:'some title',
	id:'#some'
})

html:

<dl class="form_cell form_cell_v1_mod">
  <dt class="form_c_hline form_v1_mod">
    <label for="some">some title</label>
  </dt>
  <dd class="form_c_f_w form_v1_mod">
    <input type="email" id="some" placeholder="" class="f_c_field default_mod ">
  </dd>
</dl>

textarea

jade:

+form_element({
	type:'textarea',
	class_array:default_field,
	title:'some title',
	id:'#some'
})

html:

<dl class="form_cell form_cell_v1_mod">
  <dt class="form_c_hline form_v1_mod">
    <label for="some">some title</label>
  </dt>
  <dd class="form_c_f_w form_v1_mod">
    <textarea type="textarea" id="some" placeholder="" class="f_c_field default_mod "></textarea>
  </dd>
</dl>

input(type=”checkbox”)

jade:

+form_element({
	type: 'checkbox',
	class_array: default_field,
	title: 'some title',
	id: 'id',
	add_class: 'someclass',
	name: 'radiobtn',
	checked: true
})

html:

<label class="lbl_rb_ch_block form_cell_v1_mod">
  <input name="radiobtn" type="checkbox" checked="checked" class="lbl_inp_rb_ch default_mod someclass"><span class="lbl_rb_ch_text">some title</span>
</label>

input(type=”radio”)

jade:

+form_element({
	type: 'radio',
	class_array: default_field,
	title: 'some title',
	id: 'id',
	add_class: 'someclass',
	name:'radiobtn',
	checked:true
})

html:

<label class="lbl_rb_ch_block form_cell_v1_mod">
  <input name="radiobtn" type="radio" checked="checked" class="lbl_inp_rb_ch default_mod someclass"><span class="lbl_rb_ch_text">some title</span>
</label>

select

jade:

+form_element({
	type: 'select',
	class_array: default_field,
	title: 'some title',
	id: 'id',
	add_class: 'someclass',
	options: ['Option 1', 'Option 2', 'Option 3']
})

html:

<dl class="form_cell form_cell_v1_mod">
  <dt class="form_c_hline form_v1_mod">
    <label for="id">some title</label>
  </dt>
  <dd class="form_c_f_w form_v1_mod">
    <select id="id" data-placeholder="" class="f_c_field default_mod someclass">
      <option value="Option 1">Option 1</option>
      <option value="Option 2">Option 2</option>
      <option value="Option 3">Option 3</option>
    </select>
  </dd>
</dl>

Все опции

  • type - тип поля. Возможные значения - ‘text’,’textarea’,’email’,’password’,’checkbox’,’radio’,’select’.Обязательное поле
  • title - название поля. Обычно находится в dt, за исключением checkbox и radio.Обязательное поле
  • id - Идентификатор поля.
  • class_array - массив классов-модификаторов.
  • add_class - дополнительный класс для поля.
  • value - атрибут value для поля.
  • placeholder - атрибут placeholder для поля. Для селектов добавляется в data-placeholder.
  • options - массив опций. Только для селектов.
  • name - имя поля. Только для checkbox и radio.
  • checked - атрибут checked. Только для checkbox и radio.

На этом все.