Организация элементов форм с помощью jade
Привет, разработчик!
Для того чтобы верстать быстрее и легче поддерживать проект мы сделали 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.
На этом все.