diff --git a/bootstrap.php b/bootstrap.php index d2afa2243f7bfa2914da15428c3f8e2c9b197fcb..63d71fe8754d51c5d110ec1d9fa447dc0bfefdac 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -116,6 +116,7 @@ class Bootstrap { define('FORM_ANSWER_TABLE',$prefix.'form_entry_values'); define('TOPIC_TABLE',$prefix.'help_topic'); + define('TOPIC_FORM_TABLE',$prefix.'help_topic_form'); define('SLA_TABLE', $prefix.'sla'); define('EMAIL_TABLE',$prefix.'email'); diff --git a/include/ajax.forms.php b/include/ajax.forms.php index 6c35f1bb2fe2055d220c89c583261a189223ddc0..169290c945bac96986ef2ef222710691256851b5 100644 --- a/include/ajax.forms.php +++ b/include/ajax.forms.php @@ -24,13 +24,13 @@ class DynamicFormsAjaxAPI extends AjaxController { $_SESSION[':form-data'] = array_merge($_SESSION[':form-data'], $_GET); } - if ($form = $topic->getForm()) { + foreach ($topic->getForms() as $form) { ob_start(); $form->getForm($_SESSION[':form-data'])->render(!$client); - $html = ob_get_clean(); + $html .= ob_get_clean(); ob_start(); print $form->getMedia(); - $media = ob_get_clean(); + $media .= ob_get_clean(); } return $this->encode(array( 'media' => $media, @@ -140,5 +140,23 @@ class DynamicFormsAjaxAPI extends AjaxController { array('id'=>$field->ajaxUpload(true)) ); } + + function getAllFields($id) { + global $thisstaff; + + if (!$thisstaff) + Http::response(403, 'Login required'); + elseif (!$form = DynamicForm::lookup($id)) + Http::response(400, 'No such form'); + + ob_start(); + include STAFFINC_DIR . 'templates/dynamic-form-fields-view.tmpl.php'; + $html = ob_get_clean(); + + return $this->encode(array( + 'success'=>true, + 'html' => $html, + )); + } } ?> diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php index 181c1bdbd524bc8c3c2582c874b03ca127738ba9..cdc6217228ed501bc51f01f9520db45110753ded 100644 --- a/include/class.dynamic_forms.php +++ b/include/class.dynamic_forms.php @@ -32,6 +32,11 @@ class DynamicForm extends VerySimpleModel { 'table' => FORM_SEC_TABLE, 'ordering' => array('title'), 'pk' => array('id'), + 'joins' => array( + 'fields' => array( + 'reverse' => 'DynamicFormField.form', + ), + ), ); // Registered form types @@ -112,6 +117,14 @@ class DynamicForm extends VerySimpleModel { return $this->get('deletable'); } + function disableFields(array $ids) { + foreach ($this->getFields() as $F) { + if (in_array($F->get('id'), $ids)) { + $F->disable(); + } + } + } + function instanciate($sort=1) { return DynamicFormEntry::create(array( 'form_id'=>$this->get('id'), 'sort'=>$sort)); @@ -422,6 +435,7 @@ class DynamicFormField extends VerySimpleModel { ); var $_field; + var $_disabled = false; const FLAG_ENABLED = 0x00001; const FLAG_EXT_STORED = 0x00002; // Value stored outside of form_entry_value @@ -525,6 +539,12 @@ class DynamicFormField extends VerySimpleModel { function isEditable() { return $this->hasFlag(self::FLAG_MASK_EDIT); } + function disable() { + $this->_disabled = true; + } + function isEnabled() { + return !$this->_disabled && $this->hasFlag(self::FLAG_ENABLED); + } function hasFlag($flag) { return (isset($this->flags) && ($this->flags & $flag) != 0); @@ -638,19 +658,19 @@ class DynamicFormField extends VerySimpleModel { return $this->hasFlag(self::FLAG_CLOSE_REQUIRED); } function isEditableToStaff() { - return $this->hasFlag(self::FLAG_ENABLED) + return $this->isEnabled() && $this->hasFlag(self::FLAG_AGENT_EDIT); } function isVisibleToStaff() { - return $this->hasFlag(self::FLAG_ENABLED) + return $this->isEnabled() && $this->hasFlag(self::FLAG_AGENT_VIEW); } function isEditableToUsers() { - return $this->hasFlag(self::FLAG_ENABLED) + return $this->isEnabled() && $this->hasFlag(self::FLAG_CLIENT_EDIT); } function isVisibleToUsers() { - return $this->hasFlag(self::FLAG_ENABLED) + return $this->isEnabled() && $this->hasFlag(self::FLAG_CLIENT_VIEW); } @@ -722,7 +742,7 @@ class DynamicFormEntry extends VerySimpleModel { 'pk' => array('id'), 'select_related' => array('form'), 'fields' => array('id', 'form_id', 'object_type', 'object_id', - 'sort', 'updated', 'created'), + 'sort', 'extra', 'updated', 'created'), 'joins' => array( 'form' => array( 'null' => true, @@ -785,6 +805,10 @@ class DynamicFormEntry extends VerySimpleModel { $this->_form = DynamicForm::lookup($this->get('form_id')); if ($this->_form && isset($this->id)) $this->_form->data($this); + if (isset($this->extra)) { + $x = JsonDataParser::decode($this->extra) ?: array(); + $this->_form->disableFields($x['disable'] ?: array()); + } } return $this->_form; } @@ -958,6 +982,7 @@ class DynamicFormEntry extends VerySimpleModel { } } if (!$found && ($fImpl = $field->getImpl($field)) + && $field->isEnabled() && !$fImpl->isPresentationOnly()) { $a = DynamicFormEntryAnswer::create( array('field_id'=>$field->get('id'), 'entry_id'=>$this->id)); diff --git a/include/class.ticket.php b/include/class.ticket.php index 1dd62e97cf49c0be0a0a727260f54062f8d0c8b3..dc6f5fe311c7b65be9b4231649a7cbd553447554 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -2758,20 +2758,43 @@ class Ticket { if (!$errors) { - # Perform ticket filter actions on the new ticket arguments - $__form = null; + // Handle the forms associate with the help topics. Instanciate the + // entries, disable and track the requested disabled fields. + $topic_forms = array(); if ($vars['topicId']) { - if (($__topic=Topic::lookup($vars['topicId'])) - && ($__form = $__topic->getForm()) - ) { - $__form = $__form->instanciate(); - $__form->setSource($vars); + if ($__topic=Topic::lookup($vars['topicId'])) { + foreach ($__topic->getForms() as $idx=>$__F) { + $disabled = array(); + foreach ($__F->getFields() as $field) { + if (!$field->isEnabled() && $field->hasFlag(DynamicFormField::FLAG_ENABLED)) + $disabled[] = $field->get('id'); + } + // Special handling for the ticket form — disable fields + // requested to be disabled as per the help topic. + if ($__F->get('type') == 'T') { + foreach ($form->getFields() as $field) { + if (false !== array_search($field->get('id'), $disabled)) + $field->disable(); + } + $form->sort = $idx; + $__F = $form; + } + else { + $__F = $__F->instanciate($idx); + $__F->setSource($vars); + $topic_forms[] = $__F; + } + // Track fields currently disabled + $__F->extra = JsonDataEncoder::encode(array( + 'disable' => $disabled + )); + } } } try { $vars = self::filterTicketData($origin, $vars, - array($form, $__form), $user); + array_merge(array($form), $topic_forms), $user); } catch (RejectedException $ex) { return $reject_ticket( @@ -2825,10 +2848,8 @@ class Ticket { if ($vars['topicId']) { if ($topic=Topic::lookup($vars['topicId'])) { - if ($topic_form = $topic->getForm()) { - $TF = $topic_form->getForm($vars); - $topic_form = $topic_form->instanciate(); - $topic_form->setSource($vars); + foreach ($topic_forms as $topic_form) { + $TF = $topic_form->getForm()->getForm($vars); if (!$TF->isValid($field_filter('topic'))) $errors = array_merge($errors, $TF->errors()); } @@ -2972,7 +2993,7 @@ class Ticket { $form->save(); // Save the form data from the help-topic form, if any - if ($topic_form) { + foreach ($topic_forms as $topic_form) { $topic_form->setTicketId($id); $topic_form->save(); } diff --git a/include/class.topic.php b/include/class.topic.php index 5adc575635e0fc40f214778ad4da2d2622948177..9f02858efe744889eef7d9fae6707f142791a105 100644 --- a/include/class.topic.php +++ b/include/class.topic.php @@ -52,11 +52,15 @@ class Topic extends VerySimpleModel { 'priority_id' => 'Priority.priority_id', ), ), + 'forms' => array( + 'reverse' => 'TopicFormModel.topic', + 'null' => true, + ), ), ); var $page; - var $form; + var $_forms; const DISPLAY_DISABLED = 2; @@ -129,19 +133,15 @@ class Topic extends VerySimpleModel { return $this->page; } - function getFormId() { - return $this->form_id; - } - - function getForm() { - $id = $this->getFormId(); - - if ($id == self::FORM_USE_PARENT && ($p = $this->getParent())) - $this->form = $p->getForm(); - elseif ($id && !$this->form) - $this->form = DynamicForm::lookup($id); - - return $this->form; + function getForms() { + if (!isset($this->_forms)) { + foreach ($this->forms->select_related('form') as $F) { + $extra = JsonDataParser::decode($F->extra) ?: array(); + $F->form->disableFields($extra['disable'] ?: array()); + $this->_forms[] = $F->form; + } + } + return $this->_forms; } function autoRespond() { @@ -426,12 +426,63 @@ class Topic extends VerySimpleModel { $errors['err']=sprintf(__('Unable to update %s.'), __('this help topic')) .' '.__('Internal error occurred'); } - if (!$cfg || $cfg->getTopicSortMode() == 'a') { - static::updateSortOrder(); + if ($rv) { + if (!$cfg || $cfg->getTopicSortMode() == 'a') { + static::updateSortOrder(); + } + $this->updateForms($vars, $errors); } return $rv; } + function updateForms($vars, &$errors) { + $find_disabled = function($form) use ($vars) { + $fields = $vars['fields']; + $disabled = array(); + foreach ($form->fields->values_flat('id') as $row) { + list($id) = $row; + if (false === ($idx = array_search($id, $fields))) { + $disabled[] = $id; + } + } + return $disabled; + }; + + // Consider all the forms in the request + if (is_array($form_ids = $vars['forms'])) { + $forms = TopicFormModel::objects() + ->select_related('form') + ->filter(array('topic_id' => $this->getId())); + foreach ($forms as $F) { + if (false !== ($idx = array_search($F->form_id, $form_ids))) { + $F->sort = $idx + 1; + $F->extra = JsonDataEncoder::encode( + array('disable' => $find_disabled($F->form)) + ); + $F->save(); + unset($form_ids[$idx]); + } + elseif ($F->form->get('type') != 'T') { + $F->delete(); + } + } + foreach ($form_ids as $sort=>$id) { + if (!($form = DynamicForm::lookup($id))) { + continue; + } + TopicFormModel::create(array( + 'topic_id' => $this->getId(), + 'form_id' => $id, + 'sort' => $sort + 1, + 'extra' => JsonDataEncoder::encode( + array('disable' => $find_disabled($form)) + ) + ))->save(); + } + } + return true; + } + function save($refetch=false) { if ($this->dirty) $this->updated = SqlFunction::NOW(); @@ -473,3 +524,19 @@ class Topic extends VerySimpleModel { // Add fields from the standard ticket form to the ticket filterable fields Filter::addSupportedMatches(/* @trans */ 'Help Topic', array('topicId' => 'Topic ID'), 100); + +class TopicFormModel extends VerySimpleModel { + static $meta = array( + 'table' => TOPIC_FORM_TABLE, + 'pk' => array('id'), + 'ordering' => array('sort'), + 'joins' => array( + 'topic' => array( + 'constraint' => array('topic_id' => 'Topic.topic_id'), + ), + 'form' => array( + 'constraint' => array('form_id' => 'DynamicForm.id'), + ), + ), + ); +} diff --git a/include/client/open.inc.php b/include/client/open.inc.php index 821aa6ef9cc8661e5126b070dc5d35fedc09d1df..71529516575d3d8b1dbea2d99ac4b7898dea07b4 100644 --- a/include/client/open.inc.php +++ b/include/client/open.inc.php @@ -13,11 +13,14 @@ $form = null; if (!$info['topicId']) $info['topicId'] = $cfg->getDefaultTopicId(); +$forms = array(); if ($info['topicId'] && ($topic=Topic::lookup($info['topicId']))) { - $form = $topic->getForm(); - if ($_POST && $form) { - $form = $form->instanciate(); - $form->isValidForClient(); + foreach ($topic->getForms() as $F) { + if ($_POST) { + $F = $F->instanciate(); + $F->isValidForClient(); + } + $forms[] = $F; } } @@ -29,9 +32,26 @@ if ($info['topicId'] && ($topic=Topic::lookup($info['topicId']))) { <input type="hidden" name="a" value="open"> <table width="800" cellpadding="1" cellspacing="0" border="0"> <tbody> +<?php + if (!$thisclient) { + $uform = UserForm::getUserForm()->getForm($_POST); + if ($_POST) $uform->isValid(); + $uform->render(false); + } + else { ?> + <tr><td colspan="2"><hr /></td></tr> + <tr><td><?php echo __('Email'); ?>:</td><td><?php echo $thisclient->getEmail(); ?></td></tr> + <tr><td><?php echo __('Client'); ?>:</td><td><?php echo $thisclient->getName(); ?></td></tr> + <?php } ?> + </tbody> + <tbody> + <tr><td colspan="2"><hr /> + <div class="form-header" style="margin-bottom:0.5em"> + <b><?php echo __('Help Topic'); ?></b> + </div> + </td></tr> <tr> - <td class="required"><?php echo __('Help Topic');?>:</td> - <td> + <td colspan="2"> <select id="topicId" name="topicId" onchange="javascript: var data = $(':input[name]', '#dynamic-form').serialize(); $.ajax( @@ -59,28 +79,12 @@ if ($info['topicId'] && ($topic=Topic::lookup($info['topicId']))) { <font class="error">* <?php echo $errors['topicId']; ?></font> </td> </tr> -<?php - if (!$thisclient) { - $uform = UserForm::getUserForm()->getForm($_POST); - if ($_POST) $uform->isValid(); - $uform->render(false); - } - else { ?> - <tr><td colspan="2"><hr /></td></tr> - <tr><td><?php echo __('Email'); ?>:</td><td><?php echo $thisclient->getEmail(); ?></td></tr> - <tr><td><?php echo __('Client'); ?>:</td><td><?php echo $thisclient->getName(); ?></td></tr> - <?php } ?> </tbody> <tbody id="dynamic-form"> - <?php if ($form) { + <?php foreach ($forms as $form) { include(CLIENTINC_DIR . 'templates/dynamic-form.tmpl.php'); } ?> </tbody> - <tbody><?php - $tform = TicketForm::getInstance()->getForm($_POST); - if ($_POST) $tform->isValid(); - $tform->render(false); ?> - </tbody> <tbody> <?php if($cfg && $cfg->isCaptchaEnabled() && (!$thisclient || !$thisclient->isValid())) { diff --git a/include/staff/helptopic.inc.php b/include/staff/helptopic.inc.php index 6fb6371bc77cd7a61e03ee1830c950cf2ea72504..c9702d2105347d3e47835ac1acc9cd1952c18b8e 100644 --- a/include/staff/helptopic.inc.php +++ b/include/staff/helptopic.inc.php @@ -10,6 +10,7 @@ if($topic && $_REQUEST['a']!='add') { $info['pid']=$topic->getPid(); $trans['name'] = $topic->getTranslateTag('name'); $qs += array('id' => $topic->getId()); + $forms = $topic->getForms(); } else { $title=__('Add New Help Topic'); $action='create'; @@ -21,22 +22,31 @@ if($topic && $_REQUEST['a']!='add') { } $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); ?> + +<h2 style="font-weight: normal"><?php echo $title; ?> + <i class="help-tip icon-question-sign" href="#help_topic_information"></i> + </h2> +<?php if ($topic) { ?> + <div class="big"><strong><?php echo $topic->getLocal('topic'); ?></strong></div> +<?php } ?> + +<br/> + +<ul class="tabs" id="topic-tabs"> + <li class="active"><a href="#info"><i class="icon-info-sign"></i> Help Topic Information</a></li> + <li><a href="#routing"><i class="icon-ticket"></i> New ticket options</a></li> + <li><a href="#forms"><i class="icon-paste"></i> Forms</a></li> +</ul> + <form action="helptopics.php?<?php echo Http::build_query($qs); ?>" method="post" id="save"> <?php csrf_token(); ?> <input type="hidden" name="do" value="<?php echo $action; ?>"> <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>"> <input type="hidden" name="id" value="<?php echo $info['id']; ?>"> - <h2><?php echo __('Help Topic');?></h2> - <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2"> - <thead> - <tr> - <th colspan="2"> - <h4><?php echo $title; ?></h4> - <em><?php echo __('Help Topic Information');?> - <i class="help-tip icon-question-sign" href="#help_topic_information"></i></em> - </th> - </tr> - </thead> + +<div id="topic-tabs_container"> +<div class="tab_content" id="info"> + <table class="table" border="0" cellspacing="0" cellpadding="2"> <tbody> <tr> <td width="180" class="required"> @@ -53,8 +63,8 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <?php echo __('Status');?>: </td> <td> - <input type="radio" name="isactive" value="1" <?php echo $info['isactive']?'checked="checked"':''; ?>><?php echo __('Active'); ?> - <input type="radio" name="isactive" value="0" <?php echo !$info['isactive']?'checked="checked"':''; ?>><?php echo __('Disabled'); ?> + <input type="radio" name="isactive" value="1" <?php echo $info['isactive']?'checked="checked"':''; ?>> <?php echo __('Active'); ?> + <input type="radio" name="isactive" value="0" <?php echo !$info['isactive']?'checked="checked"':''; ?>> <?php echo __('Disabled'); ?> <span class="error">* </span> <i class="help-tip icon-question-sign" href="#status"></i> </td> </tr> @@ -63,8 +73,8 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <?php echo __('Type');?>: </td> <td> - <input type="radio" name="ispublic" value="1" <?php echo $info['ispublic']?'checked="checked"':''; ?>><?php echo __('Public'); ?> - <input type="radio" name="ispublic" value="0" <?php echo !$info['ispublic']?'checked="checked"':''; ?>><?php echo __('Private/Internal'); ?> + <input type="radio" name="ispublic" value="1" <?php echo $info['ispublic']?'checked="checked"':''; ?>> <?php echo __('Public'); ?> + <input type="radio" name="ispublic" value="0" <?php echo !$info['ispublic']?'checked="checked"':''; ?>> <?php echo __('Private/Internal'); ?> <span class="error">* </span> <i class="help-tip icon-question-sign" href="#type"></i> </td> </tr> @@ -87,28 +97,26 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); </td> </tr> - <tr><th colspan="2"><em><?php echo __('New ticket options');?></em></th></tr> - <tr> - <td><strong><?php echo __('Custom Form'); ?></strong>:</td> - <td><select name="form_id"> - <option value="0" <?php -if ($info['form_id'] == '0') echo 'selected="selected"'; - ?>>— <?php echo __('None'); ?> —</option> - <option value="<?php echo Topic::FORM_USE_PARENT; ?>" <?php -if ($info['form_id'] == Topic::FORM_USE_PARENT) echo 'selected="selected"'; - ?>>— <?php echo __('Use Parent Form'); ?> —</option> - <?php foreach (DynamicForm::objects()->filter(array('type'=>'G')) as $group) { ?> - <option value="<?php echo $group->get('id'); ?>" - <?php if ($group->get('id') == $info['form_id']) - echo 'selected="selected"'; ?>> - <?php echo $group->get('title'); ?> - </option> - <?php } ?> - </select> - <span class="error"> <?php echo $errors['form_id']; ?></span> - <i class="help-tip icon-question-sign" href="#custom_form"></i> - </td> - </tr> + </tbody> + </table> + + <div style="padding:8px 3px;border-bottom: 2px dotted #ddd;"> + <strong class="big"><?php echo __('Internal Notes');?></strong><br/> + <?php echo __("be liberal, they're internal.");?> + </div> + + <textarea class="richtext no-bar" name="notes" cols="21" + rows="8" style="width: 80%;"><?php echo $info['notes']; ?></textarea> + +</div> + +<div class="hidden tab_content" id="routing"> +<div style="padding:8px 0;border-bottom: 2px dotted #ddd;"> +<div><b class="big"><?php echo __('New ticket options');?></b></div> +</div> + + <table class="table" border="0" cellspacing="0" cellpadding="2"> + <tbody> <tr> <td width="180" class="required"> <?php echo __('Department'); ?>: @@ -127,6 +135,62 @@ if ($info['form_id'] == Topic::FORM_USE_PARENT) echo 'selected="selected"'; <i class="help-tip icon-question-sign" href="#department"></i> </td> </tr> + <tr class="border"> + <td> + <?php echo __('Ticket Number Format'); ?>: + </td> + <td> + <label> + <input type="radio" name="custom-numbers" value="0" <?php echo !$info['custom-numbers']?'checked="checked"':''; ?> + onchange="javascript:$('#custom-numbers').hide();"> <?php echo __('System Default'); ?> + </label> <label> + <input type="radio" name="custom-numbers" value="1" <?php echo $info['custom-numbers']?'checked="checked"':''; ?> + onchange="javascript:$('#custom-numbers').show(200);"> <?php echo __('Custom'); ?> + </label> <i class="help-tip icon-question-sign" href="#custom_numbers"></i> + </td> + </tr> + </tbody> + <tbody id="custom-numbers" style="<?php if (!$info['custom-numbers']) echo 'display:none'; ?>"> + <tr> + <td style="padding-left:20px"> + <?php echo __('Format'); ?>: + </td> + <td> + <input type="text" name="number_format" value="<?php echo $info['number_format']; ?>"/> + <span class="faded"><?php echo __('e.g.'); ?> <span id="format-example"><?php + if ($info['custom-numbers']) { + if ($info['sequence_id']) + $seq = Sequence::lookup($info['sequence_id']); + if (!isset($seq)) + $seq = new RandomSequence(); + echo $seq->current($info['number_format']); + } ?></span></span> + <div class="error"><?php echo $errors['number_format']; ?></div> + </td> + </tr> + <tr> +<?php $selected = 'selected="selected"'; ?> + <td style="padding-left:20px"> + <?php echo __('Sequence'); ?>: + </td> + <td> + <select name="sequence_id"> + <option value="0" <?php if ($info['sequence_id'] == 0) echo $selected; + ?>>— <?php echo __('Random'); ?> —</option> +<?php foreach (Sequence::objects() as $s) { ?> + <option value="<?php echo $s->id; ?>" <?php + if ($info['sequence_id'] == $s->id) echo $selected; + ?>><?php echo $s->name; ?></option> +<?php } ?> + </select> + <button class="action-button pull-right" onclick="javascript: + $.dialog('ajax.php/sequence/manage', 205); + return false; + "><i class="icon-gear"></i> <?php echo __('Manage'); ?></button> + </td> + </tr> + </tbody> + <tbody> <tr> <td width="180"> <?php echo __('Status'); ?>: @@ -266,75 +330,90 @@ if ($info['form_id'] == Topic::FORM_USE_PARENT) echo 'selected="selected"'; <i class="help-tip icon-question-sign" href="#ticket_auto_response"></i> </td> </tr> - <tr> - <td> - <?php echo __('Ticket Number Format'); ?>: - </td> - <td> - <label> - <input type="radio" name="custom-numbers" value="0" <?php echo !$info['custom-numbers']?'checked="checked"':''; ?> - onchange="javascript:$('#custom-numbers').hide();"> <?php echo __('System Default'); ?> - </label> <label> - <input type="radio" name="custom-numbers" value="1" <?php echo $info['custom-numbers']?'checked="checked"':''; ?> - onchange="javascript:$('#custom-numbers').show(200);"> <?php echo __('Custom'); ?> - </label> <i class="help-tip icon-question-sign" href="#custom_numbers"></i> - </td> - </tr> </tbody> - <tbody id="custom-numbers" style="<?php if (!$info['custom-numbers']) echo 'display:none'; ?>"> - <tr> - <td style="padding-left:20px"> - <?php echo __('Format'); ?>: - </td> - <td> - <input type="text" name="number_format" value="<?php echo $info['number_format']; ?>"/> - <span class="faded"><?php echo __('e.g.'); ?> <span id="format-example"><?php - if ($info['custom-numbers']) { - if ($info['sequence_id']) - $seq = Sequence::lookup($info['sequence_id']); - if (!isset($seq)) - $seq = new RandomSequence(); - echo $seq->current($info['number_format']); - } ?></span></span> - <div class="error"><?php echo $errors['number_format']; ?></div> - </td> - </tr> + </table> +</div> + +<div class="hidden tab_content" id="forms"> + <table id="topic-forms" class="table" border="0" cellspacing="0" cellpadding="2"> + +<?php foreach ($forms as $F) { ?> + <tbody data-form-id="<?php echo $F->get('id'); ?>"> <tr> -<?php $selected = 'selected="selected"'; ?> - <td style="padding-left:20px"> - <?php echo __('Sequence'); ?>: - </td> - <td> - <select name="sequence_id"> - <option value="0" <?php if ($info['sequence_id'] == 0) echo $selected; - ?>>— <?php echo __('Random'); ?> —</option> -<?php foreach (Sequence::objects() as $s) { ?> - <option value="<?php echo $s->id; ?>" <?php - if ($info['sequence_id'] == $s->id) echo $selected; - ?>><?php echo $s->name; ?></option> + <td class="handle" colspan="6"> + <input type="hidden" name="forms[]" value="<?php echo $F->get('id'); ?>" /> + <div class="pull-right"> + <i class="icon-2x icon-move icon-muted"></i> +<?php if ($F->get('type') != 'T') { ?> + <a href="#" title="<?php echo __('Delete'); ?>" onclick="javascript: + if (confirm(__('You sure?'))) + var tbody = $(this).closest('tbody'); + tbody.fadeOut(function(){this.remove()}); + $(this).closest('form') + .find('[name=form_id] [value=' + tbody.data('formId') + ']') + .prop('disabled', false); + return false;"><i class="icon-2x icon-trash"></i></a> <?php } ?> - </select> - <button class="action-button pull-right" onclick="javascript: - $.dialog('ajax.php/sequence/manage', 205); - return false; - "><i class="icon-gear"></i> <?php echo __('Manage'); ?></button> + </div> + <div><strong><?php echo $F->getLocal('title'); ?></strong></div> + <div><?php echo $F->getLocal('instructions'); ?></div> </td> </tr> - </tbody> - <tbody> <tr> - <th colspan="2"> - <em><strong><?php echo __('Internal Notes');?></strong>: <?php echo __("be liberal, they're internal.");?></em> - </th> + <th><?php echo __('Enable'); ?></th> + <th><?php echo __('Label'); ?></th> + <th><?php echo __('Type'); ?></th> + <th><?php echo __('Visibility'); ?></th> + <th><?php echo __('Variable'); ?></th> </tr> + <?php + foreach ($F->getFields() as $f) { ?> <tr> - <td colspan=2> - <textarea class="richtext no-bar" name="notes" cols="21" - rows="8" style="width: 80%;"><?php echo $info['notes']; ?></textarea> - </td> + <td><input type="checkbox" name="fields[]" value="<?php + echo $f->get('id'); ?>" <?php + if ($f->isEnabled()) echo 'checked="checked"'; ?>/></td> + <td><?php echo $f->get('label'); ?></td> + <td><?php $t=FormField::getFieldType($f->get('type')); echo __($t[0]); ?></td> + <td><?php echo $f->getVisibilityDescription(); ?></td> + <td><?php echo $f->get('name'); ?></td> </tr> + <?php } ?> </tbody> -</table> + <?php } ?> + </table> + + <br/> + <strong><?php echo __('Add Custom Form'); ?></strong>: + <select name="form_id" onchange="javascript: + event.preventDefault(); + var $this = $(this), + val = $this.val(); + if (!val) return; + $.ajax({ + url: 'ajax.php/form/' + val + '/fields/view', + dataType: 'json', + success: function(json) { + if (json.success) { + $(json.html).appendTo('#topic-forms').effect('highlight'); + $this.find(':selected').prop('disabled', true); + } + } + });"> + <option value=""><?php echo '— '.__('Add a custom form') . ' —'; ?></option> + <?php foreach (DynamicForm::objects()->filter(array('type'=>'G')) as $F) { ?> + <option value="<?php echo $F->get('id'); ?>" + <?php if ($F->get('id') == $info['form_id']) + echo 'selected="selected"'; ?>> + <?php echo $F->getLocal('title'); ?> + </option> + <?php } ?> + </select> + <span class="error"> <?php echo $errors['form_id']; ?></span> + <i class="help-tip icon-question-sign" href="#custom_form"></i> +</div> + +</div> + <p style="text-align:center;"> <input type="submit" name="submit" value="<?php echo $submit_text; ?>"> <input type="reset" name="reset" value="<?php echo __('Reset');?>"> @@ -355,4 +434,19 @@ $(function() { $('[name=sequence_id]').on('change', update_example); $('[name=number_format]').on('keyup', update_example); }); +$('table#topic-forms').sortable({ + items: 'tbody', + handle: 'td.handle', + tolerance: 'pointer', + forcePlaceholderSize: true, + helper: function(e, ui) { + ui.children().each(function() { + $(this).children().each(function() { + $(this).width($(this).width()); + }); + }); + ui=ui.clone().css({'background-color':'white', 'opacity':0.8}); + return ui; + } +}); </script> diff --git a/include/staff/templates/dynamic-form.tmpl.php b/include/staff/templates/dynamic-form.tmpl.php index 487ce9a56f863a735abe6808f29a95c56bf2dc9f..6fc7b8978faea9b538a80e55acc6db3b503a0434 100644 --- a/include/staff/templates/dynamic-form.tmpl.php +++ b/include/staff/templates/dynamic-form.tmpl.php @@ -38,6 +38,8 @@ if (isset($options['entry']) && $options['mode'] == 'edit') { ?> } foreach ($form->getFields() as $field) { try { + if (!$field->isEnabled()) + continue; if ($options['mode'] == 'edit' && !$field->isEditableToStaff()) continue; } diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php index fcebc13d474f66469e7eb2e188f55505de61e165..50750cdd0df2c3a7c5d64ea88c83e86bba5c67a7 100644 --- a/include/staff/ticket-open.inc.php +++ b/include/staff/ticket-open.inc.php @@ -9,12 +9,14 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); if (!$info['topicId']) $info['topicId'] = $cfg->getDefaultTopicId(); -$form = null; +$forms = array(); if ($info['topicId'] && ($topic=Topic::lookup($info['topicId']))) { - $form = $topic->getForm(); - if ($_POST && $form) { - $form = $form->instanciate(); - $form->isValid(); + foreach ($topic->getForms() as $F) { + if ($_POST) { + $F = $F->instanciate(); + $F->isValidForClient(); + } + $forms[] = $F; } } @@ -156,9 +158,9 @@ if ($_POST) $id, ($info['topicId']==$id)?'selected="selected"':'', $selected, $name); } - if (count($topics) == 1 && !$form) { + if (count($topics) == 1 && !$forms) { if (($T = Topic::lookup($id))) - $form = $T->getForm(); + $forms = $T->getForms(); } } ?> @@ -260,18 +262,12 @@ if ($_POST) </tbody> <tbody id="dynamic-form"> <?php - if ($form) { + foreach ($forms as $form) { print $form->getForm()->getMedia(); include(STAFFINC_DIR . 'templates/dynamic-form.tmpl.php'); } ?> </tbody> - <tbody> <?php - $tform = TicketForm::getInstance()->getForm($_POST); - if ($_POST) $tform->isValid(); - $tform->render(true); - ?> - </tbody> <tbody> <?php //is the user allowed to post replies?? diff --git a/include/upgrader/streams/core/5cd0a25a-00000000.cleanup.sql b/include/upgrader/streams/core/5cd0a25a-00000000.cleanup.sql new file mode 100644 index 0000000000000000000000000000000000000000..3b391fc4d5cab0d4c779c4d380ae769e2d67ce3d --- /dev/null +++ b/include/upgrader/streams/core/5cd0a25a-00000000.cleanup.sql @@ -0,0 +1,8 @@ +/** + * @signature 0e47d678f50874fa0d33e1e3759f657e + * @version v1.9.6 + * @title Make fields disable-able per help topic + */ + +ALTER TABLE `%TABLE_PREFIX%help_topic` + DROP `form_id` int(10) unsigned NOT NULL default '0'; diff --git a/include/upgrader/streams/core/5cd0a25a-00000000.patch.sql b/include/upgrader/streams/core/5cd0a25a-00000000.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..58e4fdfc2fd7e139cb432937efbd0fe4f318249c --- /dev/null +++ b/include/upgrader/streams/core/5cd0a25a-00000000.patch.sql @@ -0,0 +1,45 @@ +/** + * @signature 0e47d678f50874fa0d33e1e3759f657e + * @version v1.9.6 + * @title Make fields disable-able per help topic + */ + +ALTER TABLE `%TABLE_PREFIX%form` + ADD `pid` int(10) unsigned DEFAULT NULL AFTER `id`, + ADD `name` varchar(64) NOT NULL DEFAULT '' AFTER `instructions`; + +ALTER TABLE `%TABLE_PREFIX%form_entry` + ADD `extra` text AFTER `sort`; + +CREATE TABLE `%TABLE_PREFIX%help_topic_form` ( + `id` int(11) unsigned NOT NULL auto_increment, + `topic_id` int(11) unsigned NOT NULL default 0, + `form_id` int(10) unsigned NOT NULL default 0, + `sort` int(10) unsigned NOT NULL default 1, + `extra` text, + PRIMARY KEY (`topic_id`, `form_id`) +) DEFAULT CHARSET=utf8; + +insert into `%TABLE_PREFIX%help_topic_form` + (`topic_id`, `form_id`, `sort`) + select A1.topic_id, case + when A2.form_id = 4294967295 then A3.form_id + when A1.form_id = 4294967295 then A2.form_id + else A1.form_id end as form_id, 1 as `sort` + from `%TABLE_PREFIX%help_topic` A1 + left join `%TABLE_PREFIX%help_topic` A2 on (A2.topic_pid = A1.topic_id) + left join `%TABLE_PREFIX%help_topic` A3 on (A3.topic_pid = A2.topic_id) + having `form_id` > 0 + union + select A2.topic_id, id as `form_id`, 2 as `sort` + from `%TABLE_PREFIX%form` A1 + join `%TABLE_PREFIX%help_topic` A2 + where A1.`type` = 'T'; + +ALTER TABLE `%TABLE_PREFIX%help_topic` + DROP `form_id` int(10) unsigned NOT NULL default '0'; + +-- Finished with patch +UPDATE `%TABLE_PREFIX%config` + SET `value` = '0e47d678f50874fa0d33e1e3759f657e' + WHERE `key` = 'schema_signature' AND `namespace` = 'core'; diff --git a/scp/ajax.php b/scp/ajax.php index 131243adeb18c39b487631bcb9c5aee7b50044c1..79dd8e1b384456df05a05373c4887f99cd7d0098 100644 --- a/scp/ajax.php +++ b/scp/ajax.php @@ -57,7 +57,8 @@ $dispatcher = patterns('', url_post('^field-config/(?P<id>\d+)$', 'saveFieldConfiguration'), url_delete('^answer/(?P<entry>\d+)/(?P<field>\d+)$', 'deleteAnswer'), url_post('^upload/(\d+)?$', 'upload'), - url_post('^upload/(\w+)?$', 'attach') + url_post('^upload/(\w+)?$', 'attach'), + url_get('^(?P<id>\d+)/fields/view$', 'getAllFields') )), url('^/list/', patterns('ajax.forms.php:DynamicFormsAjaxAPI', url_get('^(?P<list>\w+)/item/(?P<id>\d+)/properties$', 'getListItemProperties'), diff --git a/scp/css/scp.css b/scp/css/scp.css index 0d76bf2ba467afd9ff21f10e99c9f039bdc3fb2e..4773680839f8c5f349e6c2fc6090ef7a8b803464 100644 --- a/scp/css/scp.css +++ b/scp/css/scp.css @@ -51,6 +51,10 @@ div#header a { clear:both; } +.big { + font-size: 110%; +} + .faded { color:#666; } @@ -589,6 +593,27 @@ a.print { padding:2px; } +.table { + width: 100%; + border-collapse: collapse; + margin-top:3px; +} + +.table tr.header td, +.table th { + font-weight: bold; + text-align: left; + height: 24px; + background: #f0f0f0; +} + +.table tr { + border-bottom:1px dotted #ddd; +} +.table td:not(:empty) { + height: 24px; +} + .form_table { margin-top:3px; border-left:1px solid #ddd; diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql index 124b65afbb7316e046f27a427bd569048d25a17f..738df56ce9521c2a087d5aa04f326b89cff14f0d 100644 --- a/setup/inc/streams/core/install-mysql.sql +++ b/setup/inc/streams/core/install-mysql.sql @@ -115,10 +115,12 @@ INSERT INTO `%TABLE_PREFIX%config` (`namespace`, `key`, `value`) VALUES DROP TABLE IF EXISTS `%TABLE_PREFIX%form`; CREATE TABLE `%TABLE_PREFIX%form` ( `id` int(11) unsigned NOT NULL auto_increment, + `pid` int(10) unsigned DEFAULT NULL, `type` varchar(8) NOT NULL DEFAULT 'G', `deletable` tinyint(1) NOT NULL DEFAULT 1, `title` varchar(255) NOT NULL, `instructions` varchar(512), + `name` varchar(64) NOT NULL DEFAULT '', `notes` text, `created` datetime NOT NULL, `updated` datetime NOT NULL, @@ -151,6 +153,7 @@ CREATE TABLE `%TABLE_PREFIX%form_entry` ( `object_id` int(11) unsigned, `object_type` char(1) NOT NULL DEFAULT 'T', `sort` int(11) unsigned NOT NULL DEFAULT 1, + `extra` text, `created` datetime NOT NULL, `updated` datetime NOT NULL, PRIMARY KEY (`id`), @@ -443,7 +446,6 @@ CREATE TABLE `%TABLE_PREFIX%help_topic` ( `team_id` int(10) unsigned NOT NULL default '0', `sla_id` int(10) unsigned NOT NULL default '0', `page_id` int(10) unsigned NOT NULL default '0', - `form_id` int(10) unsigned NOT NULL default '0', `sequence_id` int(10) unsigned NOT NULL DEFAULT '0', `sort` int(10) unsigned NOT NULL default '0', `topic` varchar(32) NOT NULL default '', @@ -461,6 +463,16 @@ CREATE TABLE `%TABLE_PREFIX%help_topic` ( KEY `page_id` (`page_id`) ) DEFAULT CHARSET=utf8; +DROP TABLE IF EXISTS `%TABLE_PREFIX%help_topic_form`; +CREATE TABLE `%TABLE_PREFIX%help_topic_form` ( + `id` int(11) unsigned NOT NULL auto_increment, + `topic_id` int(11) unsigned NOT NULL default 0, + `form_id` int(10) unsigned NOT NULL default 0, + `sort` int(10) unsigned NOT NULL default 1, + `extra` text, + PRIMARY KEY (`topic_id`, `form_id`) +) DEFAULT CHARSET=utf8; + DROP TABLE IF EXISTS `%TABLE_PREFIX%organization`; CREATE TABLE `%TABLE_PREFIX%organization` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT,