Вот такая штукенция получилась. Radios Select для Drupal 7.

Аватар пользователя OldWarrior OldWarrior 9 января 2012 в 12:08

История из разряда "Новая жизнь старых вещей". Точнее - новая "шуба" для привычного элемента форм radios. Для тех случаев, когда элемент radios строится из модуля.

Собственно, началось всё с того, что искал способ отобразить в форме модуля некую таблицу символов с возможностью выбора любого одного символа. Символы должны быть достаточно крупные (шрифт где-то 18-20px). Для начала попытался приспособить обычный select, но не понравилось: во-первых, список слишком длинный и выбирать неудобно, а во-вторых, добиться единообразного отображения (размер шрифта, padding, выравнивание и т.д.) в разных браузерах оказалось совсем непросто.

В общем, нужно было искать более компактное решение, при котором таблица была бы именно таблицей. В процессе разных тестов случайно обнаружил, что метки (label) для элемента radios в большинстве браузеров обрабатывают клики как и родительский (связанный с меткой) сам radios-control (кружочек, по которому мы тыкаем мышкой). То есть - по клику на метку элемент устанавливается в состояние checked, как если б мы кликали на сам кружочек. Не бог весть какое открытие, но беглый поиск в гугле аналогичных развитых решений с использованием меток ничего не дал. И я приступил к работе.

После ряда тычков в неверных направлениях было выведено более-менее унифицированное и кроссбраузерное решение (CSS + jQuery). Я его назвал Radios Select. Вот оно, со скромной гордостью и удовлетворением представляю своё детище:

А вот что происходит по клику на элементе:

Код, формирующий вывод:

$values preg_split('/[\s,\.]+/'ucwords('Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sodales congue velit. Duis commodo interdum ipsum.'));

$form['rs_example_1']['radios_select_1'] = array(
  
'#type'          => 'radios',
  
'#title'         => t('Select word:'),
  
'#default_value' => 1,
  
'#options'       => $values,
  
'#radios_select' => TRUE,     // enables Radios Select for this radios element
  
'#description'   => t('Word to use in form.'),
);
?>

Собственно, Radios Select можно использовать не только, как таблицу символов, а для выбора любого значения: строки, числа. Родилась идея сделать модуль-хук, который бы темизировал элементы radios как Radios Select, если у элементов установлен соответствующий параметр, а иначе - выводил бы стандартный radios. В процессе работы над модулем элемент Radios Select "оброс" рядом параметров, позволяющих кастомизировать вывод этого псевдо-элемента (это действительно скорее псевдо-элемент, поскольку по факту строится обычный radios и последующая обработка в submit'е - типичная для radios).

Например, можно изменить свойства шрифта элемента:

$values preg_split('/[\s,\.]+/'ucwords('Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sodales congue velit. Duis commodo interdum ipsum.'));

$form['rs_example_2']['radios_select_2'] = array(
  
'#type'          => 'radios',
  
'#title'         => t('Select word:'),
  
'#default_value' => 2,
  
'#options'       => $values,
  
'#radios_select' => TRUE,     // enables Radios Select for this radios element
  
'#rs_attributes' => array(
    
'label'         => array(
      
'font'         => 'Times New Roman',  // this sets font family (same as in CSS way)
      
'font_size'    => 1.4,              // this sets font size (in "units" units)
      
'font_color'   => '#339933',        // this sets font color (same as in CSS way)
      
'line_height'  => 2,                // this sets line height (in "units" units)
      
'units'        => 'em',             // can be em or px (default: px)
    
),
  ),
  
'#description'   => t('Word to use in form.'),
);
?>

А вот и вариант для искомой таблицы символов:

$values = array();
for (
$i 33$i 256$i++) {
  
$values[] = '&#' $i ';';
}
$values array_combine($values$values);

// Replace Soft Hyphen symbol (­) by non-breaking space
// (this symbol produces row break in Firefox and Opera)
$values['­'] = ' ';

$form['rs_example_3']['radios_select_3'] = array(
  
'#type'          => 'radios',
  
'#title'         => t('Select symbol:'),
  
'#default_value' => '©',
  
'#options'       => $values,
  
'#radios_select' => TRUE,     // enables Radios Select for this radios element
  
'#rs_attributes' => array(
    
'label'          => array(
      
'width'          => 2,      // sets label width (in "units" units)
      
'height'         => 2,      // sets label height (in "units" units)
      
'line_height'    => 2,
      
'padding_x'      => '3px',  // horizontal padding (we use px instead of units)
      
'padding_y'      => '3px',  // vertical padding (we use px instead of units)
      
'units'          => 'em',
    ),
  ),
  
'#description'   => t('Symbol to use in form.'),
);
?>

Можно "подкрасить" оформление элемента (выбирается также светлая или тёмная стрелка):

$values array_merge(range('A''Z'), range('a''z'));

$form['rs_example_4']['radios_select_4_1'] = array(
  
'#type'          => 'radios',
  
'#title'         => t('Select character:'),
  
'#default_value' => 2,
  
'#options'       => $values,
  
'#radios_select' => TRUE,     // enables Radios Select for this radios element
  
'#rs_attributes' => array(
    
'element'        => array(
      
'frame_color'    => '#d4d0c8'// this sets frame color
      
'dark_arrow'     => TRUE,      // this sets dark arrow for this element
     
),
    
'label'          => array(
      
'width'          => 2,
      
'height'         => 2,
      
'padding_x'      => '3px',
      
'padding_y'      => '3px',
      
'units'          => 'em',
     ),
   ),
  
'#description'   => t('Character to use in form.'),
);
?>

Или убрать фон выбранного элемента и объединить с селектором (так называемый hollow-режим):


$values array_merge(range('A''Z'), range('a''z'));

$form['rs_example_4']['radios_select_4_2'] = array(
  
'#type'          => 'radios',
  
'#title'         => t('Select character:'),
  
'#default_value' => 2,
  
'#options'       => $values,
  
'#radios_select' => TRUE,     // enables Radios Select for this radios element
  
'#rs_attributes' => array(
    
'element'         => array(
      
'hollow'          => TRUE,   // this sets hollow mode
     
),
    
'label'         => array(
      
'width'           => 2,
      
'height'          => 2,
      
'padding_x'       => '3px',
      
'padding_y'       => '3px',
      
'units'           => 'em',
     ),
   ),
  
'#description'   => t('Character to use in form.'),
);
?>

А можно и вставить картинки в селектор, причём выровнять по желанию - либо по верху (по умолчанию), либо по низу (как в этом примере):

$module_path url(drupal_get_path('module''radios_select'));
$images_path $module_path '/examples/images/';

$values = array(
  
'$images_path 'image1.png" />Some image 1',
  
'$images_path 'image2.png" />Some image 2',
  
'$images_path 'image3.png" />Some image 3',
  
'$images_path 'image1.png" />Some image 4',
  
'$images_path 'image2.png" />Some image 5',
  
'$images_path 'image3.png" />Some image 6',
);

$form['rs_example_5']['radios_select_5_1'] = array(
  
'#type'          => 'radios',
  
'#title'         => t('Select image:'),
  
'#default_value' => 0,
  
'#options'       => $values,
  
'#radios_select' => TRUE,     // enables Radios Select for this radios element
  
'#rs_attributes' => array(
    
'label'         => array(
      
'valign'        => 'bottom'// this sets vertical alignment of labels to bottom
      
'font_size'     => 12,
      
'line_height'   => 14,
      
'padding_x'     => 4,
      
'padding_y'     => 4,
     ),
   ),
  
'#description'   => t('Select horizontal or vertical image.'),
);
?>

Другой вариант с картинками - выравнивание "в ряд" с текстом метки (можно также задать произвольный vertical-align для изображения, как обычно в CSS, здесь, в примере - просто смещение от базовой линии):

$module_path url(drupal_get_path('module''radios_select'));
$images_path $module_path '/examples/images/';

$values = array(
  
'$images_path 'ru.png" /> Russian Federation',
  
'$images_path 'us.png" /> USA',
  
'$images_path 'ca.png" /> Canada',
  
'$images_path 'fr.png" /> France',
  
'$images_path 'de.png" /> Germany',
  
'$images_path 'it.png" /> Italy',
  
'$images_path 'gb.png" /> United Kingdom',
  
'$images_path 'gr.png" /> Greece',
  
'$images_path 'tr.png" /> Turkey',
  
'$images_path 'ua.png" /> Ukraine',
  
'$images_path 'no.png" /> Norway',
);

$form['rs_example_5']['radios_select_5_2'] = array(
  
'#type'          => 'radios',
  
'#title'         => t('Select country:'),
  
'#default_value' => 0,
  
'#options'       => $values,
  
'#radios_select' => TRUE,     // enables Radios Select for this radios element
  
'#rs_attributes' => array(
    
'label'         => array(
      
'img_valign'    => '-4px',        // sets vertical alignment of images
      
'nowrap'        => 'TRUE',        // disables word wrapping for text in labels
     
),
   ),
  
'#description'   => t('Country from where you are.'),
);
?>

А можно упорядочить метки в колонки (любое количество колонок):

$module_path url(drupal_get_path('module''radios_select'));
$images_path $module_path '/examples/images/';

$values = array(
  
'$images_path 'ru.png" /> Russian Federation',
  
'$images_path 'us.png" /> USA',
  
'$images_path 'ca.png" /> Canada',
  
'$images_path 'fr.png" /> France',
  
'$images_path 'de.png" /> Germany',
  
'$images_path 'it.png" /> Italy',
  
'$images_path 'gb.png" /> United Kingdom',
  
'$images_path 'gr.png" /> Greece',
  
'$images_path 'tr.png" /> Turkey',
  
'$images_path 'ua.png" /> Ukraine',
  
'$images_path 'no.png" /> Norway',
);

$form['rs_example_6']['radios_select_6'] = array(
  
'#type'          => 'radios',
  
'#title'         => t('Select country:'),
  
'#default_value' => 0,
  
'#options'       => $values,
  
'#radios_select' => TRUE,     // enables Radios Select for this radios element
  
'#rs_attributes' => array(
    
'element'         => array(
      
'columns'         => 4,       // this sets ordering by 4 columns
    
),
    
'label'         => array(
      
'img_valign'      => -4,      // px by default, so we can skip units
      
'nowrap'          => 'TRUE',
     ),
   ),
  
'#description'   => t('Country from where you are.'),
);
?>

Наконец, труъ-программисты могут полностью изменить вид Radios Select с помощью CSS (стили аттачатся "на лету", при создании элемента):

$module_path url(drupal_get_path('module''radios_select'));
$images_path $module_path '/examples/images/';

$values = array(
  
'$images_path 'ru.png" /> Russian Federation',
  
'$images_path 'us.png" /> USA',
  
'$images_path 'ca.png" /> Canada',
  
'$images_path 'fr.png" /> France',
  
'$images_path 'de.png" /> Germany',
  
'$images_path 'it.png" /> Italy',
  
'$images_path 'gb.png" /> United Kingdom',
  
'$images_path 'gr.png" /> Greece',
  
'$images_path 'tr.png" /> Turkey',
  
'$images_path 'ua.png" /> Ukraine',
  
'$images_path 'no.png" /> Norway',
);

$form['rs_example_7']['radios_select_7'] = array(
  
'#type'          => 'radios',
  
'#title'         => t('Select country:'),
  
'#default_value' => 0,
  
'#options'       => $values,
  
'#radios_select' => TRUE,     // enables Radios Select for this radios element
  
'#rs_attributes' => array(
    
'element'         => array(
      
'columns'         => 4,
      
'css'             => array(
        
'div.type-radios-current {background: #222 url("'$images_path 'custom_bg.png") bottom right no-repeat; border-color: #222 !important;}',
        
'div.type-radios-current .inner {background: #a8a8a8;}',
        
'div.type-radios-current label  {background: #ffc136 url("'$images_path 'custom_label_active.png") center center repeat-x !important; border: 1px solid #c35e22 !important; color: black;}',
        
'div.rs_opened {background: #222 url("'$images_path 'custom_bg_active.png") bottom right no-repeat;}',
        
'div.rs_opened .inner {background: none;}',
        
'div.type-radios-select {background: #d0d0d0 url("'$images_path 'custom_select_bg.png") top center repeat-x !important; border-color: #222 !important;}',
        
'div.type-radios-select label.selected {background: #ffc136 url("'$images_path 'custom_label_active.png") center center repeat-x !important; border: 1px solid #c35e22 !important; color: black;}',
        
'div.type-radios-select label {background: #3a3a3a url("'$images_path 'custom_label.png") center center repeat-x !important; border: 1px solid #222 !important; color: white;}',
        
'div.type-radios-select label:hover {background: #ffc136 url("'$images_path 'custom_label_active.png") center center repeat-x !important;}',
      ),
    ),
    
'label'         => array(
      
'img_valign'      => -4,
      
'nowrap'          => 'TRUE',
     ),
   ),
  
'#description'   => t('Country from where you are.'),
);
?>

Все эти примеры (рабочие и с исходным кодом) доступны из help'а модуля Radios Select (см. приложенный архив) по адресу: admin/help/radios_select

Internet Explorer.

В IE, как обычно, всё "не как у людей". Начнём с того, что все "красивые" закругления в нём отсутствуют. Попытки прицепить JS-библиотеки типа PIE, curved-corner и пр. положительного результата не дали - эти надстройки ломают разметку inline-элементов.

Вторая проблема - IE единственный из браузеров, который не захотел "понимать" клики по меткам. Пришлось специально для него сделать эмуляцию клика по радиокнопке при клике на метке.

Ещё одна особенность конкретно IE6 - курсор почему-то не устанавливается в "hand" (pointer) при hover'е над метками, даже если явно указывать для него правило в CSS.

В общем, базовый функционал в IE всё же обеспечен (по крайней мере версии IE6, IE7, IE8 с Radios Select работают нормально). Но выглядит в нем всё чуть менее красиво.

Поведение при noscript.

При выключенном JS происходит следующее:

1. Скрывается контейнер выбранного (текущего) элемента - тот, который со стрелкой справа.

2. Делается видимым контейнер селектора (который содержит все элементы).

3. Становятся видимыми сами радиокнопки (слева от каждого элемента), таким образом пользователь может выбрать нужный пункт традиционным для radios образом - щёлкнув на элементе.

4. Таким образом, форматирование/оформление Radios Select в основном сохраняется, добавляются только input'ы.

Примечание: IE и здесь ведёт себя несколько отлично от других браузеров. При выключенном JS он не "признаёт" клики на вложенных в метку картинках (IMG) как клики на метке. Только если пользователь кликнул на текст метки или непосредственно на круглый элемент-радиокнопку.

Примечание: при выключенном JS input'ам присваивается свойство float: left (с тем, чтобы сохранить разметку и равные ширины при использовании колонок. Как следствие радиокнопка "уходит" с базовой линии контейнера и автоматически начинает позиционироваться от верха. Это в общем-то никак не сказывается на разных способах вывода элемента - за исключением, когда используется выравнивание по нижнему краю (как в примере с картинками выше). В этом случае кнопки будут расположены на разной высоте:

Желающие могут скачать и установить модуль. Модуль очень нуждается в тестировании под разными браузерами. Пока протестировано в GoogleChrome, Safari, Opera 11, Firefox 8, IE 6,7,8.

Если будете использовать/тестировать элемент под другими браузерами - просьба отписываться здесь о результатах (с указанием версии браузера).

Как бы и всё. :-)

Скачать модуль Radios Select

ВложениеРазмер
Иконка пакета radios_select-7.x-beta2.zip47.02 КБ
0 Thanks

Комментарии

Аватар пользователя Darteg Darteg 9 января 2012 в 12:40
"OldWarrior" wrote:

. В планах есть предусмотреть какую-то возможность пользователю хоть как-то выбрать нужный пункт, но пока толкового решения не нашёл.

Может полностью вырубать, если нету graceful degradation?

Аватар пользователя OldWarrior OldWarrior 9 января 2012 в 13:28
"Darteg" wrote:

Может полностью вырубать, если нету graceful degradation?

Я пока рассматриваю вариант, при котором селектор будет открыт в случае отсутствия JS и сами радиокнопки не будут скрыты. Как-то так. То есть - в селекторе всё тоже самое, но только к меткам слева добавятся сами управляющие элементы - "кружочки".

Разумеется при этом установки ширины меток будут относиться только к меткам и не повлияют на ширину связки "элемент-метка". Ничего страшного, в общем-то. Но зато хоть какой-то выбор останется пользователю.

Что-то вроде этого:

<noscript>
  <style type="text/css" media="all">
    import url("rs_without_js.css");
  </style>
</noscript>
Аватар пользователя vitg vitg 9 января 2012 в 20:33

Я бы сказал "вау", иногда от селектов - картинок с текстом приходится отказываться. Хорошая вещь, пригодится.

Аватар пользователя OldWarrior OldWarrior 11 января 2012 в 21:12
  • Добавлена обработка noscript. Теперь пользователь может выбрать кнопку, даже если отключен JS (см. выше, в посте).
  • Добавлено изображение прелоадера (отображается в контейнере текущего элемента до загрузки и начала работы JS).
  • Исправлены несколько неточностей в помощи и примерах.
  • Протестировано теперь и в IE8.

Просьба помочь с тестированием в разных браузерах по-прежнему актуальна. Собственно ничего особо делать не нужно - только включить модуль и зайти на страницу помощи, там убедиться что элементы работают.

Аватар пользователя Ch Ch 13 января 2012 в 18:59

Я бы оформил radios_select.examples.inc как отдельный субмодуль, на подобии того, как это сделано в ситулс. Можно так же как там сделать демонстрационную страницу в админке, с различными radios элементами и т.д.
Для code review стоит добавить файлы LICENSE.txt и README.txt, и проверить код на соответствие Coding standards (лишние пробелы, комментарии и т.д.). Есть специальные инструменты для этого Сoder и Code Sniffer.

Аватар пользователя OldWarrior OldWarrior 14 января 2012 в 4:42
"Ch" wrote:

Я бы оформил radios_select.examples.inc как отдельный субмодуль, на подобии того, как это сделано в ситулс. Можно так же как там сделать демонстрационную страницу в админке, с различными radios элементами и т.д.

Тоже думал над этим. Но пока примеров не так уж много, вроде как особого смысла нет. В планах есть добавление такой фичи, как выбор предопределённых готовых пресетов оформления элементаю (скажем, для таблиц символов или картинок и т.д) - тогда возможно и будет сабмодуль для примеров.

На D.org я, разумеется, выложил "вылизанную" по всем Drupal Code Standards версию:
git clone --branch 7.x-1.x git@git.drupal.org:sandbox/OldWarrior/1399438.git radios_select

"Ch" wrote:

И кстати, может стоит оформить эти элементы как патч для Elements?

Интересная мысль. Надо будет посмотреть модуль.

Аватар пользователя OldWarrior OldWarrior 19 января 2012 в 9:50

Ребята, помогите проверить модуль под IE9 - у кого он установлен.

Думаю, что ничем не будет отличаться от IE8, но всё же... чтобы убедиться.

Аватар пользователя yexel yexel 23 января 2012 в 8:00

Правильно я понял, что эта крутая штукенция - только утилита и используется для других модулей?
А есть ли возможность "прилепить" её к какому-нибудь полю (то, что в 6-м друпале называлось CCK), чтобы выбирать значения из такого вот красивенького списка?

Аватар пользователя OldWarrior OldWarrior 23 января 2012 в 10:00
"yexel" wrote:

Правильно я понял, что эта крутая штукенция - только утилита и используется для других модулей?

Да, правильно.
Это только для случаев, когда элемент строится из модуля.
Возможно, когда-то и добавится поддержка виджета, но пока её нет.

Аватар пользователя yexel yexel 23 января 2012 в 11:29
"OldWarrior" wrote:

Возможно, когда-то и добавится поддержка виджета, но пока её нет.

Жаль... А я посмотрел на эти красивые списки и... размечтался :)