diff --git a/include/class.config.php b/include/class.config.php
index b0373f6e9d9679b2ec93e8b8179efbdf2b2167fc..c70a21d881e65a04acd81df917ec1d1891e68d3e 100644
--- a/include/class.config.php
+++ b/include/class.config.php
@@ -165,6 +165,8 @@ class OsticketConfig extends Config {
         'clients_only' => false,
         'client_registration' => 'closed',
         'accept_unregistered_email' => true,
+        'default_help_topic' => 0,
+        'help_topic_sort_mode' => 'a',
     );
 
     function OsticketConfig($section=null) {
@@ -426,6 +428,30 @@ class OsticketConfig extends Config {
         return $this->defaultPriority;
     }
 
+    function getDefaultTopicId() {
+        return $this->get('default_help_topic');
+    }
+
+    function getTopicSortMode() {
+        return $this->get('help_topic_sort_mode');
+    }
+
+    function setTopicSortMode($mode) {
+        $modes = static::allTopicSortModes();
+        if (!isset($modes[$mode]))
+            throw new InvalidArgumentException($mode
+                .': Unsupport help topic sort mode');
+
+        $this->update('help_topic_sort_mode', $mode);
+    }
+
+    static function allTopicSortModes() {
+        return array(
+            'a' => 'Alphabetically',
+            'm' => 'Manually',
+        );
+    }
+
     function getDefaultTemplateId() {
         return $this->get('default_template_id');
     }
@@ -938,6 +964,7 @@ class OsticketConfig extends Config {
         return $this->updateAll(array(
             'random_ticket_ids'=>$vars['random_ticket_ids'],
             'default_priority_id'=>$vars['default_priority_id'],
+            'default_help_topic'=>$vars['default_help_topic'],
             'default_sla_id'=>$vars['default_sla_id'],
             'max_open_tickets'=>$vars['max_open_tickets'],
             'autolock_minutes'=>$vars['autolock_minutes'],
diff --git a/include/class.topic.php b/include/class.topic.php
index ad3b21a416f147ba443d2417c786f1bb7c6299b2..7ef0ad412bc944d5ddf00699d4725cabe2902d59 100644
--- a/include/class.topic.php
+++ b/include/class.topic.php
@@ -78,6 +78,15 @@ class Topic {
         return $this->ht['name'];
     }
 
+    function getFullName() {
+        return self::getTopicName($this->getId());
+    }
+
+    static function getTopicName($id) {
+        $names = static::getHelpTopics();
+        return $names[$id];
+    }
+
     function getDeptId() {
         return $this->ht['dept_id'];
     }
@@ -144,6 +153,16 @@ class Topic {
         return $this->getHashtable();
     }
 
+    function setSortOrder($i) {
+        if ($i != $this->ht['sort']) {
+            $sql = 'UPDATE '.TOPIC_TABLE.' SET `sort`='.db_input($i)
+                .' WHERE `topic_id`='.db_input($this->getId());
+            return (db_query($sql) && db_affected_rows() == 1);
+        }
+        // Noop
+        return true;
+    }
+
     function update($vars, &$errors) {
 
         if(!$this->save($this->getId(), $vars, $errors))
@@ -169,23 +188,39 @@ class Topic {
         return self::save(0, $vars, $errors);
     }
 
-    function getHelpTopics($publicOnly=false) {
-
-        $topics=array();
-        $sql='SELECT ht.topic_id, CONCAT_WS(" / ", ht2.topic, ht.topic) as name '
-            .' FROM '.TOPIC_TABLE. ' ht '
-            .' LEFT JOIN '.TOPIC_TABLE.' ht2 ON(ht2.topic_id=ht.topic_pid) '
-            .' WHERE ht.isactive=1';
-
-        if($publicOnly)
-            $sql.=' AND ht.ispublic=1';
-
-        $sql.=' ORDER BY name';
-        if(($res=db_query($sql)) && db_num_rows($res))
-            while(list($id, $name)=db_fetch_row($res))
-                $topics[$id]=$name;
+    static function getHelpTopics($publicOnly=false) {
+        global $cfg;
+        static $names;
+
+        if ($names) return $names;
+
+        $sql = 'SELECT topic_id, topic_pid, ispublic, topic FROM '.TOPIC_TABLE
+            . ' WHERE isactive=1';
+
+        $sql .= ' ORDER BY '
+            . ($cfg->getTopicSortMode() == 'm' ? '`sort`' : '`topic_id`');
+        $res = db_query($sql);
+
+        // Fetch information for all topics, in declared sort order
+        $topics = array();
+        while (list($id, $pid, $pub, $topic) = db_fetch_row($res))
+            $topics[$id] = array('pid'=>$pid, 'public'=>$pub,
+                'topic'=>$topic);
+
+        // Resolve parent names
+        foreach ($topics as $id=>$info) {
+            if ($publicOnly && !$info['public'])
+                continue;
+            $name = $info['topic'];
+            while ($info['pid'] && ($info = $topics[$info['pid']])) {
+                $name = sprintf('%s / %s', $info['topic'], $name);
+            }
+            $names[$id] = $name;
+        }
 
-        return $topics;
+        if ($cfg->getTopicSortMode() == 'a')
+            uasort($names, function($a, $b) { return strcmp($a, $b); });
+        return $names;
     }
 
     function getPublicHelpTopics() {
@@ -203,7 +238,7 @@ class Topic {
         return $id;
     }
 
-    function lookup($id) {
+    static function lookup($id) {
         return ($id && is_numeric($id) && ($t= new Topic($id)) && $t->getId()==$id)?$t:null;
     }
 
diff --git a/include/client/open.inc.php b/include/client/open.inc.php
index 26b6d30edf9ab857dd1fb5b25f63bcfbc5a22c3e..415eacabc5fda233296723eea60a538b67d88bbf 100644
--- a/include/client/open.inc.php
+++ b/include/client/open.inc.php
@@ -10,6 +10,9 @@ if($thisclient && $thisclient->isValid()) {
 $info=($_POST && $errors)?Format::htmlchars($_POST):$info;
 
 $form = null;
+if (!$info['topicId'])
+    $info['topicId'] = $cfg->getDefaultTopicId();
+
 if ($info['topicId'] && ($topic=Topic::lookup($info['topicId']))) {
     $form = $topic->getForm();
     if ($_POST && $form) {
diff --git a/include/staff/email.inc.php b/include/staff/email.inc.php
index e8d3a430e74c3f66a40dc374c1974b2dd3a9fa6d..acfcb4c64aff9ce23eb31d61e998aa7ef5766bcd 100644
--- a/include/staff/email.inc.php
+++ b/include/staff/email.inc.php
@@ -129,14 +129,11 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 			<select name="topic_id">
 			    <option value="0" selected="selected">&mdash; None &mdash;</option>
 			    <?php
-			    $sql='SELECT topic_id, topic FROM '.TOPIC_TABLE.' T ORDER by topic';
-			    if(($res=db_query($sql)) && db_num_rows($res)){
-				while(list($id,$name)=db_fetch_row($res)){
-				    $selected=($info['topic_id'] && $id==$info['topic_id'])?'selected="selected"':'';
-				    echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name);
-				}
-			    }
-			    ?>
+                    $topics = Topic::getHelpTopics();
+                    while (list($id,$topic) = each($topics)) { ?>
+                        <option value="<?php echo $id; ?>"<?php echo ($info['topic_id']==$id)?'selected':''; ?>><?php echo $topic; ?></option>
+                    <?php
+                    } ?>
 			</select>
 			<i class="help-tip icon-question-sign" href="#new_ticket_help_topic"></i>
 		</span>
diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php
index 8395a29e3d723ed881405cfb8d06f96bbad728bc..3a4a9f760d80665c4d565647cf0111b9952d17af 100644
--- a/include/staff/helptopics.inc.php
+++ b/include/staff/helptopics.inc.php
@@ -1,7 +1,6 @@
 <?php
 if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied');
 
-$qstr='';
 $sql='SELECT topic.* '
     .', IF(ptopic.topic_pid IS NULL, topic.topic, CONCAT_WS(" / ", ptopic.topic, topic.topic)) as name '
     .', dept.dept_name as department '
@@ -11,34 +10,13 @@ $sql='SELECT topic.* '
     .' LEFT JOIN '.DEPT_TABLE.' dept ON (dept.dept_id=topic.dept_id) '
     .' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (pri.priority_id=topic.priority_id) ';
 $sql.=' WHERE 1';
-$sortOptions=array('name'=>'name','status'=>'topic.isactive','type'=>'topic.ispublic',
-                   'dept'=>'department','priority'=>'priority','updated'=>'topic.updated');
-$orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
-$sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'name';
-//Sorting options...
-if($sort && $sortOptions[$sort]) {
-    $order_column =$sortOptions[$sort];
-}
-$order_column=$order_column?$order_column:'topic.topic';
-
-if($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])]) {
-    $order=$orderWays[strtoupper($_REQUEST['order'])];
-}
-$order=$order?$order:'ASC';
-
-if($order_column && strpos($order_column,',')){
-    $order_column=str_replace(','," $order,",$order_column);
-}
-$x=$sort.'_sort';
-$$x=' class="'.strtolower($order).'" ';
-$order_by="$order_column $order ";
+$order_by = ($cfg->getTopicSortMode() == 'm' ? '`sort`' : '`name`');
 
 $total=db_count('SELECT count(*) FROM '.TOPIC_TABLE.' topic ');
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
 $pageNav=new Pagenate($total, $page, PAGE_LIMIT);
-$pageNav->setURL('helptopics.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
+$pageNav->setURL('helptopics.php');
 //Ok..lets roll...create the actual query
-$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
 $query="$sql GROUP BY topic.topic_id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
 $res=db_query($query);
 if($res && ($num=db_num_rows($res)))
@@ -53,31 +31,43 @@ else
 <div style="float:right;text-align:right;padding-top:5px;padding-right:5px;">
     <b><a href="helptopics.php?a=add" class="Icon newHelpTopic">Add New Help Topic</a></b></div>
 <div class="clear"></div>
-<form action="helptopics.php" method="POST" name="topics">
+<form id="save" action="helptopics.php" method="POST" name="topics">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
-<input type="hidden" id="action" name="a" value="" >
+<input type="hidden" id="action" name="a" value="sort" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
-    <caption><?php echo $showing; ?></caption>
+    <caption><span style="display:inline-block;vertical-align:middle"><?php
+         echo $showing; ?></span>
+    <div class="pull-right">Sorting Mode:
+        <select name="help_topic_sort_mode">
+<?php foreach (OsticketConfig::allTopicSortModes() as $i=>$m)
+    echo sprintf('<option value="%s"%s>%s</option>',
+        $i, $i == $cfg->getTopicSortMode() ? ' selected="selected"' : '', $m); ?>
+        </select>
+    </div>
+    </caption>
     <thead>
         <tr>
-            <th width="7">&nbsp;</th>
-            <th width="320"><a <?php echo $name_sort; ?> href="helptopics.php?<?php echo $qstr; ?>&sort=name">Help Topic</a></th>
-            <th width="80"><a  <?php echo $status_sort; ?> href="helptopics.php?<?php echo $qstr; ?>&sort=status">Status</a></th>
-            <th width="100"><a  <?php echo $type_sort; ?> href="helptopics.php?<?php echo $qstr; ?>&sort=type">Type</a></th>
-            <th width="100"><a  <?php echo $priority_sort; ?> href="helptopics.php?<?php echo $qstr; ?>&sort=priority">Priority</a></th>
-            <th width="200"><a  <?php echo $dept_sort; ?> href="helptopics.php?<?php echo $qstr; ?>&sort=dept">Department</a></th>
-            <th width="150" nowrap><a  <?php echo $updated_sort; ?>href="helptopics.php?<?php echo $qstr; ?>&sort=updated">Last Updated</a></th>
+            <th width="7" style="height:20px;">&nbsp;</th>
+            <th style="padding-left:4px;vertical-align:middle" width="320">Help Topic</th>
+            <th style="padding-left:4px;vertical-align:middle" width="80">Status</th>
+            <th style="padding-left:4px;vertical-align:middle" width="100">Type</th>
+            <th style="padding-left:4px;vertical-align:middle" width="100">Priority</th>
+            <th style="padding-left:4px;vertical-align:middle" width="200">Department</th>
+            <th style="padding-left:4px;vertical-align:middle" width="150" nowrap>Last Updated</th>
         </tr>
     </thead>
-    <tbody>
+    <tbody class="<?php if ($cfg->getTopicSortMode() == 'm') echo 'sortable-rows'; ?>"
+        data-sort="sort-">
     <?php
         $total=0;
         $ids=($errors && is_array($_POST['ids']))?$_POST['ids']:null;
         if($res && db_num_rows($res)):
             $defaultDept = $cfg->getDefaultDept();
             $defaultPriority = $cfg->getDefaultPriority();
+            $sort = 0;
             while ($row = db_fetch_array($res)) {
+                $sort++; // Track initial order for transition
                 $sel=false;
                 if($ids && in_array($row['topic_id'],$ids))
                     $sel=true;
@@ -93,6 +83,8 @@ else
                 ?>
             <tr id="<?php echo $row['topic_id']; ?>">
                 <td width=7px>
+                  <input type="hidden" name="sort-<?php echo $row['topic_id']; ?>" value="<?php
+                        echo $row['sort'] ?: $sort; ?>"/>
                   <input type="checkbox" class="ckb" name="ids[]" value="<?php echo $row['topic_id']; ?>"
                             <?php echo $sel?'checked="checked"':''; ?>>
                 </td>
@@ -126,6 +118,7 @@ if($res && $num): //Show options..
     echo '<div>&nbsp;Page:'.$pageNav->getPageLinks().'&nbsp;</div>';
 ?>
 <p class="centered" id="actions">
+    <input type="submit" name="submit" value="Save">
     <input class="button" type="submit" name="enable" value="Enable" >
     <input class="button" type="submit" name="disable" value="Disable">
     <input class="button" type="submit" name="delete" value="Delete">
diff --git a/include/staff/settings-tickets.inc.php b/include/staff/settings-tickets.inc.php
index 37bc2af8561a8e12252dca25e9ef10f1167e3c7e..3be8dd7d6f1b5afb3a6ac2b8fa3c3cf14dffe516 100644
--- a/include/staff/settings-tickets.inc.php
+++ b/include/staff/settings-tickets.inc.php
@@ -63,6 +63,19 @@ if(!($maxfileuploads=ini_get('max_file_uploads')))
                 &nbsp;<span class="error">*&nbsp;<?php echo $errors['default_priority_id']; ?></span> <i class="help-tip icon-question-sign" href="#default_priority"></i>
              </td>
         </tr>
+        <tr>
+            <td width="180">Default Help Topic:</td>
+            <td>
+                <select name="default_help_topic">
+                    <option value="0">&mdash; None &mdash;</option><?php
+                    $topics = Topic::getHelpTopics();
+                    while (list($id,$topic) = each($topics)) { ?>
+                        <option value="<?php echo $id; ?>"<?php echo ($config['default_help_topic']==$id)?'selected':''; ?>><?php echo $topic; ?></option>
+                    <?php
+                    } ?>
+                </select>
+            </td>
+        </tr>
         <tr>
             <td>Maximum <b>Open</b> Tickets:</td>
             <td>
@@ -88,7 +101,7 @@ if(!($maxfileuploads=ini_get('max_file_uploads')))
             <td>Claim on Response:</td>
             <td>
                 <input type="checkbox" name="auto_claim_tickets" <?php echo $config['auto_claim_tickets']?'checked="checked"':''; ?>>
-                &nbsp;Enable&nbsp;<i class="help-tip icon-question-sign" href="#claim_tickets"></i>
+                Enable&nbsp;<i class="help-tip icon-question-sign" href="#claim_tickets"></i>
             </td>
         </tr>
         <tr>
diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php
index d14f7e98e393e6ed10d5a03c9ce5523e8fdbe6a8..f9a3ad3c161ab14730b4814ae1ae93433e9150bb 100644
--- a/include/staff/ticket-open.inc.php
+++ b/include/staff/ticket-open.inc.php
@@ -3,6 +3,9 @@ if(!defined('OSTSCPINC') || !$thisstaff || !$thisstaff->canCreateTickets()) die(
 $info=array();
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 
+if (!$info['topicId'])
+    $info['topicId'] = $cfg->getDefaultTopicId();
+
 $form = null;
 if ($info['topicId'] && ($topic=Topic::lookup($info['topicId']))) {
     $form = $topic->getForm();
diff --git a/scp/helptopics.php b/scp/helptopics.php
index 0847257cfc0d3da5c7d95a79773f0d34062c0b33..1b4eff07e2e7075e4585b76a8b83161a7da319c3 100644
--- a/scp/helptopics.php
+++ b/scp/helptopics.php
@@ -41,9 +41,15 @@ if($_POST){
             }
             break;
         case 'mass_process':
-            if(!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) {
-                $errors['err'] = 'You must select at least one help topic';
-            } else {
+            switch(strtolower($_POST['a'])) {
+            case 'sort':
+                // Pass
+                break;
+            default:
+                if(!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids']))
+                    $errors['err'] = 'You must select at least one help topic';
+            }
+            if (!$errors) {
                 $count=count($_POST['ids']);
 
                 switch(strtolower($_POST['a'])) {
@@ -86,6 +92,23 @@ if($_POST){
                         elseif(!$errors['err'])
                             $errors['err']  = 'Unable to delete selected help topics';
 
+                        break;
+                    case 'sort':
+                        try {
+                            $cfg->setTopicSortMode($_POST['help_topic_sort_mode']);
+                            if ($cfg->getTopicSortMode() == 'm') {
+                                foreach ($_POST as $k=>$v) {
+                                    if (strpos($k, 'sort-') === 0
+                                            && is_numeric($v)
+                                            && $t = Topic::lookup(substr($k, 5)))
+                                        $t->setSortOrder($v);
+                                }
+                            }
+                            $msg = 'Successfully set sorting configuration';
+                        }
+                        catch (Exception $ex) {
+                            $errors['err'] = 'Unable to set sorting mode';
+                        }
                         break;
                     default:
                         $errors['err']='Unknown action - get technical help.';
diff --git a/scp/js/scp.js b/scp/js/scp.js
index b2e0ba77b9a9a1d95555194884d08441b86f3d1a..8559f909e587a05c443a7cf300636cc1a93aeb9e 100644
--- a/scp/js/scp.js
+++ b/scp/js/scp.js
@@ -137,7 +137,7 @@ var scp_prep = function() {
         var fObj = el.closest('form');
         if(!fObj.data('changed')){
             fObj.data('changed', true);
-            $('input[type=submit]', fObj).css('color', 'red');
+            $('input[type=submit][name="submit"]', fObj).css('color', 'red');
             $(window).bind('beforeunload', function(e) {
                 return 'Are you sure you want to leave? Any changes or info you\'ve entered will be discarded!';
             });
@@ -437,6 +437,7 @@ var scp_prep = function() {
    // Sortable tables for dynamic forms objects
    $('.sortable-rows').sortable({
        'helper': fixHelper,
+       'cursor': 'move',
        'stop': function(e, ui) {
            var attr = ui.item.parent('tbody').data('sort');
            warnOnLeave(ui.item);