воскресенье, 21 февраля 2010 г.

Отрисовываем виджет красиво!

Вас не пугают подобные конструкции в виджетах?
<?php
return $this->getOption('date_widget')->render($name, $value, $attributes, $errors).
           $this->renderTag('input', array('type' => 'hidden', 'size' => 10, 'id' => $id = $this->generateId($name).'_jquery_control', 'disabled' => 'disabled')).
           sprintf(<<<EOF
<script type="text/javascript">
  function wfd_%s_read_linked()
  {
    jQuery("#%s").val(jQuery("#%s").val() + "-" + jQuery("#%s").val() + "-" + jQuery("#%s").val());

    return {};
  }

  function wfd_%s_update_linked(date)
  {
    jQuery("#%s").val(parseInt(date.substring(0, 4), 10));
    jQuery("#%s").val(parseInt(date.substring(5, 7), 10));
    jQuery("#%s").val(parseInt(date.substring(8), 10));
  }

  function wfd_%s_check_linked_days()
  {
    var daysInMonth = 32 - new Date(jQuery("#%s").val(), jQuery("#%s").val() - 1, 32).getDate();
    jQuery("#%s option").attr("disabled", "");
    jQuery("#%s option:gt(" + (%s) +")").attr("disabled", "disabled");

    if (jQuery("#%s").val() > daysInMonth)
    {
      jQuery("#%s").val(daysInMonth);
    }
  }

  jQuery(document).ready(function() {
    jQuery("#%s").datepicker(jQuery.extend({}, {
      minDate:    new Date(%s, 1 - 1, 1),
      maxDate:    new Date(%s, 12 - 1, 31),
      beforeShow: wfd_%s_read_linked,
      onSelect:   wfd_%s_update_linked,
      showOn:     "button"
      %s
    }, jQuery.datepicker.regional["%s"], %s, {dateFormat: "yy-mm-dd"}));
  });

  jQuery("#%s, #%s, #%s").change(wfd_%s_check_linked_days);
</script>
EOF
      ,
      $prefix, $id,
      $this->generateId($name.'[year]'), $this->generateId($name.'[month]'), $this->generateId($name.'[day]'),
      $prefix,
      $this->generateId($name.'[year]'), $this->generateId($name.'[month]'), $this->generateId($name.'[day]'),
      $prefix,
      $this->generateId($name.'[year]'), $this->generateId($name.'[month]'),
      $this->generateId($name.'[day]'), $this->generateId($name.'[day]'),
      ($this->getOption('can_be_empty') ? 'daysInMonth' : 'daysInMonth - 1'),
      $this->generateId($name.'[day]'), $this->generateId($name.'[day]'),
      $id,
      min($this->getOption('date_widget')->getOption('years')), max($this->getOption('date_widget')->getOption('years')),
      $prefix, $prefix, $image, $this->getOption('culture'), $this->getOption('config'),
      $this->generateId($name.'[day]'), $this->generateId($name.'[month]'), $this->generateId($name.'[year]'),
      $prefix
    );
?>
Если нет, то этот пост не для вас. Остальные читают дальше.

Меня напрягает рендеринг виджета из его метода render(), а именно — вывод всех тегов через renderTag() и renderContentTag(), а также конструкции типа приведенной выше, когда весь код помещается в heredoc, и рендерится с помощью sprintf. Я не уверен в правильности своей позиции, но я полагаю, что виджет в общем, и его метод render() в частности, реализуют бизнес-логику, а не отображение. Как бы то ни было, мне удобнее работать с виджетом как с кусочком контроллера, а не View. Исходя из этого напрашивается вопрос: как выделить из виджета (точнее, из его метода render()) непосредственное отображение? То есть Шаблон. Как сделать так, чтобы виджет пользовался обычным, написанным на HTML, шаблоном? Ответ очевиден: использовать партиал.
<?php
  public function render($name, $value = null, $attributes = array(), $errors = array())
  {
     .....
     return get_partial('default/my_super_widget',array(параметры_для_виджета));
  }
?>

Возникает вопрос: где хранить файлы партиалов? Варианты: global, default/template, my_widgets/templates, ... Я еще не определился с оптимальным вариантом.

И не забудьте подключить хелпер-библиотеку Partial, если она была отключена:

sfContext::getInstance()->getConfiguration()->loadHelpers('Partial');

2 комментария:

  1. Напрягает, конечно. Именно для таких случаев придумали unobstrusive JS.

    ОтветитьУдалить
  2. @develop7 - вероятно, JS - не самый лучший пример. Рассмотренное решение более общее - для совершенно произвольных виджетов. Особенно полезно для виджетов, содержащих много HTML.

    ОтветитьУдалить