diff --git a/include/ajax.forms.php b/include/ajax.forms.php
index 9a026e83c5861f5621678dcf0864f008efd44e3a..57959fe727d8b3ff90f06580f7e142497d5a9a8b 100644
--- a/include/ajax.forms.php
+++ b/include/ajax.forms.php
@@ -58,15 +58,27 @@ class DynamicFormsAjaxAPI extends AjaxController {
         $ent->delete();
     }
 
-    function getListItemProperties($item_id) {
-        if (!($item = DynamicListItem::lookup($item_id)))
+    function getListItemProperties($list_id, $item_id) {
+
+        if (is_numeric($list_id))
+            $list = DynamicList::lookup($list_id);
+        else
+            $list = BuiltInCustomList::lookup($list_id);
+
+        if (!($item = $list->getItem($item_id)))
             Http::response(404, 'No such list item');
 
         include(STAFFINC_DIR . 'templates/list-item-properties.tmpl.php');
     }
 
-    function saveListItemProperties($item_id) {
-        if (!($item = DynamicListItem::lookup($item_id)))
+    function saveListItemProperties($list_id, $item_id) {
+
+        if (is_numeric($list_id))
+            $list = DynamicList::lookup($list_id);
+        else
+            $list = BuiltInCustomList::lookup($list_id);
+
+        if (!($item = $list->getItem($item_id)))
             Http::response(404, 'No such list item');
 
         if (!$item->setConfiguration())
diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php
index 9fa8253a949a7c58f89b63dc4a24851de1e52b5b..9c49000d050e4e211bf65e84d5b5acb594a30ea0 100644
--- a/include/class.dynamic_forms.php
+++ b/include/class.dynamic_forms.php
@@ -448,6 +448,14 @@ class DynamicFormField extends VerySimpleModel {
         return $this->get('edit_mask') & 8;
     }
 
+    function  isChangeable() {
+        return ($this->get('edit_mask') & 16) == 0;
+    }
+
+    function  isConfigurable() {
+        return ($this->get('edit_mask') & 32) == 0;
+    }
+
     /**
      * Used when updating the form via the admin panel. This represents
      * validation on the form field template, not data entered into a form
diff --git a/include/class.list.php b/include/class.list.php
index e2d7592af596a0285ed3ef60f0a0a8ca44061a76..2ba87622560907893962a6e62656310df4c21860 100644
--- a/include/class.list.php
+++ b/include/class.list.php
@@ -36,10 +36,14 @@ interface CustomList {
     function getAllItems();
     function getItems($criteria);
 
+    function getItem($id);
+    function addItem($vars, &$errors);
+
     function getForm(); // Config form
     function hasProperties();
 
     function getSortModes();
+    function getSortMode();
     function getListOrderBy();
 
     function isBuiltIn();
@@ -48,8 +52,35 @@ interface CustomList {
     function delete();
 
     static function create($vars, &$errors);
+    static function lookup($id);
+}
+
+/*
+ * Custom list item interface
+ */
+interface CustomListItem {
+    function getId();
+    function getValue();
+    function getAbbrev();
+    function getSortOrder();
+
+    function getConfiguration();
+    function getConfigurationForm();
+
+
+    function isEnabled();
+    function isDeletable();
+    function isEnableable();
+    function isInternal();
+
+    function enable();
+    function disable();
+
+    function update($vars, &$errors);
+    function delete();
 }
 
+
 /*
  * Base class for Built-in Custom Lists
  *
@@ -81,11 +112,15 @@ abstract class BuiltInCustomList implements CustomList {
     abstract function getAllItems();
     abstract function getItems($criteria);
 
+    abstract function addItem($vars, &$errors);
+
     abstract function getForm(); // Config form
     abstract function hasProperties();
 
     abstract function getListOrderBy();
 
+    abstract function getSortMode();
+
     function getSortModes() {
         return static::$sort_modes;
     }
@@ -186,8 +221,12 @@ class DynamicList extends VerySimpleModel implements CustomList {
        return static::$sort_modes;
     }
 
+    function getSortMode() {
+        return $this->sort_mode;
+    }
+
     function getListOrderBy() {
-        switch ($this->sort_mode) {
+        switch ($this->getSortMode()) {
             case 'Alpha':   return 'value';
             case '-Alpha':  return '-value';
             case 'SortCol': return 'sort';
@@ -234,7 +273,15 @@ class DynamicList extends VerySimpleModel implements CustomList {
         return $this->_items;
     }
 
-    function addItem($vars) {
+
+
+    function getItem($id) {
+         return DynamicListItem::lookup(array(
+                     'id' => $id,
+                     'list_id' => $this->getId()));
+    }
+
+    function addItem($vars, &$errors) {
 
         $item = DynamicListItem::create(array(
             'list_id' => $this->getId(),
@@ -250,16 +297,30 @@ class DynamicList extends VerySimpleModel implements CustomList {
         return $item;
     }
 
-    function getConfigurationForm() {
+    function getConfigurationForm($autocreate=false) {
         if (!$this->_form) {
-            $this->_form = DynamicForm::lookup(
-                array('type'=>'L'.$this->get('id')));
+            $this->_form = DynamicForm::lookup(array('type'=>'L'.$this->getId()));
+            if (!$this->_form
+                    && $autocreate
+                    && $this->createConfigurationForm())
+                return $this->getConfigurationForm(false);
         }
+
         return $this->_form;
     }
 
-    function getForm() {
-        return $this->getConfigurationForm();
+    private function createConfigurationForm() {
+
+        $form = DynamicForm::create(array(
+                    'type' => 'L'.$this->getId(),
+                    'title' => $this->getName() . ' Properties'
+        ));
+
+        return $form->save(true);
+    }
+
+    function getForm($autocreate=true) {
+        return $this->getConfigurationForm($autocreate);
     }
 
     function update($vars, &$errors) {
@@ -295,6 +356,39 @@ class DynamicList extends VerySimpleModel implements CustomList {
             return false;
     }
 
+    private function createForm() {
+
+        $form = DynamicForm::create(array(
+                    'type' => 'L'.$this->getId(),
+                    'title' => $this->getName() . ' Properties'
+        ));
+
+        return $form->save(true);
+    }
+
+    static function add($vars, &$errors) {
+
+        $required = array('name');
+        $ht = array();
+        foreach (static::$fields as $f) {
+            if (in_array($f, $required) && !$vars[$f])
+                $errors[$f] = sprintf('%s is required', mb_convert_case($f, MB_CASE_TITLE));
+            elseif(isset($vars[$f]))
+                $ht[$f] = $vars[$f];
+        }
+
+        if (!$ht || $errors)
+            return false;
+
+        // Create the list && form
+        if (!($list = self::create($ht))
+                || !$list->save(true)
+                || !$list->createConfigurationForm())
+            return false;
+
+        return $list;
+    }
+
     static function create($ht=false, &$errors=array()) {
         $inst = parent::create($ht);
         $inst->set('created', new SqlFunction('NOW'));
@@ -326,7 +420,7 @@ FormField::addFieldTypes('Custom Lists', array('DynamicList', 'getSelections'));
  * sort - (int) If sorting by this field, represents the numeric sort order
  *      that this item should come in the dropdown list
  */
-class DynamicListItem extends VerySimpleModel {
+class DynamicListItem extends VerySimpleModel implements CustomListItem {
 
     static $meta = array(
         'table' => LIST_ITEM_TABLE,
@@ -356,6 +450,18 @@ class DynamicListItem extends VerySimpleModel {
         return $this->set('status', $this->get('status') | $flag);
     }
 
+    function isInternal() {
+        return false;
+    }
+
+    function isEnableable() {
+        return true;
+    }
+
+    function isDeletable() {
+        return !$this->isInternal();
+    }
+
     function isEnabled() {
         return $this->hasStatus(self::ENABLED);
     }
@@ -371,6 +477,10 @@ class DynamicListItem extends VerySimpleModel {
         return $this->get('id');
     }
 
+    function getListId() {
+        return $this->get('list_id');
+    }
+
     function getValue() {
         return $this->get('value');
     }
@@ -415,6 +525,10 @@ class DynamicListItem extends VerySimpleModel {
         return $this->_form;
     }
 
+    function getForm() {
+        return $this->getConfigurationForm();
+    }
+
     function getVar($name) {
         $config = $this->getConfiguration();
         $name = mb_strtolower($name);
@@ -432,7 +546,12 @@ class DynamicListItem extends VerySimpleModel {
         return $this->toString();
     }
 
-    function update($vars, $save = true) {
+    function update($vars, &$errors=array()) {
+
+        if (!$vars['value']) {
+            $errors['value-'.$this->getId()] = 'Value required';
+            return false;
+        }
 
         foreach (array(
                     'sort' => 'sort',
@@ -440,13 +559,9 @@ class DynamicListItem extends VerySimpleModel {
                     'abbrev' => 'extra') as $k => $v) {
             if (isset($vars[$k]))
                 $this->set($v, $vars[$k]);
-
         }
 
-        if ($save)
-            $this->save();
-
-        return true;
+        return $this->save();
     }
 
     function delete() {
@@ -471,9 +586,13 @@ class TicketStatusList extends BuiltInCustomList {
             'name' => 'Status',
             'name_plural' => 'Statuses',
     );
+
     // Fields of interest we need to store
     static $config_fields = array('sort_mode', 'notes');
 
+    var $_items;
+    var $_form;
+
     function getId() {
         return $this->ht['id'];
     }
diff --git a/include/staff/dynamic-list.inc.php b/include/staff/dynamic-list.inc.php
index ad0e8d29d2bcd2e46b8e5710a51909c607f16850..ef9f9c5a02c594aa55926bbb9eedffff674522d5 100644
--- a/include/staff/dynamic-list.inc.php
+++ b/include/staff/dynamic-list.inc.php
@@ -22,7 +22,7 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
     <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>Custom List: <?php echo $list->getName(); ?></h2>
+    <h2>Custom List: <?php echo $list ? $list->getName() : 'Add new list'; ?></h2>
 
 <ul class="tabs">
     <li><a href="#definition" class="active">
@@ -48,8 +48,8 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
             <td width="180" class="required">Name:</td>
             <td>
                 <?php
-                if ($list->isBuiltIn())
-                    echo $info['name'];
+                if ($list && $list->isBuiltIn())
+                    echo $list->getName();
                 else {
                     echo sprintf('<input size="50" type="text" name="name"
                             value="%s"/> <span
@@ -63,8 +63,8 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
             <td width="180">Plural Name:</td>
             <td>
                 <?php
-                    if ($list->isBuiltIn())
-                        echo $info['name_plural'];
+                    if ($list && $list->isBuiltIn())
+                        echo $list->getPluralName();
                     else
                         echo sprintf('<input size="50" type="text"
                                 name="name_plural" value="%s"/>',
@@ -75,7 +75,9 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
         <tr>
             <td width="180">Sort Order:</td>
             <td><select name="sort_mode">
-                <?php foreach ($list->getSortModes() as $key=>$desc) { ?>
+                <?php
+                $sortModes = $list ? $list->getSortModes() : DynamicList::getSortModes();
+                foreach ($sortModes as $key=>$desc) { ?>
                 <option value="<?php echo $key; ?>" <?php
                     if ($key == $info['sort_mode']) echo 'selected="selected"';
                     ?>><?php echo $desc; ?></option>
@@ -115,7 +117,7 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
         </tr>
     </thead>
     <tbody class="sortable-rows" data-sort="prop-sort-">
-    <?php if ($form) foreach ($form->getDynamicFields() as $f) {
+    <?php if ($list && $form=$list->getForm()) foreach ($form->getDynamicFields() as $f) {
         $id = $f->get('id');
         $deletable = !$f->isDeletable() ? 'disabled="disabled"' : '';
         $force_name = $f->isNameForced() ? 'disabled="disabled"' : '';
@@ -129,7 +131,7 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
                     if ($ferrors['label']) echo '<br/>'; echo $ferrors['label']; ?>
             </td>
             <td nowrap><select name="type-<?php echo $id; ?>" <?php
-                if (!$fi->isChangeable()) echo 'disabled="disabled"'; ?>>
+                if (!$fi->isChangeable() || !$f->isChangeable()) echo 'disabled="disabled"'; ?>>
                 <?php foreach (FormField::allTypes() as $group=>$types) {
                         ?><optgroup label="<?php echo Format::htmlchars($group); ?>"><?php
                         foreach ($types as $type=>$nfo) {
@@ -148,6 +150,7 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
                         echo $f->get('id'); ?>"
                     onclick="javascript:
                         $('#overlay').show();
+                        $('#field-config .body').html('Loading...');
                         $('#field-config .body').load($(this).attr('href').substr(1));
                         $('#field-config').show();
                         return false;
@@ -161,8 +164,13 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
                     if ($ferrors['name']) echo '<br/>'; echo $ferrors['name'];
                 ?></font>
                 </td>
-            <td><input type="checkbox" name="delete-<?php echo $id; ?>"
-                    <?php echo $deletable; ?>/>
+            <td>
+                <?php
+                if (!$f->isDeletable())
+                    echo '<i class="icon-ban-circle"></i>';
+                else
+                    echo sprintf('<input type="checkbox" name="delete-prop-%s">', $id);
+                ?>
                 <input type="hidden" name="prop-sort-<?php echo $id; ?>"
                     value="<?php echo $f->get('sort'); ?>"/>
                 </td>
@@ -220,7 +228,11 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
         <tr>
             <th></th>
             <th>Value</th>
+            <?php
+            if (!$list || !$list->isBuiltIn()) { ?>
             <th>Abbrev <em style="display:inline">&mdash; Abbreviations and such</em></th>
+            <?php
+            } ?>
             <th>Disabled</th>
             <th>Delete</th>
         </tr>
@@ -242,22 +254,51 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
                 value="<?php echo $i->getValue(); ?>"/>
                 <?php if ($list->hasProperties()) { ?>
                 <a class="action-button" style="float:none;overflow:inherit"
-                    href="#ajax.php/list/item/<?php
-                        echo $id ?>/properties"
+                    href="#ajax.php/list/<?php
+                        echo $list->getId(); ?>/item/<?php echo $id ?>/properties"
                     onclick="javascript:
                         $('#overlay').show();
+                        $('#field-config .body').html('Loading...');
                         $('#field-config .body').load($(this).attr('href').substr(1));
                         $('#field-config').show();
                         return false;
                     "><i class="icon-edit"></i> Properties</a>
-                <?php } ?></td>
+                <?php
+                }
+
+                if ($errors["value-$id"])
+                    echo sprintf('<br><span class="error">%s</span>',
+                            $errors["value-$id"]);
+                ?>
+            </td>
+            <?php
+            if (!$list->isBuiltIn()) { ?>
             <td><input type="text" size="30" name="abbrev-<?php echo $id; ?>"
                 value="<?php echo $i->getAbbrev(); ?>"/></td>
+            <?php
+            } ?>
             <td>
-                <input type="checkbox" name="disable-<?php echo $id; ?>" <?php
-                if (!$i->isEnabled()) echo 'checked="checked"'; ?>/></td>
+                <?php
+                if ($i->isInternal())
+                     echo '<i class="icon-ban-circle"></i>';
+                else
+                    echo sprintf('<input type="checkbox" name="disable-%s"
+                            %s %s />',
+                            $id,
+                            !$i->isEnabled() ? ' checked="checked" ' : '',
+                            (!$i->isEnabled() && !$i->isEnableable()) ? ' disabled="disabled" ' : ''
+                            );
+                ?>
+            </td>
             <td>
-                <input type="checkbox" name="delete-<?php echo $id; ?>"/></td>
+                <?php
+                if (!$i->isDeletable())
+                    echo '<i class="icon-ban-circle"></i>';
+                else
+                    echo sprintf('<input type="checkbox" name="delete-item-%s">', $id);
+
+                ?>
+            </td>
         </tr>
     <?php }
     }
@@ -266,9 +307,13 @@ $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info)
             <td><?php echo $icon; ?> <em>+</em>
                 <input type="hidden" name="sort-new-<?php echo $i; ?>"/></td>
             <td><input type="text" size="40" name="value-new-<?php echo $i; ?>"/></td>
+            <?php
+            if (!$list || !$list->isBuiltIn()) { ?>
             <td><input type="text" size="30" name="abbrev-new-<?php echo $i; ?>"/></td>
-            <td></td>
-            <td></td>
+            <?php
+            } ?>
+            <td>&nbsp;</td>
+            <td>&nbsp;</td>
         </tr>
     <?php } ?>
     </tbody>
diff --git a/include/staff/templates/list-item-properties.tmpl.php b/include/staff/templates/list-item-properties.tmpl.php
index ce4a0ca5ee64aeb1ccef1914cea444f21f1c1390..ef7158d03c78fb746cb100575bc54b34ab65f722 100644
--- a/include/staff/templates/list-item-properties.tmpl.php
+++ b/include/staff/templates/list-item-properties.tmpl.php
@@ -1,8 +1,9 @@
-    <h3>Item Properties &mdash; <?php echo $item->get('value') ?></h3>
+    <h3>Item Properties &mdash; <?php echo $item->getValue(); ?></h3>
     <a class="close" href=""><i class="icon-remove-circle"></i></a>
     <hr/>
-    <form method="post" action="ajax.php/list/item/<?php
-            echo $item->get('id'); ?>/properties" onsubmit="javascript:
+    <form method="post" action="ajax.php/list/<?php
+            echo $list->getId(); ?>/item/<?php
+            echo $item->getId(); ?>/properties" onsubmit="javascript:
             var form = $(this);
             $.post(this.action, form.serialize(), function(data, status, xhr) {
                 if (!data.length) {
diff --git a/scp/ajax.php b/scp/ajax.php
index a192cce8cf92da76bf185a441840093133d03099..0cf11d7d46d541eeba4521d412ee4f62b78b4844 100644
--- a/scp/ajax.php
+++ b/scp/ajax.php
@@ -57,8 +57,8 @@ $dispatcher = patterns('',
         url_delete('^answer/(?P<entry>\d+)/(?P<field>\d+)$', 'deleteAnswer')
     )),
     url('^/list/', patterns('ajax.forms.php:DynamicFormsAjaxAPI',
-        url_get('^item/(?P<id>\d+)/properties$', 'getListItemProperties'),
-        url_post('^item/(?P<id>\d+)/properties$', 'saveListItemProperties')
+        url_get('^(?P<list>\w+)/item/(?P<id>\d+)/properties$', 'getListItemProperties'),
+        url_post('^(?P<list>\w+)/item/(?P<id>\d+)/properties$', 'saveListItemProperties')
     )),
     url('^/report/overview/', patterns('ajax.reports.php:OverviewReportAjaxAPI',
         # Send
diff --git a/scp/lists.php b/scp/lists.php
index 56232c76c3c482da7abb8092c3a52daed7ee0a8e..84fe3bdc600274e58e371a430cab28affe082d09 100644
--- a/scp/lists.php
+++ b/scp/lists.php
@@ -16,112 +16,108 @@ if ($_REQUEST['id']) {
         $errors['err'] = 'Unknown or invalid dynamic list ID.';
 }
 
+$errors = array();
+$max_isort = 0;
+
 if($_POST) {
-    $fields = array('name', 'name_plural', 'sort_mode', 'notes');
-    $required = array('name');
     switch(strtolower($_POST['do'])) {
         case 'update':
-            if ($list->update($_POST, $errors))
-                $msg = 'Custom list updated successfully';
-            elseif ($errors)
-                $errors['err'] = 'Unable to update custom list. Correct any error(s) below and try again.';
-            else
-                $errors['err'] = 'Unable to update custom list. Unknown internal error';
-
-            if ($list->getNumItems()) {
+            if (!$list)
+                $errors['err'] = 'Unknown or invalid list';
+            elseif ($list->update($_POST, $errors)) {
+                // Update items
+                $items = array();
                 foreach ($list->getAllItems() as $item) {
                     $id = $item->getId();
-                    if ($_POST["delete-$id"] == 'on') {
+                    if ($_POST["delete-item-$id"] == 'on' && $item->isDeletable()) {
                         $item->delete();
                         continue;
                     }
 
-                    $item->update(array(
-                                'value' => $_POST["value-$id"],
-                                'abbrev' => $_POST["abbrev-$id"],
-                                'sort' => $_POST["name-$id"],
-                                ),
-                            false);
-
-                    if ($_POST["disable-$id"] == 'on')
-                        $item->disable();
-                    else
-                        $item->enable();
+                    $ht = array(
+                            'value' => $_POST["value-$id"],
+                            'abbrev' => $_POST["abbrev-$id"],
+                            'sort' => $_POST["sort-$id"],
+                            );
+                    $value = mb_strtolower($ht['value']);
+                    if (!$value)
+                        $errors["value-$id"] = 'Value required';
+                    elseif (in_array($value, $items))
+                        $errors["value-$id"] = 'Value already in-use';
+                    elseif ($item->update($ht, $errors)) {
+                        if ($_POST["disable-$id"] == 'on')
+                            $item->disable();
+                        elseif(!$item->isEnabled() && $item->isEnableable())
+                            $item->enable();
+
+                        $item->save();
+                        $items[] = $value;
+                    }
 
-                    $item->save();
+                    $max_isort = max($max_isort, $_POST["sort-$id"]);
                 }
-            }
 
-            $names = array();
-            if (!$form) {
-                $form = DynamicForm::create(array(
-                    'type' => 'L'.$list->getId(),
-                    'title' => $list->getName() . ' Properties'
-                ));
-                $form->save(true);
-            }
-            foreach ($form->getDynamicFields() as $field) {
-                $id = $field->get('id');
-                if ($_POST["delete-$id"] == 'on' && $field->isDeletable()) {
-                    $field->delete();
-                    // Don't bother updating the field
-                    continue;
-                }
-                if (isset($_POST["type-$id"]) && $field->isChangeable())
-                    $field->set('type', $_POST["type-$id"]);
-                if (isset($_POST["name-$id"]) && !$field->isNameForced())
-                    $field->set('name', $_POST["name-$id"]);
-                # TODO: make sure all help topics still have all required fields
-                foreach (array('sort','label') as $f) {
-                    if (isset($_POST["prop-$f-$id"])) {
-                        $field->set($f, $_POST["prop-$f-$id"]);
+                // Update properties
+                if (!$errors && ($form = $list->getForm())) {
+                    $names = array();
+                    foreach ($form->getDynamicFields() as $field) {
+                        $id = $field->get('id');
+                        if ($_POST["delete-prop-$id"] == 'on' && $field->isDeletable()) {
+                            $field->delete();
+                            // Don't bother updating the field
+                            continue;
+                        }
+                        if (isset($_POST["type-$id"]) && $field->isChangeable())
+                            $field->set('type', $_POST["type-$id"]);
+                        if (isset($_POST["name-$id"]) && !$field->isNameForced())
+                            $field->set('name', $_POST["name-$id"]);
+
+                        foreach (array('sort','label') as $f) {
+                            if (isset($_POST["prop-$f-$id"])) {
+                                $field->set($f, $_POST["prop-$f-$id"]);
+                            }
+                        }
+                        if (in_array($field->get('name'), $names))
+                            $field->addError('Field variable name is not unique', 'name');
+                        if (preg_match('/[.{}\'"`; ]/u', $field->get('name')))
+                            $field->addError('Invalid character in variable name. Please use letters and numbers only.', 'name');
+                        if ($field->get('name'))
+                            $names[] = $field->get('name');
+                        if ($field->isValid())
+                            $field->save();
+                        else
+                            # notrans (not shown)
+                            $errors["field-$id"] = 'Field has validation errors';
+                        // Keep track of the last sort number
+                        $max_sort = max($max_sort, $field->get('sort'));
                     }
                 }
-                if (in_array($field->get('name'), $names))
-                    $field->addError('Field variable name is not unique', 'name');
-                if (preg_match('/[.{}\'"`; ]/u', $field->get('name')))
-                    $field->addError('Invalid character in variable name. Please use letters and numbers only.', 'name');
-                if ($field->get('name'))
-                    $names[] = $field->get('name');
-                if ($field->isValid())
-                    $field->save();
+
+                if ($errors)
+                     $errors['err'] = $errors['err'] ?: 'Unable to update custom list items.  Correct any error(s) and try again.';
                 else
-                    # notrans (not shown)
-                    $errors["field-$id"] = 'Field has validation errors';
-                // Keep track of the last sort number
-                $max_sort = max($max_sort, $field->get('sort'));
-            }
+                    $msg = 'Custom list updated successfully';
+
+            } elseif ($errors)
+                $errors['err'] = 'Unable to update custom list. Correct any error(s) below and try again.';
+            else
+                $errors['err'] = 'Unable to update custom list. Unknown internal error';
+
             break;
         case 'add':
-            foreach ($fields as $f)
-                if (in_array($f, $required) && !$_POST[$f])
-                    $errors[$f] = sprintf('%s is required',
-                        mb_convert_case($f, MB_CASE_TITLE));
-            $list = DynamicList::create(array(
-                'name'=>$_POST['name'],
-                'name_plural'=>$_POST['name_plural'],
-                'sort_mode'=>$_POST['sort_mode'],
-                'notes'=>$_POST['notes']));
-
-            $form = DynamicForm::create(array(
-                'title'=>$_POST['name'] . ' Properties'
-            ));
-
-            if ($errors)
-                $errors['err'] = 'Unable to create custom list. Correct any error(s) below and try again.';
-            elseif (!$list->save(true))
+            if ($list=DynamicList::add($_POST, $errors)) {
+                 $msg = 'Custom list added successfully';
+            } elseif ($errors) {
+                $errors['err'] = 'Unable to create custom list. Correct any
+                    error(s) below and try again.';
+            } else {
                 $errors['err'] = 'Unable to create custom list: Unknown internal error';
-
-            $form->set('type', 'L'.$list->get('id'));
-            if (!$errors && !$form->save(true))
-                $errors['err'] = 'Unable to create properties for custom list: Unknown internal error';
-            else
-                $msg = 'Custom list added successfully';
+            }
             break;
 
         case 'mass_process':
             if(!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) {
-                $errors['err'] = 'You must select at least one API key';
+                $errors['err'] = 'You must select at least one custom list';
             } else {
                 $count = count($_POST['ids']);
                 switch(strtolower($_POST['a'])) {
@@ -152,8 +148,8 @@ if($_POST) {
             $list->addItem(array(
                         'value' => $_POST["value-new-$i"],
                         'abbrev' =>$_POST["abbrev-new-$i"],
-                        'sort' => $_POST["sort-new-$i"]
-                        ));
+                        'sort' => $_POST["sort-new-$i"] ?: ++$max_isort,
+                        ), $errors);
         }
     }
 
@@ -162,12 +158,11 @@ if($_POST) {
             if (!$_POST["prop-label-new-$i"])
                 continue;
             $field = DynamicFormField::create(array(
-                'form_id'=>$form->get('id'),
-                'sort'=>$_POST["prop-sort-new-$i"]
-                    ? $_POST["prop-sort-new-$i"] : ++$max_sort,
-                'label'=>$_POST["prop-label-new-$i"],
-                'type'=>$_POST["type-new-$i"],
-                'name'=>$_POST["name-new-$i"],
+                'form_id' => $form->get('id'),
+                'sort' => $_POST["prop-sort-new-$i"] ?: ++$max_sort,
+                'label' => $_POST["prop-label-new-$i"],
+                'type' => $_POST["type-new-$i"],
+                'name' => $_POST["name-new-$i"],
             ));
             $field->setForm($form);
             if ($field->isValid())