]> git.andy128k.dev Git - ipf.git/commitdiff
form layout
authorAndrey Kutejko <andy128k@gmail.com>
Mon, 18 Aug 2014 19:59:14 +0000 (22:59 +0300)
committerAndrey Kutejko <andy128k@gmail.com>
Mon, 18 Aug 2014 19:59:14 +0000 (22:59 +0300)
ipf/admin/app.php
ipf/form.php
ipf/form/boundfield.php
ipf/form/layout.php [new file with mode: 0644]

index 8c74d61c669614c79be7cda8d02e455fae85211d..a8651b4c0b3a40b21911a5b5af8e866967607c22 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use \PFF\HtmlBuilder\Tag as Tag;
+
 class IPF_Admin_App extends IPF_Application
 {
     public function __construct()
@@ -94,14 +96,54 @@ class IPF_Admin_App extends IPF_Application
 
     public static function renderForm($form)
     {
-        return $form->htmlOutput(
-            '<div class="form-row"><div>%2$s %1$s%3$s%4$s</div></div>',
-            '<div>%s</div>',
-            '</div>',
-            '<p class="help">%s</p>',
-            true,
-            '<div class="form-group-title">%s</div>',
-            false);
+        return $form->renderLayout(new IPF_Admin_Form_Layout, false);
+    }
+}
+
+class IPF_Admin_Form_Layout extends IPF_Form_LayoutAdapter
+{
+    public function startForm($form)
+    {
+        $errors = $this->commonErrors($form);
+        return $this->errors($errors) .
+            $this->hiddenWidgets($form);
+    }
+
+    public function startGroup($label)
+    {
+        if ($label)
+            return Tag::div(array('class' => 'form-group-title'), $label)->html();
+        else
+            return '';
+    }
+
+    public function field($boundField, $label)
+    {
+        if ($boundField->help_text) {
+            $help_text = Tag::p(array('class' => 'help'))
+                ->raw($boundField->help_text);
+        } else {
+            $help_text = '';
+        }
+
+        return $this->errors($boundField->errors) .
+            Tag::div(array('class' => 'form-row'),
+                Tag::div()
+                    ->raw($label)
+                    ->raw(' ')
+                    ->raw($boundField->render_w())
+                    ->append($help_text));
+    }
+
+    private function errors($errors)
+    {
+        if (!count($errors))
+            return '';
+
+        $ul = Tag::ul(array('class' => 'errorlist'));
+        foreach ($errors as $err)
+            $ul->append(Tag::li(null, $err));
+        return Tag::div(null, $ul);
     }
 }
 
index 2a803a7b4fb3febdcebc327387befbdd53327966..f034d4317fd2f9fa125400c8865008b47a98e421 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use \PFF\HtmlBuilder\Tag as Tag;
+
 abstract class IPF_Form implements Iterator
 {
     public $fields = array();
@@ -106,27 +108,31 @@ abstract class IPF_Form implements Iterator
         return '';
     }
 
-    public function render_top_errors()
+    public function hiddenFields()
     {
-        $top_errors = (isset($this->errors['__all__'])) ? $this->errors['__all__'] : array();
-        array_walk($top_errors, 'IPF_Form_htmlspecialcharsArray');
-        return new IPF_Template_SafeString(IPF_Form::renderErrorsAsHTML($top_errors), true);
+        $hidden = array();
+        foreach ($this->fields as $name => $field)
+            if ($field->widget->is_hidden)
+                $hidden[] = $name;
+        return $hidden;
     }
 
-    public function get_top_errors()
+    public function render_top_errors($raw=false)
     {
-        return (isset($this->errors['__all__'])) ? $this->errors['__all__'] : array();
+        $errors = IPF_Form::renderErrorsAsHTML($this->get_top_errors());
+        if ($raw)
+            return $errors;
+        else
+            return new IPF_Template_SafeString($errors, true);
     }
-    
-    public function htmlOutput($normal_row, $error_row, $row_ender,
-                               $help_text_html, $errors_on_separate_row, $group_title=null,
-                               $extra_js=true)
+
+    public function get_top_errors()
     {
-        $top_errors = (isset($this->errors['__all__'])) ? $this->errors['__all__'] : array();
-        array_walk($top_errors, 'IPF_Form_htmlspecialcharsArray');
-        $output = array();
-        $hidden_fields = array();
+        return \PFF\Arr::get($this->errors, '__all__', array());
+    }
 
+    public function renderLayout($layout, $raw=false)
+    {
         foreach ($this->field_groups as $field_group) {
             if (!$field_group['fields'])
                 throw new IPF_Exception('Empty field group.');
@@ -146,31 +152,20 @@ abstract class IPF_Form implements Iterator
             );
         }
         
-        if (count($groups)) {
-            $render_group_title = $group_title ? true : false;
-        } else {
+        if (!count($groups)) {
             $groups = array(array('fields' => $this->fields));
-            $render_group_title = false;
         }
 
+        $output = $layout->startForm($this);
         foreach ($groups as $group) {
-            if ($render_group_title && isset($group['label']))
-                $output[] = sprintf($group_title, $group['label']);
+            $groupLabel = \PFF\Arr::get($group, 'label', '');
+            $output .= $layout->startGroup($groupLabel);
 
             foreach ($group['fields'] as $name=>$field) {
                 $bf = new IPF_Form_BoundField($this, $field, $name);
-                $bf_errors = $bf->errors;
-                array_walk($bf_errors, 'IPF_Form_htmlspecialcharsArray');
-                if ($field->widget->is_hidden) {
-                    foreach ($bf_errors as $_e) {
-                        $top_errors[] = sprintf(__('(Hidden field %1$s) %2$s'),
-                                                $name, $_e);
-                    }
-                    $hidden_fields[] = $bf; // Not rendered
-                } else {
-                    if ($errors_on_separate_row and count($bf_errors)) {
-                        $output[] = sprintf($error_row, IPF_Form::renderErrorsAsHTML($bf_errors));
-                    }
+
+                if (!$field->widget->is_hidden) {
+
                     if (strlen($bf->label) > 0) {
                         $label = htmlspecialchars($bf->label, ENT_COMPAT, 'UTF-8');
                         if ($this->label_suffix) {
@@ -183,49 +178,22 @@ abstract class IPF_Form implements Iterator
                             $label_attrs = array('class'=>'required');
                         else
                             $label_attrs = array();
-                        $label = $bf->labelTag($label,$label_attrs);
+                        $label = $bf->labelTagRaw($label, $label_attrs);
                     } else {
                         $label = '';
                     }
-                    if ($bf->help_text) {
-                        // $bf->help_text can contains HTML and is not
-                        // escaped.
-                        $help_text = sprintf($help_text_html, $bf->help_text);
-                    } else {
-                        $help_text = '';
-                    }
-                    $errors = '';
-                    if (!$errors_on_separate_row and count($bf_errors)) {
-                        $errors = IPF_Form::renderErrorsAsHTML($bf_errors);
-                    }
-                    $output[] = sprintf($normal_row, $errors, $label,
-                                        $bf->render_w(), $help_text);
+
+                    $output .= $layout->field($bf, $label);
                 }
             }
+            $output .= $layout->endGroup($groupLabel);
         }
-        if (count($top_errors)) {
-            $errors = sprintf($error_row, IPF_Form::renderErrorsAsHTML($top_errors));
-            array_unshift($output, $errors);
-        }
-        if (count($hidden_fields)) {
-            $_tmp = '';
-            foreach ($hidden_fields as $hd) {
-                $_tmp .= $hd->render_w();
-            }
-            if (count($output)) {
-                $last_row = array_pop($output);
-                $last_row = substr($last_row, 0, -strlen($row_ender)).$_tmp
-                    .$row_ender;
-                $output[] = $last_row;
-            } else {
-                $output[] = $_tmp;
-            }
-        }
+        $output .= $layout->endForm($this);
 
-        if ($extra_js)
-            $output = array_merge($output, $this->extra_js());
+        if (!$raw)
+            $output = new IPF_Template_SafeString($output, true);
 
-        return new IPF_Template_SafeString($this->before_render . implode("\n", $output) . $this->after_render, true);
+        return $output;
     }
 
     public function extra_js()
@@ -236,35 +204,24 @@ abstract class IPF_Form implements Iterator
         return array_unique($extra_js);
     }
 
-    public function render_p()
+    public function render_p($raw=false)
     {
-        return $this->htmlOutput('<p>%1$s%2$s %3$s%4$s</p>', '%s', '</p>', ' %s', true);
+        return $form->renderLayout(new IPF_Form_ParagraphLayout, $raw);
     }
 
-    public function render_ul()
+    public function render_ul($raw=false)
     {
-        return $this->htmlOutput('<li>%1$s%2$s %3$s%4$s</li>', '<li>%s</li>', '</li>', ' %s', false);
+        return $form->renderLayout(new IPF_Form_ListLayout, $raw);
     }
 
-    public function render_table()
+    public function render_table($raw=false)
     {
-        return $this->htmlOutput(
-            '<tr><th>%2$s</th><td>%1$s%3$s%4$s</td></tr>',
-            '<tr><td colspan="2">%s</td></tr>',
-            '</td></tr>',
-            '<br /><span class="helptext">%s</span>',
-            false);
+        return $form->renderLayout(new IPF_Form_TableLayout, $raw);
     }
 
-    public function render_admin()
+    public function render_admin($raw=false)
     {
-        return $this->htmlOutput(
-            '<div class="form-row"><div>%2$s %1$s%3$s%4$s</div></div>',
-            '<div>%s</div>',
-            '</div>',
-            '<p class="help">%s</p>',
-            true,
-            '<div class="form-group-title">%s</div>');
+        return $form->renderLayout(new IPF_Admin_Form_Layout, $raw);
     }
 
     function __get($prop)
@@ -309,13 +266,12 @@ abstract class IPF_Form implements Iterator
 
     public static function renderErrorsAsHTML($errors)
     {
-        if (count($errors)==0)
+        if (!count($errors))
             return '';
-        $tmp = array();
-        foreach ($errors as $err) {
-            $tmp[] = '<li>'.$err.'</li>';
-        }
-        return '<ul class="errorlist">'.implode("\n", $tmp).'</ul>';
+        $ul = Tag::ul(array('class' => 'errorlist'));
+        foreach ($errors as $err)
+            $ul->append(Tag::li(null, $err));
+        return $ul;
     }
 }
 
index 5794474cd596657908440e9cdf690c8866405f63..df6908fb4ed9b7f2cbb4750277153275536394f5 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use \PFF\HtmlBuilder\Tag as Tag;
+
 class IPF_Form_BoundField
 {
     public $form = null;
@@ -48,27 +50,27 @@ class IPF_Form_BoundField
         return $widget->render($this->html_name, $this->value(), $attrs);
     }
 
-    public function labelTag($contents=null, $attrs=array())
+    public function labelTag($contents=null, $attrs=array(), $raw=false)
     {
-        $contents = ($contents) ? $contents : htmlspecialchars($this->label);
+        $label = Tag::label($attrs);
+
+        if ($contents)
+            $label->raw($contents);
+        else
+            $label->append($this->label);
+
         $widget = $this->field->widget;
         $id = (isset($widget->attrs['id'])) ? $widget->attrs['id'] : $this->autoId();
-        $_tmp = array();
-        $class_found = false;
-        foreach ($attrs as $attr=>$val) {
-            $_tmp[] = $attr.'="'.$val.'"';
-            if ($attr=='class')
-               $class_found = true;
-        }
-        if ( (!$class_found) && ($this->field->required==1))
-               $_tmp[] = 'class="req"';
-        if (count($_tmp)) {
-            $attrs = ' '.implode(' ', $_tmp);
-        } else {
-            $attrs = '';
-        }
-        return new IPF_Template_SafeString(sprintf('<label for="%s"%s>%s</label>',
-                                                    $widget->idForLabel($id), $attrs, $contents), true);
+
+        $label->attr('for', $widget->idForLabel($id));
+
+        if ($this->field->required)
+            $label->addClass('req');
+
+        if ($raw)
+            return $label;
+        else
+            return new IPF_Template_SafeString($label, true);
     }
 
     public function autoId()
@@ -82,9 +84,13 @@ class IPF_Form_BoundField
         return '';
     }
 
-    public function fieldErrors()
+    public function fieldErrors($raw=false)
     {
-        return new IPF_Template_SafeString(IPF_Form::renderErrorsAsHTML($this->errors), true);
+        $errors = IPF_Form::renderErrorsAsHTML($this->errors);
+        if ($raw)
+            return $errors;
+        else
+            return new IPF_Template_SafeString($errors, true);
     }
 
     public function __get($prop)
diff --git a/ipf/form/layout.php b/ipf/form/layout.php
new file mode 100644 (file)
index 0000000..fab7043
--- /dev/null
@@ -0,0 +1,178 @@
+<?php
+
+/* informal interface IPF_Form_Layout
+{
+    public function startForm($form);
+    public function startGroup($label);
+    public function field($boundField, $label);
+    public function endGroup($label);
+    public function endForm($form);
+}*/
+
+
+abstract class IPF_Form_LayoutAdapter /*implements informal interface IPF_Form_Layout*/
+{
+    public function startForm($form) { return ''; }
+    public function startGroup($label) { return ''; }
+    public abstract function field($boundField, $label);
+    public function endGroup($label) { return ''; }
+    public function endForm($form) { return ''; }
+
+    protected function commonErrors($form)
+    {
+        $commonErrors = $form->get_top_errors();
+        foreach ($form->hiddenFields() as $field_name)
+            foreach (\PFF\Arr::get($form->errors, $field_name, array()) as $error)
+                $commonErrors[] = sprintf(__('(Hidden field %1$s) %2$s'), $field_name, $error);
+        return $commonErrors;
+    }
+
+    protected function hiddenWidgets($form)
+    {
+        $hiddenWidgets = '';
+        foreach ($form->hiddenFields() as $field_name)
+            $hiddenWidgets .= $form->field($field_name)->render_w();
+        return $hiddenWidgets;
+    }
+
+    private $deferred = '';
+
+    protected function defer($code)
+    {
+        $this->deferred .= $code;
+    }
+
+    protected function takeDeferred()
+    {
+        $deferred = $this->deferred;
+        $this->deferred = '';
+        return $deferred;
+    }
+
+    protected function errorList($errors)
+    {
+        if (!count($errors))
+            return '';
+
+        $ul = Tag::ul(array('class' => 'errorlist'));
+        foreach ($errors as $err)
+            $ul->append(Tag::li(null, $err));
+        return $ul;
+    }
+}
+
+
+class IPF_Form_ParagraphLayout extends IPF_Form_LayoutAdapter
+{
+    public function startForm($form)
+    {
+        $o = $this->hiddenWidgets($form) . $form->extra_js();
+
+        $errors = $this->commonErrors($form);
+        if (count($errors))
+            $o .= $this->errorList($errors);
+
+        return $o;
+    }
+
+    public function field($boundField, $label)
+    {
+        return
+            $this->errorList($boundField->errors) .
+            Tag::p()
+                ->raw($label)
+                ->raw(' ')
+                ->raw($boundField->render_w())
+                ->raw(' ')
+                ->raw($boundField->help_text);
+    }
+}
+
+
+class IPF_Form_ListLayout extends IPF_Form_LayoutAdapter
+{
+    public function startForm($form)
+    {
+        $this->defer($this->hiddenWidgets($form) . $form->extra_js());
+
+        $errors = $this->commonErrors($form);
+        if (count($errors))
+            return Tag::li()
+                ->raw($this->errorList($errors))
+                ->raw($this->takeDeferred());
+        else
+            return '';
+    }
+
+    public function field($boundField, $label)
+    {
+        if ($boundField->help_text)
+            $help_text = '<br /><span class="helptext">'.$boundField->help_text.'</span>';
+        else
+            $help_text = '';
+
+        return Tag::li()
+            ->raw($this->takeDeferred())
+            ->raw($this->errorList($boundField->errors))
+            ->raw($label)
+            ->raw(' ')
+            ->raw($boundField->render_w())
+            ->raw($help_text);
+    }
+
+    public function endForm($form)
+    {
+        $deferred = $this->deferred();
+        if ($deferred)
+            return Tag::li()->raw($deferred);
+        else
+            return '';
+    }
+}
+
+
+class IPF_Form_TableLayout extends IPF_Form_LayoutAdapter
+{
+    public function startForm($form)
+    {
+        $this->defer($this->hiddenWidgets($form) . $form->extra_js());
+
+        $errors = $this->commonErrors($form);
+        if (count($errors))
+            return Tag::tr(null,
+                Tag::td()->attr('colspan', 2)
+                    ->raw($this->errorList($errors))
+                    ->raw($this->deferred()));
+        else
+            return '';
+    }
+
+    public function field($boundField, $label)
+    {
+        if ($boundField->help_text)
+            $help_text = '<br /><span class="helptext">'.$boundField->help_text.'</span>';
+        else
+            $help_text = '';
+
+        return Tag::tr(null,
+            Tag::th()
+                ->raw($label),
+            Tag::td()
+                ->raw($this->takeDeferred())
+                ->raw($this->errorList($boundField->errors))
+                ->raw($boundField->render_w())
+                ->raw($help_text));
+    }
+
+    public function endForm($form)
+    {
+        $deferred = $this->takeDeferred();
+        if ($deferred)
+            return Tag::tr(null,
+                Tag::td()
+                    ->raw($deferred));
+        else
+            return '';
+    }
+}
+