diff --git a/include/ajax.forms.php b/include/ajax.forms.php
index 2142e8e4faa947b5060539e79a8ef9d2b535025a..1ec760b077e1c934ee13cffa568147eb22897344 100644
--- a/include/ajax.forms.php
+++ b/include/ajax.forms.php
@@ -36,5 +36,19 @@ class DynamicFormsAjaxAPI extends AjaxController {
         else
             $field->save();
     }
+
+    function deleteAnswer($entry_id, $field_id) {
+        global $thisstaff;
+
+        if (!$thisstaff)
+            Http::response(403, 'Login required');
+
+        $ent = DynamicFormEntryAnswer::lookup(array(
+            'entry_id'=>$entry_id, 'field_id'=>$field_id));
+        if (!$ent)
+            Http::response(404, 'Answer not found');
+
+        $ent->delete();
+    }
 }
 ?>
diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php
index 248ee66d2210156f25ce120e18e603af91484c3e..6869fe7076d668b578d097490dc464553b40b8a3 100644
--- a/include/ajax.tickets.php
+++ b/include/ajax.tickets.php
@@ -611,5 +611,51 @@ class TicketsAjaxAPI extends AjaxController {
 
     }
 
+    function manageForms($ticket_id) {
+        include(STAFFINC_DIR . 'templates/form-manage.tmpl.php');
+    }
+
+    function updateForms($ticket_id) {
+        global $thisstaff;
+
+        if (!$thisstaff)
+            Http::response(403, "Login required");
+        elseif (!($ticket = Ticket::lookup($ticket_id)))
+            Http::response(404, "No such ticket");
+        elseif (!$ticket->checkStaffAccess($thisstaff))
+            Http::response(403, "Access Denied");
+        elseif (!isset($_POST['forms']))
+            Http::response(422, "Send updated forms list");
+
+        // Add new forms
+        $forms = DynamicFormEntry::forTicket($ticket_id);
+        foreach ($_POST['forms'] as $sort => $id) {
+            $found = false;
+            foreach ($forms as $e) {
+                if ($e->get('form_id') == $id) {
+                    $e->set('sort', $sort);
+                    $e->save();
+                    $found = true;
+                    break;
+                }
+            }
+            // New form added
+            if (!$found && ($new = DynamicForm::lookup($id))) {
+                $f = $new->instanciate();
+                $f->set('sort', $sort);
+                $f->setTicketId($ticket_id);
+                $f->save();
+            }
+        }
+
+        // Deleted forms
+        foreach ($forms as $idx => $e) {
+            if (!in_array($e->get('form_id'), $_POST['forms']))
+                $e->delete();
+        }
+
+        Http::response(201, 'Successfully managed');
+    }
+
 }
 ?>
diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php
index c58a22f4644e3d768caf172579fe5b2c2310ff4a..c1b790ccb46410923fcd11364539bd0ed057ad4a 100644
--- a/include/class.dynamic_forms.php
+++ b/include/class.dynamic_forms.php
@@ -457,6 +457,10 @@ class DynamicFormEntry extends VerySimpleModel {
     var $_errors = false;
     var $_clean = false;
 
+    function getId() {
+        return $this->get('id');
+    }
+
     function getAnswers() {
         if (!isset($this->_values)) {
             $this->_values = DynamicFormEntryAnswer::objects()
@@ -579,8 +583,8 @@ class DynamicFormEntry extends VerySimpleModel {
             ->filter(array('object_id'=>$org_id, 'object_type'=>'O'));
     }
 
-    function render($staff=true, $title=false) {
-        return $this->getForm()->render($staff, $title);
+    function render($staff=true, $title=false, $options=array()) {
+        return $this->getForm()->render($staff, $title, $options);
     }
 
     /**
@@ -592,11 +596,15 @@ class DynamicFormEntry extends VerySimpleModel {
      * entry.
      */
     function addMissingFields() {
+        // Track deletions
+        foreach ($this->getAnswers() as $answer)
+            $answer->deleted = true;
+
         foreach ($this->getForm()->getDynamicFields() as $field) {
             $found = false;
             foreach ($this->getAnswers() as $answer) {
                 if ($answer->get('field_id') == $field->get('id')) {
-                    $found = true; break;
+                    $answer->deleted = false; $found = true; break;
                 }
             }
             if (!$found && ($field = $field->getImpl($field))
@@ -605,6 +613,7 @@ class DynamicFormEntry extends VerySimpleModel {
                     array('field_id'=>$field->get('id'), 'entry_id'=>$this->id));
                 $a->field = $field;
                 $a->entry = $this;
+                $a->deleted = false;
                 // Add to list of answers
                 $this->_values[] = $a;
                 $this->_fields[] = $field;
@@ -710,6 +719,7 @@ class DynamicFormEntryAnswer extends VerySimpleModel {
     var $field;
     var $form;
     var $entry;
+    var $deleted = false;
     var $_value;
 
     function getEntry() {
@@ -742,6 +752,10 @@ class DynamicFormEntryAnswer extends VerySimpleModel {
         return $this->get('value_id');
     }
 
+    function isDeleted() {
+        return $this->deleted;
+    }
+
     function toString() {
         return $this->getField()->toString($this->getValue());
     }
diff --git a/include/class.forms.php b/include/class.forms.php
index 42f4651a1debd6fd0234244ef6f9f1f6aec10ea7..4eeed67e73c36e51ae944873698a701eb34b4a1e 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -99,11 +99,11 @@ class Form {
         return $this->_errors;
     }
 
-    function render($staff=true, $title=false, $instructions=false) {
+    function render($staff=true, $title=false, $options=array()) {
         if ($title)
             $this->title = $title;
-        if ($instructions)
-            $this->instructions = $instructions;
+        if (isset($options['instructions']))
+            $this->instructions = $options['instructions'];
         $form = $this;
         if ($staff)
             include(STAFFINC_DIR . 'templates/dynamic-form.tmpl.php');
diff --git a/include/class.orm.php b/include/class.orm.php
index cdf25599501b82e474893d2ccca18823804d38f1..ef04e3d3e9bb7bb2412c074e9c73e2c57d3d9157 100644
--- a/include/class.orm.php
+++ b/include/class.orm.php
@@ -319,6 +319,14 @@ class QuerySet implements IteratorAggregate, ArrayAccess {
         return $this->count() > 0;
     }
 
+    function delete() {
+        $class = $this->compiler;
+        $compiler = new $class();
+        $ex = $compiler->compileDelete($this);
+        $ex->execute();
+        return $ex->affected_rows();
+    }
+
     // IteratorAggregate interface
     function getIterator() {
         $class = $this->iterator;
@@ -863,7 +871,28 @@ class MySqlCompiler extends SqlCompiler {
     function compileInsert() {
     }
 
-    function compileDelete() {
+    function compileDelete($queryset) {
+        $model = $queryset->model;
+        $table = $model::$meta['table'];
+        $where_pos = array();
+        $where_neg = array();
+        $joins = array();
+        foreach ($queryset->constraints as $where) {
+            $where_pos[] = $this->compileWhere($where, $model);
+        }
+        foreach ($queryset->exclusions as $where) {
+            $where_neg[] = $this->compileWhere($where, $model);
+        }
+
+        $where = '';
+        if ($where_pos || $where_neg) {
+            $where = ' WHERE '.implode(' AND ', $where_pos)
+                .implode(' AND NOT ', $where_neg);
+        }
+        $joins = $this->getJoins();
+        $sql = 'DELETE '.$this->quote($table).'.* FROM '
+            .$this->quote($table).$joins.$where;
+        return new MysqlExecutor($sql, $this->params);
     }
 
     // Returns meta data about the table used to build queries
@@ -885,14 +914,18 @@ class MysqlExecutor {
     }
 
     function _prepare() {
+        $this->execute();
+        $this->_setup_output();
+        $this->stmt->store_result();
+    }
+
+    function execute() {
         if (!($this->stmt = db_prepare($this->sql)))
             throw new Exception('Unable to prepare query: '.db_error()
                 .' '.$this->sql);
         if (count($this->params))
             $this->_bind($this->params);
-        $this->stmt->execute();
-        $this->_setup_output();
-        $this->stmt->store_result();
+        return $this->stmt->execute();
     }
 
     function _bind($params) {
@@ -997,6 +1030,14 @@ class MysqlExecutor {
         $this->stmt = null;
     }
 
+    function affected_rows() {
+        return $this->stmt->affected_rows;
+    }
+
+    function insert_id() {
+        return $this->stmt->insert_id;
+    }
+
     function __toString() {
         return $this->sql;
     }
diff --git a/include/staff/dynamic-form.inc.php b/include/staff/dynamic-form.inc.php
index a565e1be5bf5e0b8e51523afaaf8be4d181460b7..86adb1c1315d69c587afaf3ec16e164431fc69be 100644
--- a/include/staff/dynamic-form.inc.php
+++ b/include/staff/dynamic-form.inc.php
@@ -16,7 +16,7 @@ if($form && $_REQUEST['a']!='add') {
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 
 ?>
-<form action="?id=<?php echo urlencode($_REQUEST['id']); ?>" method="post" id="save">
+<form id="manage-form" action="?id=<?php echo urlencode($_REQUEST['id']); ?>" method="post">
     <?php csrf_token(); ?>
     <input type="hidden" name="do" value="<?php echo $action; ?>">
     <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
@@ -167,7 +167,9 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     if ($ferrors['name']) echo '<br/>'; echo $ferrors['name'];
                 ?></font>
                 </td>
-            <td><input type="checkbox" name="delete-<?php echo $id; ?>"
+            <td><input class="delete-box" type="checkbox" name="delete-<?php echo $id; ?>"
+                    data-field-label="<?php echo $f->get('label'); ?>"
+                    data-field-id="<?php echo $id; ?>"
                     <?php echo $deletable; ?>/>
                 <input type="hidden" name="sort-<?php echo $id; ?>"
                     value="<?php echo $f->get('sort'); ?>"/>
@@ -228,8 +230,63 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
     <input type="reset"  name="reset"  value="Reset">
     <input type="button" name="cancel" value="Cancel" onclick='window.location.href="?"'>
 </p>
+
+<div style="display:none;" class="draggable dialog" id="delete-confirm">
+    <h3><i class="icon-trash"></i> Remove Existing Data?</h3>
+    <a class="close" href=""><i class="icon-remove-circle"></i></a>
+    <hr/>
+    <p>
+        <strong>You are about to delete <span id="deleted-count"></span> fields.</strong>
+        Would you also like to remove data currently entered for this field?
+        <em>If you opt not to remove the data now, you will have the option
+        to delete the the data when editing it</em>
+    </p><p style="color:red">
+        Deleted data CANNOT be recovered.
+    </p>
+    <hr>
+    <div id="deleted-fields"></div>
+    <hr style="margin-top:1em"/>
+    <p class="full-width">
+        <span class="buttons" style="float:left">
+            <input type="button" value="No, Cancel" class="close">
+        </span>
+        <span class="buttons" style="float:right">
+            <input type="submit" value="Continue" class="confirm">
+        </span>
+     </p>
+    <div class="clear"></div>
+</div>
 </form>
 
 <div style="display:none;" class="dialog draggable" id="field-config">
     <div class="body"></div>
 </div>
+
+<script type="text/javascript">
+$('#manage-form').on('submit.inline', function() {
+    var formObj = this, deleted = $('input.delete-box:checked', this);
+    if (deleted.length) {
+        $('#overlay').show();
+        $('#deleted-fields').empty();
+        deleted.each(function(i, e) {
+            $('#deleted-fields').append($('<p></p>')
+                .append($('<input/>').attr({type:'checkbox',name:'delete-data-'
+                    + $(e).data('fieldId')})
+                ).append($('<strong>').html(
+                    'Remove all data entered for <u>' + $(e).data('fieldLabel') + '</u>'
+                ))
+            );
+        });
+        $('#delete-confirm').show().delegate('input.confirm', 'click.confirm', function() {
+            $('.dialog#delete-confirm').hide();
+            $(formObj).unbind('submit.inline');
+            $(window).unbind('beforeunload');
+            $('#loading').show();
+        })
+        return false;
+    }
+    // TODO: Popup the 'please wait' dialog
+    $(window).unbind('beforeunload');
+    $('#loading').show();
+});
+</script>
diff --git a/include/staff/templates/dynamic-form.tmpl.php b/include/staff/templates/dynamic-form.tmpl.php
index 09d97ab650ab3d79df393153cda76fb999eeb980..e6afae15a37d7b1ebb80eafa8fb1e341e6c98672 100644
--- a/include/staff/templates/dynamic-form.tmpl.php
+++ b/include/staff/templates/dynamic-form.tmpl.php
@@ -1,8 +1,35 @@
-<tr><td style="width:150px"></td><td></td></tr>
+<?php
+// If the form was removed using the trashcan option, and there was some
+// other validation error, don't render the deleted form the second time
+if (isset($options['entry']) && $options['mode'] == 'edit'
+    && $_POST
+    && ($_POST['forms'] && !in_array($options['entry']->getId(), $_POST['forms']))
+)
+    return;
+?>
+<tbody>
+<?php
+// Keep up with the entry id in a hidden field to decide what to add and
+// delete when the parent form is submitted
+if (isset($options['entry']) && $options['mode'] == 'edit') { ?>
+    <input type="hidden" name="forms[]" value="<?php
+        echo $options['entry']->getId(); ?>" />
+<?php } ?>
 <?php if ($form->getTitle()) { ?>
     <tr><th colspan="2">
         <em><strong><?php echo Format::htmlchars($form->getTitle()); ?></strong>:
-        <?php echo Format::htmlchars($form->getInstructions()); ?></em>
+        <?php echo Format::htmlchars($form->getInstructions()); ?>
+<?php if ($options['mode'] == 'edit') { ?>
+        <div class="pull-right">
+    <?php if ($options['entry']
+                && $options['entry']->getForm()->get('type') == 'G') { ?>
+            <a href="#" title="Delete Entry" onclick="javascript:
+                $(this).closest('tbody').remove();
+                return false;"><i class="icon-trash"></i></a>&nbsp;
+    <?php } ?>
+            <i class="icon-sort" title="Drag to Sort"></i>
+        </div>
+<?php } ?></em>
     </th></tr>
     <?php
     }
@@ -13,15 +40,33 @@
                 <?php
             }
             else { ?>
-                <td class="multi-line <?php if ($field->get('required')) echo 'required'; ?>" style="min-width:120px;">
+                <td class="multi-line <?php if ($field->get('required')) echo 'required';
+                ?>" style="min-width:120px;" <?php if ($options['width'])
+                    echo "width=\"{$options['width']}\""; ?>>
                 <?php echo Format::htmlchars($field->get('label')); ?>:</td>
-                <td><?php
+                <td><div style="position:relative"><?php
             }
             $field->render(); ?>
             <?php if ($field->get('required')) { ?>
                 <font class="error">*</font>
             <?php
             }
+            if (($a = $field->getAnswer()) && $a->isDeleted()) {
+                ?><a class="action-button danger overlay" title="Delete this data"
+                    href="#delete-answer"
+                    onclick="javascript:if (confirm('You sure?'))
+                        $.ajax({
+                            url: 'ajax.php/form/answer/'
+                                +$(this).data('entryId') + '/' + $(this).data('fieldId'),
+                            type: 'delete',
+                            success: $.proxy(function() {
+                                $(this).closest('tr').fadeOut();
+                            }, this)
+                        });"
+                    data-field-id="<?php echo $field->getAnswer()->get('field_id');
+                ?>" data-entry-id="<?php echo $field->getAnswer()->get('entry_id');
+                ?>"> <i class="icon-trash"></i> </a></div><?php
+            }
             if ($field->get('hint') && !$field->isBlockLevel()) { ?>
                 <br /><em style="color:gray;display:inline-block"><?php
                     echo Format::htmlchars($field->get('hint')); ?></em>
@@ -31,8 +76,7 @@
                 <br />
                 <font class="error"><?php echo Format::htmlchars($e); ?></font>
             <?php } ?>
-            </td>
+            </div></td>
         </tr>
-        <?php
-    }
-?>
+    <?php } ?>
+</tbody>
diff --git a/include/staff/templates/form-manage.tmpl.php b/include/staff/templates/form-manage.tmpl.php
new file mode 100644
index 0000000000000000000000000000000000000000..5e59011df9c12931f013395dbaa11920e0a1214f
--- /dev/null
+++ b/include/staff/templates/form-manage.tmpl.php
@@ -0,0 +1,77 @@
+<h3><i class="icon-paste"></i> Manage Forms</i></h3>
+<b><a class="close" href="#"><i class="icon-remove-circle"></i></a></b>
+<hr/>
+Sort the forms on this ticket by click and dragging on them. Use the box
+below the forms list to add new forms to the ticket.
+<br/>
+<br/>
+<form method="post" action="#tickets/<?php echo $ticket_id; ?>/forms/manage">
+<div id="ticket-entries">
+<?php
+$current_list = array();
+foreach (DynamicFormEntry::forTicket($ticket_id) as $e) { ?>
+<div class="sortable-row-item" data-id="<?php echo $e->get('id'); ?>">
+    <input type="hidden" name="forms[]" value="<?php echo $e->get('form_id'); ?>" />
+    <i class="icon-reorder"></i> <?php echo $e->getForm()->getTitle();
+    $current_list[] = $e->get('form_id');
+    if ($e->getForm()->get('type') == 'G') { ?>
+    <div class="delete"><a href="#"><i class="icon-trash"></i></a></div>
+    <?php } ?>
+</div>
+<?php } ?>
+</div>
+<hr/>
+<i class="icon-plus"></i>&nbsp;
+<select name="new-form" onchange="javascript:
+    var $sel = $(this).find('option:selected');
+    $('#ticket-entries').append($('<div></div>').addClass('sortable-row-item')
+        .text(' '+$sel.text())
+        .data('id', $sel.val())
+        .prepend($('<i>').addClass('icon-reorder'))
+        .append($('<input/>').attr({name:'forms[]', type:'hidden'}).val($sel.val()))
+        .append($('<div></div>').addClass('delete')
+            .append($('<a href=\'#\'>').append($('<i>').addClass('icon-trash')))
+        )
+    );
+    $sel.prop('disabled',true);">
+<option selected="selected" disabled="disabled">Add a new form to this ticket</option>
+<?php foreach (DynamicForm::objects()->filter(array(
+    'type'=>'G')) as $f
+) {
+    if (in_array($f->get('id'), $current_list))
+        continue;
+    ?><option value="<?php echo $f->get('id'); ?>"><?php
+    echo $f->getTitle(); ?></option><?php
+} ?>
+</select>
+<div id="delete-warning" style="display:none">
+<hr>
+    <div id="msg_warning">
+    Clicking <strong>Save Changes</strong> will permanently delete data
+    associated with the deleted forms
+    </div>
+</div>
+    <hr>
+    <p class="full-width">
+        <span class="buttons" style="float:left">
+            <input type="reset" value="Reset">
+            <input type="button" name="cancel" class="<?php echo $user ? 'cancel' : 'close' ?>"  value="Cancel">
+        </span>
+        <span class="buttons" style="float:right">
+            <input type="submit" value="Save Changes">
+        </span>
+     </p>
+
+<script type="text/javascript">
+$(function() {
+    $('#ticket-entries').sortable({containment:'parent',tolerance:'pointer'});
+    $('#ticket-entries .delete a').live('click', function() {
+        var $div = $(this).closest('.sortable-row-item');
+        $('select[name=new-form]').find('option[data-id='+$div.data('id')+']')
+            .prop('disabled',false);
+        $div.remove();
+        $('#delete-warning').show();
+        return false;
+    })
+});
+</script>
diff --git a/include/staff/ticket-edit.inc.php b/include/staff/ticket-edit.inc.php
index e60f275c2633c237a51f91eeab1b048bf0abf980..299835b3734d270cbd9e62a73d7fc73bf872c329 100644
--- a/include/staff/ticket-edit.inc.php
+++ b/include/staff/ticket-edit.inc.php
@@ -128,14 +128,16 @@ if ($_POST)
                 <em>Time is based on your time zone (GMT <?php echo $thisstaff->getTZoffset(); ?>)</em>
             </td>
         </tr>
-        </tbody>
-        <tbody id="dynamic-form">
+    </tbody>
+</table>
+<table class="form_table dynamic-forms" width="940" border="0" cellspacing="0" cellpadding="2">
         <?php if ($forms)
             foreach ($forms as $form) {
-                $form->render(true);
+                $form->render(true, false, array('mode'=>'edit','width'=>160,'entry'=>$form));
         } ?>
-        </tbody>
-        <tbody>
+</table>
+<table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2">
+    <tbody>
         <tr>
             <th colspan="2">
                 <em><strong>Internal Note</strong>: Reason for editing the ticket (required) <font class="error">&nbsp;<?php echo $errors['note'];?></font></em>
@@ -159,3 +161,18 @@ if ($_POST)
 <div style="display:none;" class="dialog draggable" id="user-lookup">
     <div class="body"></div>
 </div>
+<script type="text/javascript">
+$('table.dynamic-forms').sortable({
+  items: 'tbody',
+  handle: 'th',
+  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/ticket-view.inc.php b/include/staff/ticket-view.inc.php
index fc636f515dee5388adaa6ee20d554137238f3b0a..d2c8ebe9a72cc4c88c2ef56ab230bf9236b0814b 100644
--- a/include/staff/ticket-view.inc.php
+++ b/include/staff/ticket-view.inc.php
@@ -107,9 +107,14 @@ if($ticket->isOverdue())
                         <li><a class="confirm-action" id="ticket-answered" href="#answered"><i class="icon-circle-arrow-right"></i> Mark as Answered</a></li>
                     <?php
                     }
-                }
+                } ?>
+                <li><a href="#ajax.php/tickets/<?php echo $ticket->getId();
+                    ?>/forms/manage" onclick="javascript:
+                    $.dialog($(this).attr('href').substr(1), 201);
+                    return false"
+                    ><i class="icon-paste"></i> Manage Forms</a></li>
 
-                if($thisstaff->canBanEmails()) {
+<?php           if($thisstaff->canBanEmails()) {
                      if(!$emailBanned) {?>
                         <li><a class="confirm-action" id="ticket-banemail"
                             href="#banemail"><i class="icon-ban-circle"></i> Ban Email (<?php echo $ticket->getEmail(); ?>)</a></li>
diff --git a/scp/ajax.php b/scp/ajax.php
index b13822d17c0ebefd04d02a89d4af76c79d8c9980..5d12a8b43ebc215fce392f197b203bf842cfd1ec 100644
--- a/scp/ajax.php
+++ b/scp/ajax.php
@@ -53,7 +53,8 @@ $dispatcher = patterns('',
     url('^/form/', patterns('ajax.forms.php:DynamicFormsAjaxAPI',
         url_get('^help-topic/(?P<id>\d+)$', 'getFormsForHelpTopic'),
         url_get('^field-config/(?P<id>\d+)$', 'getFieldConfiguration'),
-        url_post('^field-config/(?P<id>\d+)$', 'saveFieldConfiguration')
+        url_post('^field-config/(?P<id>\d+)$', 'saveFieldConfiguration'),
+        url_delete('^answer/(?P<entry>\d+)/(?P<field>\d+)$', 'deleteAnswer')
     )),
     url('^/report/overview/', patterns('ajax.reports.php:OverviewReportAjaxAPI',
         # Send
@@ -117,7 +118,9 @@ $dispatcher = patterns('',
         url_get('^(?P<tid>\d+)/add-collaborator/auth:(?P<bk>\w+):(?P<id>.+)$', 'addRemoteCollaborator'),
         url('^(?P<tid>\d+)/add-collaborator$', 'addCollaborator'),
         url_get('^lookup', 'lookup'),
-        url_get('^search', 'search')
+        url_get('^search', 'search'),
+        url_get('^(?P<tid>\d+)/forms/manage$', 'manageForms'),
+        url_post('^(?P<tid>\d+)/forms/manage$', 'updateForms')
     )),
     url('^/collaborators/', patterns('ajax.tickets.php:TicketsAjaxAPI',
         url_get('^(?P<cid>\d+)/view$', 'viewCollaborator'),
diff --git a/scp/css/scp.css b/scp/css/scp.css
index 50bea7ea4bc26d2cc5634889b0ff35e6c9ec3d34..55b706178234fb2d8a20134cbb55f35553176d2c 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -1559,3 +1559,73 @@ div.selected-signature {
 div.selected-signature .inner {
     opacity: 0.5;
 }
+
+.action-button.danger:hover {
+    opacity: 1.0;
+    border-color: rgba(95,75,0,0.8) !important;
+    background: #fc9f41; /* Old browsers */
+    color: rgba(255,255,255,0.8) !important;
+    /* IE9 SVG, needs conditional override of 'filter' to 'none' */
+    background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZjOWY0MSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNjZTgxMTQiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);
+    background: -moz-linear-gradient(top,  #fc9f41 0%, #ce8114 100%); /* FF3.6+ */
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fc9f41), color-stop(100%,#ce8114)); /* Chrome,Safari4+ */
+    background: -webkit-linear-gradient(top,  #fc9f41 0%,#ce8114 100%); /* Chrome10+,Safari5.1+ */
+    background: -o-linear-gradient(top,  #fc9f41 0%,#ce8114 100%); /* Opera 11.10+ */
+    background: -ms-linear-gradient(top,  #fc9f41 0%,#ce8114 100%); /* IE10+ */
+    background: linear-gradient(to bottom,  #fc9f41 0%,#ce8114 100%); /* W3C */
+    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fc9f41', endColorstr='#ce8114',GradientType=0 ); /* IE6-8 */
+}
+.action-button.danger {
+    color: #999 !important;
+    background: transparent;
+    border: 1px solid rgba(0,0,0,0.5);
+    opacity: 0.6;
+}
+
+.action-button.overlay {
+    float: none;
+    position: absolute;
+    top: 4px;
+    right: 5px;
+}
+
+.sortable-row-item {
+    border: 1px solid rgba(0, 0, 0, 0.7);
+    padding: 9px;
+    cursor: move;
+    position: relative;
+}
+.sortable-row-item:hover {
+    background: rgba(0, 0, 0, 0.1);
+}
+.sortable-row-item:active {
+    background: rgba(0, 0, 0, 0.3);
+}
+.sortable-row-item:first-child {
+    border-top-right-radius: 5px;
+    border-top-left-radius: 5px;
+}
+.sortable-row-item:last-child {
+    border-bottom-right-radius: 5px;
+    border-bottom-left-radius: 5px;
+}
+.sortable-row-item + .sortable-row-item {
+    margin-top: -1px;
+}
+
+.sortable-row-item .delete {
+    border-left: 1px solid rgba(0, 0, 0, 0.7);
+    border-top-right-radius: inherit;
+    border-bottom-right-radius: inherit;
+    position: absolute;
+    top: 0px;
+    right: 0;
+    padding: 9px;
+    padding-left: 12px;
+    font-size: 105%;
+}
+
+.sortable-row-item .delete:hover {
+    background: #fc9f41; /* Old browsers */
+    color: rgba(255,255,255,0.8) !important;
+}
diff --git a/scp/forms.php b/scp/forms.php
index 077b3e0ff409c5b84b0fa6babd4751ad775efad1..43e66242aa85f55ea2baad290a9fa29369990055 100644
--- a/scp/forms.php
+++ b/scp/forms.php
@@ -23,6 +23,11 @@ if($_POST) {
             foreach ($form->getDynamicFields() as $field) {
                 $id = $field->get('id');
                 if ($_POST["delete-$id"] == 'on' && $field->isDeletable()) {
+                    if ($_POST["delete-data-$id"]) {
+                        DynamicFormEntryAnswer::objects()
+                            ->filter(array('field_id'=>$id))
+                            ->delete();
+                    }
                     $field->delete();
                     // Don't bother updating the field
                     continue;
diff --git a/scp/tickets.php b/scp/tickets.php
index f679f5035a2355ef80482f4a8084f09975c25427..2a8c9e6ee4938a4a19ea57812c0a5559499f4255 100644
--- a/scp/tickets.php
+++ b/scp/tickets.php
@@ -198,16 +198,30 @@ if($_POST && !$errors):
         case 'edit':
         case 'update':
             $forms=DynamicFormEntry::forTicket($ticket->getId());
-            foreach ($forms as $form)
-                if (!$form->isValid())
+            foreach ($forms as $form) {
+                // Don't validate deleted forms
+                if (!in_array($form->getId(), $_POST['forms']))
+                    continue;
+                elseif (!$form->isValid())
                     $errors = array_merge($errors, $form->errors());
+            }
             if(!$ticket || !$thisstaff->canEditTickets())
                 $errors['err']='Permission Denied. You are not allowed to edit tickets';
             elseif($ticket->update($_POST,$errors)) {
                 $msg='Ticket updated successfully';
                 $_REQUEST['a'] = null; //Clear edit action - going back to view.
                 //Check to make sure the staff STILL has access post-update (e.g dept change).
-                foreach ($forms as $f) $f->save();
+                foreach ($forms as $f) {
+                    // Drop deleted forms
+                    $idx = array_search($f->getId(), $_POST['forms']);
+                    if ($idx === false) {
+                        $f->delete();
+                    }
+                    else {
+                        $f->set('sort', $idx);
+                        $f->save();
+                    }
+                }
                 if(!$ticket->checkStaffAccess($thisstaff))
                     $ticket=null;
             } elseif(!$errors['err']) {