diff --git a/include/class.forms.php b/include/class.forms.php index 5cbdcae5b7de73f80ecf70f6253bf4feb8ff0bdb..b47444e793caa0ed6a9eefc649d602f36e257e64 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -19,7 +19,7 @@ * data for a ticket */ class Form { - + static $renderer = 'GridFluidLayout'; static $id = 0; var $fields = array(); @@ -174,6 +174,17 @@ class Form { echo $this->getMedia(); } + function getLayout() { + $rc = @$options['renderer'] ?: static::$renderer; + return new $rc($title, $options); + } + + function asTable($options=array()) { + return $this->getLayout()->asTable($this); + // XXX: Media can't go in a table + echo $this->getMedia(); + } + function getMedia() { static $dedup = array(); @@ -322,6 +333,137 @@ abstract class AbstractForm extends Form { abstract function buildFields(); } +/** + * Container class to represent the connection between the form fields and the + * rendered state of the form. + */ +interface FormRenderer { + // Render the form fields into a table + function asTable($form); + // Render the form fields into divs + function asBlock($form); +} + +abstract class FormLayout { + static $default_cell_layout = 'Cell'; + + function getLayout($field) { + $layout = $field->get('layout') ?: static::$default_cell_layout; + if (is_string($layout)) + $layout = new $layout(); + return $layout; + } +} + +class GridFluidLayout +extends FormLayout +implements FormRenderer { + function asTable($form) { + ob_start(); +?> + <table class="<?php echo 'grid form' ?>"> + <colgroup width="8.333333%"><col span="12"/></colgroup> + <caption><?php echo Format::htmlchars($form->getTitle()); ?> + <div><small><?php echo Format::viewableImages($form->getInstructions()); ?></small></div> + </caption> +<?php + $row_size = 12; + $cols = $row = 0; + foreach ($form->getFields() as $f) { + $layout = $this->getLayout($f); + $size = $layout->getWidth() ?: 12; + if ($offs = $layout->getOffset()) { + $size += $offs; + } + if ($cols < $size || $layout->isBreakForced()) { + if ($row) echo '</tr>'; + echo '<tr>'; + $cols = $row_size; + $row++; + } + // Render the cell + $cols -= $size; + $attrs = array('colspan' => $size, 'rowspan' => $layout->getHeight(), + 'style' => '"'.$layout->getOption('style').'"'); + if ($offs) { ?> + <td colspan="<?php echo $offset; ?>"></td> <?php + } + ?> + <td class="cell" <?php echo Format::array_implode('=', ' ', array_filter($attrs)); ?> + data-field-id="<?php echo $f->get('id'); ?>"> + <fieldset class="field <?php if (!$f->isVisible()) echo 'hidden'; ?>" + id="field<?php echo $f->getWidget()->id; ?>" + data-field-id="<?php echo $f->get('id'); ?>"> +<?php if ($label = $f->get('label')) { ?> + <label class="<?php if ($f->isRequired()) echo 'required'; ?>" + for="<?php echo $f->getWidget()->id; ?>"> + <?php echo Format::htmlchars($label); ?>: + </label> +<?php } + if ($f->get('hint')) { ?> + <div class="field-hint-text"> + <?php echo Format::htmlchars($f->get('hint')); ?> + </div> +<?php } + $f->render(); + if ($f->errors()) + foreach ($f->errors() as $e) + echo sprintf('<div class="error">%s</div>', Format::htmlchars($e)); +?> + </fieldset> + </td> + <?php + } + if ($row) + echo '</tr>'; + + echo '</tbody></table>'; + + return ob_get_clean(); + } + + function asBlock($form) {} +} + +/** + * Basic container for field and form layouts. By default every cell takes + * a whole output row and does not imply any sort of width. + */ +class Cell { + function isBreakForced() { return true; } + function getWidth() { return false; } + function getHeight() { return 1; } + function getOffset() { return 0; } + function getOption($prop) { return false; } +} + +/** + * Fluid grid layout, meaning each cell renders to the right of the previous + * cell (for left-to-right layouts). A width in columns can be specified for + * each cell along with an offset from the previous cell. A height of columns + * along with an optional break is supported. + */ +class GridFluidCell +extends Cell { + var $span; + var $options; + + function __construct($span, $options=array()) { + $this->span = $span; + $this->options = $options + array( + 'rows' => 1, # rowspan + 'offset' => 0, # skip some columns + 'break' => false, # start on a new row + ); + } + + function isBreakForced() { return $this->options['break']; } + function getWidth() { return $this->span; } + function getHeight() { return $this->options['rows']; } + function getOffset() { return $this->options['offset']; } + function getOption($prop) { return $this->options[$prop]; } +} + require_once(INCLUDE_DIR . "class.json.php"); class FormField { diff --git a/include/staff/templates/quick-add.tmpl.php b/include/staff/templates/quick-add.tmpl.php index b8efa8dd8283dadefc58ede8be02c1f0cc79f134..7f04098f316b34b96d305cad3649bd90fbde5e5e 100644 --- a/include/staff/templates/quick-add.tmpl.php +++ b/include/staff/templates/quick-add.tmpl.php @@ -6,8 +6,8 @@ <div id="msg_error" class="error-banner"><?php echo Format::htmlchars($errors['err']); ?></div> <?php } ?> <form method="post" action="#<?php echo $path; ?>"> - <div class="inset quick-add"> - <?php $form->render(); ?> + <div class="quick-add"> + <?php echo $form->asTable(); ?> </div> <hr> <p class="full-width"> diff --git a/scp/css/scp.css b/scp/css/scp.css index 37cdf097d1fb5fd024e7eabdd8952e63a8f64734..8287b4ce28c2de7d65e9a7d90e20406c2b5765b0 100644 --- a/scp/css/scp.css +++ b/scp/css/scp.css @@ -2613,7 +2613,7 @@ td.indented { form .inset { padding: 10px; } -.dialog form .inset { +.dialog form .quick-add { min-height: 150px; } .span12 { @@ -2688,15 +2688,6 @@ table.grid.form caption { margin-bottom: 5px; } -#basic_search { - background-color: #f4f4f4; - margin: -10px; - margin-bottom: 0px; - padding: 8px; - box-shadow: inset 0 4px 12px -11px black, inset 0 -4px 12px -11px black; - border-bottom: 1px dotted #aaa; -} - #basic_search { background-color: #f4f4f4; margin: -10px 0; @@ -2706,3 +2697,10 @@ table.grid.form caption { border-bottom: 1px dotted #aaa; border-radius: 0 0 5px 5px; } + +#basic-ticket-search { + border: 1px solid #999; + border-color: rgba(0,0,0,0.45); + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; +}