0 Пользователей и 1 Гость просматривают эту тему.
  • 11 Ответов
  • 23079 Просмотров
*

Professor

  • Захожу иногда
  • 59
  • 10 / 0
[how to] Красота JHTML, или создание элементов формы средствами Joomla! - 2

Я недавно сел разбираться, как же всё таки работает JHTML. И появилась мысль всё, чему научусь сам, задокументировать в виде темы на форуме.
Порыскал по форуму, нашёл похожую тему. Она и становится отправной точкой, а так же в честь неё названа эта тема.

В указанной теме приведён пример выпадающего списка SELECT. Но там всё расписано не подробно, моей же целью является описать максимальные возможности JHTML по созданию элементов форм. По этому не в обиду автору, но чуть позже я повторюсь и приведу здесь пример создания выпадающего списка с более объёмными и подробными комментариями.

Как работает JHTML::_()?

Практически всегда доступ к объектам JHTML осуществляется через загрузочную функцию JHTML::_().
Первый параметр является строкой, указывающей, какому helper-методу необходимо будет передать все последующие параметры. Параметр имеет вид строки, содержащей название префикса класса хелпера, название самого класса хелпера и название вызываемого метода, разделённые точкой. Первые два (префикс и название класса) являются не обязательными, но чаще всего название класса указывается. Таким образом, если строка состоит из двух частей, разделённых точкой, то указано название класса и метода.
Теперь, увидев в коде
Код: php
$p = JHTML::_("select.genericlist", $params, $value, $text, $attribs);
мы понимаем, что JHTML::_() загрузит класс с префиксом JHTML (этот префикс стоит по умолчанию) и названием Select и вызовет метод genericlist, передав ему все остальные параметры ($params, $value, $text, $attribs).
Сам класс JHTML и функция-загрузчик определены в файле JOOMLA/libraries/html/html.php
Вызываемый в нашем примере класс JHTMLSelect и метод genericlist описаны в JOOMLA/libraries/html/html/select.php

Пример создания выпадающего списка (<SELECT>)
Пример взят из приведённой выше темы и немного дополнен.

Код
     // Получаем объект базы данных
     $database =& JFactory::getDBO();
     // Формируем запрос
     $query = "SELECT c.id AS value, c.title AS text FROM #__categories AS c WHERE c.section='com_qcontacts_details'";
     // Выполняем запрос
     $database->setQuery($query);
     // Получаем массив объектов
     $categorylist = $database->loadObjectList();
     // Создаём первый элемент выпадающего списка (<option value="0">Выберите категорию</option>)
     $categories[] = JHTML::_('select.option',  '0', "Выберите категорию", 'value', 'text' );
     // Добавляем массив данных из базы данных
     $categories = array_merge( $categories, $categorylist);
     // Получаем выпадающий список
     $list = JHTML::_(
                         'select.genericlist' /* тип элемента формы */,
                         $categories /* массив, каждый элемент которого содержит value и текст */,
                         'cid' /* id и name select`a формы */,
                         'class="inputbox" size="1"' /* другие атрибуты элемента select */,
                         'value' /* название поля в массиве объектов содержащего ключ */,
                         'text' /* название поля в массиве объектов содержащего значение */,
                         0 /* value элемента, который должен быть выбран (selected) по умолчанию */,
                         'cid' /* id select'a формы */,
                         true /* пропускать ли элементы полей text через JText::_(), default = false */
                      );
Разберём код поподробнее.
Код
     // Формируем запрос
     $query = "SELECT c.id AS value, c.title AS text FROM #__categories AS c WHERE c.section='com_qcontacts_details'";
Здесь стоит обратить внимание на то, что поля id и title из таблицы выбираются с параметром AS. Это означает, что впоследствии эти поля будут доступны по псевдонимам (value и text соотв. в нашем случае. Они будут использоваться в дальнейшем при работе с классом)). Впрочем, выборку можно было делать и без подобных излишеств. Позже укажу как именно.
Код
     // Создаём первый элемент выпадающего списка (<option value="0">Выберите категорию</option>)
     $categories[] = JHTML::_('select.option',  '0', "Выберите категорию", 'value', 'text' );
Здесь я хочу обратить внимание на то, что здесь мы получаем объект. Объект будет иметь поля value и text (их можно определить и по-другому), и содержать значения, соответственно, 0 и "Выберите категорию".
Код
     // Получаем выпадающий список
     $list = JHTML::_(
                         'select.genericlist' /* тип элемента формы */,
                         $categories /* массив, каждый элемент которого содержит value и текст */,
                         'name' /* id и name select`a формы */,
                         'class="inputbox" size="1"' /* другие атрибуты элемента select */,
                         'value' /* название поля в массиве объектов содержащего ключ */,
                         'text' /* название поля в массиве объектов содержащего значение */,
                         0 /* value элемента, который должен быть выбран (selected) по умолчанию */,
                         'cid' /* id select'a формы */,
                         true /* пропускать ли элементы полей text через JText::_(), default = false */
                      );
Ну а здесь мы остановимся поподробнее.
Первый парамерт - см. выше.
Второй параметр ($categories) - это обязательно должен быть массив объектов, либо массив ассоциативных массивов. В случае массива объектов каждый объект должен иметь поля value и text, а в случае массива ассоциативных массивов - каждый из последних должен содержать ключи value и text (только в нашем случае, см. пятый и шестой параметры), которые будут содержать значение value, передаваемое каждому элементу <OPTION> (<OPTION value="..." />), и текст, который будет отображаться в выпадающем списке, соответственно.
Третий параметр ('name') - это, как было сказано, name и id select'a формы. Впрочем, id можно задать отличным от name. См. восьмой параметр.
Четвёртый параметр - ясно.
Пятый и шестой параметры - это соответственно названия полей объектов, содержащих значения для value OPTION'a и отображаемого текста, в случае, если $categories - массив объектов, и названия ключей ассоциативного массива в случае, если $categories - массив ассоциативных массивов.
Седьмой параметр - value элемента, который должен быть выбран (selected) по умолчанию(Может быть задан в виде массива значений или массива объектов, что очень удобно. Но такой подход требуется для multiply select)
Восьмой параметр - это id selecta. Если он не задан, id будет совпадать с name, заданным третьим параметром.
Девятый параметр - это флаг, показывающий, нужно ли пропускать элементы полей (в нашем случае) text  через функцию JText::_(), и имеющий гордое название $translate. Проще говоря, элемент для мультиязычности. По умолчанию в функции равен false.

Ну и живой пример, в нём я намеренно сделаю названия полей отличными от приведённых в примере выше, а так же проделаю другие шалости.
Код
     // Получаем объект базы данных
     $database =& JFactory::getDBO();
     // Формируем запрос
     $query = "SELECT c.id, c.title FROM #__categories AS c WHERE c.section='com_qcontacts_details'";
     // Выполняем запрос
     $database->setQuery($query);
     // Получаем массив ассоциативных массивов, ключи которых соответствуют полям в базе данных, т.е. id и title
     $categorylist = $database->loadAssocList();
     // Создаём первый элемент выпадающего списка (<option value="0">Выберите категорию</option>)
     // Обратите внимание, что мы указываем в параметрах названия полей будущего объекта, id и title.
     // Они должны совпадать с ключами массивов, пришедших из базы данных
     $categories[] = JHTML::_('select.option',  '0', "Выберите категорию", 'id', 'title' );
     // Добавляем массив данных из базы данных
     // Обращаю ваше внимание на то, что мы объединяем массив ассоциативных массивов и массив объектов.
     // Такая конструкция "прокатит"
     $categories = array_merge( $categories, $categorylist);
     // Получаем выпадающий список
     $list = JHTML::_(
                         'select.genericlist' /* генерируем выпадающий список */,
                         /* массив, каждый элемент которого является ассоциативным
                         массивом с ключами id и title ЛИБО объектом с полями id и title  */
                         $categories,
                         'name' /* только name select`a формы */,
                         'class="inputbox" size="1"' /* другие атрибуты элемента select */,
                         'id' /* название поля в массиве объектов содержащего ключ */,
                         'title' /* название поля в массиве объектов содержащего значение */,
                         0 /* value элемента, который должен быть выбран (selected) по умолчанию. */,
                         'cid' /* id select'a формы */,
                         true /* пропускать ли элементы полей text через JText::_(), default = false */
                      );
« Последнее редактирование: 22.11.2010, 22:48:54 от Professor »
*

Professor

  • Захожу иногда
  • 59
  • 10 / 0
Пример создания multiply select (<SELECT>)

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

Код
// Получаем объект базы данных
     $database =& JFactory::getDBO();
     // Формируем запрос
     $query = "SELECT c.id AS value, c.title AS text, c.published AS selected FROM #__categories AS c WHERE c.section='com_qcontacts_details'";
     // Выполняем запрос
     $database->setQuery($query);
     // Получаем массив объектов
     $categorylist = $database->loadObjectList();
     // Формируем массив объектов, которые будут выбраны по умолчанию после формирования списка
     $selected = array ();
     foreach ($categorylist as $key => $value)
     {
        if ((int)$value->selected == 1)
        {
          // Обратите внимание, мы присваиваем элементу массива [u]объект[/u]
          // здесь можно было создать массив значений, а не объектов: $selected[] =& $value->value;
          // но гибкость JHTML позволяет делать по-другому.
          $selected[] =& $value;
        }
     }
     // размер списка
     $size = count ($categorylist);
     // Получаем multiselect список
     $list = JHTML::_(
                         'select.genericlist' /* генерируем multiply select список */,
                         /* массив, каждый элемент которого является ассоциативным
                         массивом с ключами id и title ЛИБО объектом с полями id и title  */
                         $categories,
                         'cid[]' /* id и name select`a формы */,
                         'class="inputbox" size=" . $size . " MULTIPLE' /* другие атрибуты элемента select */,
                         'value' /* название поля в массиве объектов содержащего ключ */,
                         'text' /* название поля в массиве объектов содержащего значение */,
                         /* в нашем случае - массив объектов, указывающих, какие элементы списка будут выбраны по умолчанию
                             Для этого объекты обязательно должны содержать поле, указанное пятым параметром,
                             и иметь те же значения, что и в списке $categories */
                         $selected
                      );

upd: Вспомнил. По 3-му параметру пара замечаний.
В multiselect'е я указал его со скобочками, и в качестве восьмого параметра я не указал id. Метод сам отрежет квадратные скобки и подставит оставшееся значение в поле id
И вообще, это не всё) Я продолжу, и опишу создание radiоbox'ов и т.д. А так же буду дополнять уже написанное, ибо есть чем.
« Последнее редактирование: 22.07.2010, 23:19:55 от Professor »
*

Professor

  • Захожу иногда
  • 59
  • 10 / 0
Ну что ж, продолжим.

Пример создания radiobox'ов (<input type="radio" ... />)

Как и обещал, Radiobox
Тут, вобщем то, ничего тяжёлого нет. Всё делается практически так же, как с genericlist. Снова беру первый пример и немного адаптирую:

Код
    // Получаем объект базы данных
     $database =& JFactory::getDBO();
     // Формируем запрос
     $query = "SELECT c.id AS value, c.title AS text FROM #__categories AS c WHERE c.section='com_qcontacts_details'";
     // Выполняем запрос
     $database->setQuery($query);
     // Получаем массив объектов, поля которых соответствуют полям в базе данных, т.е. value и text
     $categorylist = $database->loadObjectList();
     // Получаем список radiobox'ов
     $list = JHTML::_(
                         'select.radiolist' /* генерируем список radiobox'ов */,
                         /* массив, каждый элемент которого является
                           ИСКЛЮЧИТЕЛЬНО объектом с полями value и text  */
                         $categories,
                         'name' /* name каждого из radio-элементов */,
                         'class="radiobox"' /* другие атрибуты элемента input */,
                         'value' /* название поля в массиве объектов содержащего ключ */,
                         'text' /* название поля в массиве объектов содержащего значение */,
                         0 /* value элемента, который должен быть выбран (selected) по умолчанию. */,
                         'cid' /* т.н. id_text - текст, который подставится в атрибут id тега input
                            и к которому в конце добавится значение поля value, которое, не забываем, для
                            каждого элемента input в списке будет различным */,
                         true /* пропускать ли элементы полей text через JText::_(), default = false */
                      );

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

Кстати, я раньше не обращал на это ваше внимание. Может быть кому то будет интересно. В качестве списка атрибутов тегов (четвёртый параметр) можно передавать не строку, а массив. Это можно делать и в genericlist, и тут. Т.е., обращаясь к примеру из первого поста (там больше атрибутов), можно было передать не
Код
'class="inputbox" size="1"'
а
Код
array ("class" => "inputbox", "size" = 1)
Как вы понимаете, этот метод не подходит для multiselect - нам не удастся передать просто слово MULTISELECT, если мы передаём массив - строка параметров формируется по методу: "ключ элемента массива"="значение элемента массива"

Кстати, есть такая интересная фишка в radiolist: если в у объектов массива будет поле id (по этому я его в примере изменил на value) - то функция подставит в конце каждого radio-input'a значение из этого поля. Но в этом случае в тег будет подставляться два id  - сначала id=id_text+value, а потом, после value (это уже такой атрибут у input'a) - ещё раз id=значение_поля_id. Не знаю, валидно ли это с точки зрения верстки, но явно удобно, что бы присвоить конкретные id для каждого input'a. К слову, эта штука на половину реализована и в genericlist - но предусмотрительно закомментирована, т.к, как вы понимаете, там не имеет смысла.

Немного насчёт selected. Что бы получить отмеченную радио-точку, нужно передать значение, равное полю value в одном из объектов массива. Тогда у соответствующего input'a будет дописано в конце  checked="checked".
Но тут есть ещё такая хитрость - можно передать массив значений, и если будут находиться соответствия с полями value - каждому input'у будет добавляться в конце  selected="selected" (НЕ checked="checked"). Эффекта это не даёт никакого. Практической пользы от этого я не вижу, может быть кто то сможет мне объяснить)

Ну и на последок. Рядом с каждым <input type="radio" ... /> (справа) создаётся тег <label for="...">поле $text объекта</label>, в for подставляется соотв. id input'a.
Генерируются инпуты вместе с служебными знаками - \n\t и \n, а именно, перед каждым инпутом и label'ом ставится \n\t, и ещё в самом конце списка добавляется \n. Если хотите создать удобочитаемый список - заменяйте эти знаки через JString::str_ireplace () на "<br />". Кто не знает - \n - знак переноса строки, \t - знак табуляции.

Пример создания да/нет radiolist-а (<input type="radio" ... />)

Да, есть и такое) Создаёт радиолист с двумя пунктами - да и нет. Текст можно задавать свой. Передаются значения 1 или 0. Текст прогоняется через JText::_() принудительно, без спроса. Фактически является оболочкой для работы с другими функциями хелпер-класса, использует select.option и select.radiolist.
Пример использования:
Код
$list = JHTML::_(
                    "select.booleanlist", // вызываем метод booleanlist
                    "name", // имя для наших input'ов
                    "class=boolclass", // доп. атрибуты, опять же, можно передавать массивом
                    0, // значение по умолчанию, может быть только 1 или 0, приводится к типу integer.
                    "Да", // текст для пункта со значением 1, default="yes"
                    "Нет", // текст для пункта со значением 0, default="no"
                    "cid"  // id для полей, по принципу 8-го параметра из примера выше
);

Здесь описаны все параметры, принимаемые функцией.

Пример создания списка чисел (<select>...</select>)

Мы можем создать select список исключительно чисел, задав диапазон и шаг. Не уверен в особой практической выгоде, но может быть кому то и будет удобно. Привожу пример с комментариями:
Код
$list = JHTML::_(
                     "select.integerlist", // вызываем метод integerlist
                     -15, // нижняя граница диапазона
                     15, // верхняя граница диапазона
                     3, // шаг
                     "intlist", // имя для select'a
                     "class=\"select_intlist\"", // доп. атрибуты, можно передавать массивом
                     12, // selected
                     "%+d" // формат выводимой строки. Если параметр задан, то каждое число прогоняется через функицю sprintf с соотв. форматом.
);

Метод является обёрткой, использует всё те же select.option и select.genericlist

Надеюсь, кому то это будет полезным, потому что, если не ошибаюсь, метод JHTML::_() будет и в J!1.6

Следующим делом хочу описать создание выпадающих фильтров, как при просмотре материалов в менеджере материалов (по категориям, автору и т.д.), но чуть хитрее, а так же реализацию сортировки таблицы по полям с использованием JHTML. Надеюсь до конца выходных управлюсь.
« Последнее редактирование: 30.09.2010, 17:17:12 от Professor »
*

Виталик

  • Завсегдатай
  • 1244
  • 130 / 0
*

Professor

  • Захожу иногда
  • 59
  • 10 / 0
Имеешь в виду что бы вызывать его через JHTML::_()?
Сегодня к вечеру опишу как это сделать.
« Последнее редактирование: 18.08.2010, 17:45:43 от Professor »
*

Виталик

  • Завсегдатай
  • 1244
  • 130 / 0
да, кажеться есть вариант правильно разместить его в админской части компонента, что-бы он был везде доступен
*

Professor

  • Захожу иногда
  • 59
  • 10 / 0
Вот, наваял.

Пример создания своего JHTML класса, который будет вызываться загрузочной функцией JHTML::_()

Ничего сложного в этом, как оказалось, нету)
Обязательным условием будет то, что наш класс будет находиться в админпапке нашего компонента (можно и в фронт-энд папку положить)

И так, в админпапке нашего компонента создаём папку HTML (без разницы как назвать).
В этой папке создаём файл с именем нашего хелпер-класса, например, myjhtmlclass.php.
В этом файле, в самом начале, пишем
Код: php
defined('JPATH_BASE') or die();
а затем создаём наш класс. Сразу скажу несколько слов по этому поводу. В первом посте я описывал, как работает загрузочная функция JHTML::_(). Если помните, ей первым параметром передаётся строка, разделяющая точкой название префикса класса, имя класса и имя метода, к которому мы будем обращаться. В нашем примере я специально создам класс с отличным от JHTML префиксом - условимся называть его MYJHTML. Имя нашего хелпер-класса будет Myjhtmlclass, ну а методы мы сможем называть как захотим.
И так, объявляем класс:
Код: php
class MYJHTMLMyjhtmlclass
{
 function simplepostform ($name)
 {
  $html = "<form name=\"" . $name . "\" action=\"index.php\" method=\"POST\">";
  $html .= "<input type=\"text\" name=\"input1\" id=\"id1\" value=\"value1\" /><br />";
  $html .= "<input type=\"text\" name=\"input2\" id=\"id2\" value=\"value2\" /><br />";
  $html .= "<input type=\"submit\" name=\"submitbutton\" id=\"id3\" value=\"PRESS ME PLEASE\" /><br />";
  $html .= "</form>";

  return $html;
 }
}
Теперь у нас готов класс и метод, к которым мы можем обратиться через загрузочную функцию JHTML::_()
Обратите внимание - метод нашего хелпер-класса принимает один параметр.

Что бы обратиться к этому методу, нам нужно в том месте, где мы обращаемся, всего лишь добавить путь, в котором загрузочная функция будет искать наш класс. Делается это следующим образом:
Код: php
JHTML::addIncludePath (JPATH_COMPONENT_ADMINISTRATOR . DS . "html");
Имя папки (html), как я говорил, может быть другим.
Теперь мы можем обратиться к нашему хелпер-классу и его методам следующим образом:
Код: php
$form = JHTML::_("MYJHTML.myjhtmlclass.simplepostform", "formname");
Мы указываем и префикс, этого можно было не делать, если бы мы назвали наш класс JHTMLMyjhtmlclass. Тогда мы могли бы обратиться к классу следующим образом:
Код: php
$form = JHTML::_("myjhtmlclass.simplepostform", "formname");
Второй параметр, "formname", передастся в нашу функцию.
Обратите внимание на регистр префикса и класса.
Когда мы объявляем наш класс, а так же когда обращаемся через загрузочную функцию,все символы в префиксе (MYJHTML) должны быть заглавными, но имя класса (Myjhtmlclass) при объявлении должно начинаться с заглавной буквы, а остальные буквы должны быть строчными, а при обращении все буквы класса и метода должны быть строчными.

Вот вроде и всё) Будут вопросы - пишите, разберёмся.
*

T34

  • Новичок
  • 9
  • 1 / 0
Спасибо за примеры!

Есть вопрос: как вставить в скрытое поле формы обратной связи одно из значений, которое формирует динамический выпадающий список?

Конкретно это выглядит следующим образом.

Создана форма, которая содержит следующий выпадающий список, формируемый сложным запросом к БД:
Код
<select class="cf_inputbox validate-selection required"
        id="select_1" size="1" name="select_1" title="Выберите одно">
      <option value=''>Выберите, кликнув здесь</option>
<?php
if (!$mainframe->isSite() ) {return;}
$db =& JFactory::getDBO();
$query = "
  SELECT `evdet_id`, `dtstart`, FROM_UNIXTIME(dtstart,'%a, %d/%m/%y %H:%i') AS `dt_start`,FROM_UNIXTIME(dtend,'%H:%i') AS `dt_end`,`summary`
    FROM `#__jevents_vevdetail`
    WHERE `dtend` >= UNIX_TIMESTAMP()
    ORDER BY dtstart;
";
$db->setQuery($query);
$options = $db->loadAssocList();
foreach ( $options as $o ) {
  echo "<option value='".$o[dtstart]."-".$o[dt_start]."-".$o[dt_end]." ".$o[summary]."'>".$o[dt_start]."-".$o[dt_end]." ".$o[summary]."</option>";
}
?>
     </select>

Нажимая кнопку "Отправить", пользователь посылает данные в таблицу БД, включая выбранное значения из вышеуказанного списка. Однако мне нужно сделать так, чтобы одновременно в другое поле той же таблицы (поле 'time') при отправке формы было записано значение `dtstart`, соответствующее выбранной строке выпадающего меню.

Я попытался реализовать это с помощью скрытого поля формы:
Код
<input type='hidden' name='time' id='time' value='<?php echo $o['dtstart']; ?>' /> 

Однако этот способ не работает — в скрытое поле форма подставляет просто самое старшее из всех значений `dtstart`, какие содержит в себе таблица 'jos_jevents_vevdetail'. Мне же нужно, как я писал выше, чтобы это значение соответствовало выбранной в выпадающем меню строке.

Который день роюсь в Интернете, ответ найти не могу.

Подскажите, пожалуйста, можно ли решить эту задачу, и если можно — то как именно?
*

Professor

  • Захожу иногда
  • 59
  • 10 / 0
Вопрос совершенно не по теме, если можно, модераторы, перенесите последнее сообщение и это в отдельную тему.
*

LED

  • Осваиваюсь на форуме
  • 14
  • 0 / 0
Cупер! Огромное спасибо, самая лучшая статья по теме  :D
*

Al195

  • Осваиваюсь на форуме
  • 13
  • 0 / 0
Добрый день
возможно ли создание списка из CheckBox с возможностью мультивыбора
по аналогии multiply select
*

BaR

  • Захожу иногда
  • 86
  • 6 / 0
Добрый день
возможно ли создание списка из CheckBox с возможностью мультивыбора
по аналогии multiply select

Тоже интересует, данная возможность, заранее спасибо за ответ!
Чтобы оставить сообщение,
Вам необходимо Войти или Зарегистрироваться
 

Как вы "въехали" в создание расширений?

Автор aanvale

Ответов: 4
Просмотров: 2199
Последний ответ 13.10.2012, 21:44:25
от passer
Создание таблицы в БД при установке плагина

Автор mohax

Ответов: 2
Просмотров: 1922
Последний ответ 14.06.2011, 17:35:46
от mohax
Создание плагина всплывающего изображения

Автор CTPZ

Ответов: 1
Просмотров: 1700
Последний ответ 25.04.2011, 12:09:12
от moskitos80
Создание компонента! Joomla 1.5 MVC!

Автор ANRY_777

Ответов: 7
Просмотров: 3531
Последний ответ 23.02.2011, 18:58:30
от ANRY_777
Создание конфига для компонента

Автор b2z

Ответов: 10
Просмотров: 2448
Последний ответ 21.10.2010, 18:47:23
от shprota