diff --git a/include/ajax.forms.php b/include/ajax.forms.php
index 070606298089eb337009a6203dcddd97dcf3d6c6..8044fafc32c7b1d9e77ee93f341d14903627d5f4 100644
--- a/include/ajax.forms.php
+++ b/include/ajax.forms.php
@@ -39,8 +39,10 @@ class DynamicFormsAjaxAPI extends AjaxController {
 
     function saveFieldConfiguration($field_id) {
         $field = DynamicFormField::lookup($field_id);
-        if (!$field->setConfiguration())
-            return (include STAFFINC_DIR . 'templates/dynamic-field-config.tmpl.php');
+        if (!$field->setConfiguration()) {
+            include STAFFINC_DIR . 'templates/dynamic-field-config.tmpl.php';
+            return;
+        }
         else
             $field->save();
         Http::response(201, 'Field successfully updated');
@@ -75,8 +77,10 @@ class DynamicFormsAjaxAPI extends AjaxController {
         if (!$list || !($item = $list->getItem( (int) $item_id)))
             Http::response(404, 'No such list item');
 
-        if (!$item->setConfiguration())
-            return (include STAFFINC_DIR . 'templates/list-item-properties.tmpl.php');
+        if (!$item->setConfiguration()) {
+            include STAFFINC_DIR . 'templates/list-item-properties.tmpl.php';
+            return;
+        }
         else
             $item->save();
 
diff --git a/include/class.forms.php b/include/class.forms.php
index 68175ed43d2cf98ac47865a74a793d5db7c465d3..98ae957cf003094fafa797867d1e42352fc2c96f 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -1260,6 +1260,13 @@ class FileUploadField extends FormField {
         if ($next < $limit * 2)
             $sizes[$limit] = Format::file_size($limit);
 
+        // Load file types
+        $_types = YamlDataParser::load(INCLUDE_DIR . '/config/filetype.yaml');
+        $types = array();
+        foreach ($_types as $type=>$info) {
+            $types[$type] = $info['description'];
+        }
+
         global $cfg;
         return array(
             'size' => new ChoiceField(array(
@@ -1268,11 +1275,16 @@ class FileUploadField extends FormField {
                 'default'=>$cfg->getMaxFileSize(),
                 'choices'=>$sizes
             )),
+            'mimetypes' => new ChoiceField(array(
+                'label'=>'Allowed File Types',
+                'hint'=>'Choose file types to accept. To accept any file, leave all unchecked',
+                'required'=>false,
+                'choices'=>$types,
+                'configuration'=>array('multiselect'=>true)
+            )),
             'extensions' => new TextareaField(array(
-                'label'=>'Allowed Extensions',
-                'hint'=>'Enter allowed file extensions separated by a comma.
-                e.g .doc, .pdf. To accept all files enter wildcard
-                <b><i>.*</i></b> — i.e dotStar (NOT Recommended).',
+                'label'=>'Allowed File Extensions',
+                'hint'=>'Accept files based only on the file extension. Enter comma-separated list of extensions. (e.g .doc, .pdf).',
                 'default'=>$cfg->getAllowedFileTypes(),
                 'configuration'=>array('html'=>false, 'rows'=>2),
             )),
@@ -1301,7 +1313,7 @@ class FileUploadField extends FormField {
         $file = array_shift($files);
         $file['name'] = urldecode($file['name']);
 
-        if (!$bypass && !$this->isValidFileType($file['name']))
+        if (!$bypass && !$this->isValidFileType($file['name'], $file['type']))
             Http::response(415, 'File type is not allowed');
 
         $config = $this->getConfiguration();
@@ -1319,7 +1331,7 @@ class FileUploadField extends FormField {
      * for browsers which do not support the HTML5 way of uploading async.
      */
     function uploadFile($file) {
-        if (!$this->isValidFileType($file['name']))
+        if (!$this->isValidFileType($file['name'], $file['type']))
             throw new FileUploadError(__('File type is not allowed'));
 
         $config = $this->getConfiguration();
@@ -1334,7 +1346,7 @@ class FileUploadField extends FormField {
      * sent other than via web upload
      */
     function uploadAttachment(&$file) {
-        if (!$this->isValidFileType($file['name']))
+        if (!$this->isValidFileType($file['name'], $file['type']))
             throw new FileUploadError(__('File type is not allowed'));
 
         if (is_callable($file['data']))
@@ -1360,16 +1372,18 @@ class FileUploadField extends FormField {
     function isValidFileType($name, $type=false) {
         $config = $this->getConfiguration();
 
-        // Return true if all file types are allowed (.*)
-        if (strpos($config['extensions'], '.*') || !$config['extensions'])
+        // Check MIME type - file ext. shouldn't be solely trusted.
+        if ($type && $config['__mimetypes']
+                && in_array($type, $config['__mimetypes']))
             return true;
 
-        $allowed = array_map('trim', explode(',', strtolower($config['extensions'])));
+        // Return true if all file types are allowed (.*)
+        if (strpos($config['__extensions'], '.*') || !$config['__extensions'])
+            return true;
 
+        $allowed = $config['__extensions'];
         $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
 
-        //TODO: Check MIME type - file ext. shouldn't be solely trusted.
-
         return ($ext && is_array($allowed) && in_array(".$ext", $allowed));
     }
 
@@ -1385,6 +1399,49 @@ class FileUploadField extends FormField {
         return $this->attachments ? $this->attachments->getAll() : array();
     }
 
+    function getConfiguration() {
+        $config = parent::getConfiguration();
+        $_types = YamlDataParser::load(INCLUDE_DIR . '/config/filetype.yaml');
+        $mimetypes = array();
+        $extensions = array();
+        if (isset($config['mimetypes']) && is_array($config['mimetypes'])) {
+            foreach ($config['mimetypes'] as $type=>$desc) {
+                foreach ($_types[$type]['types'] as $mime=>$exts) {
+                    $mimetypes[$mime] = true;
+                    foreach ($exts as $ext)
+                        $extensions['.'.$ext] = true;
+                }
+            }
+        }
+        if (strpos($config['extensions'], '.*') !== false)
+            $config['extensions'] = '';
+
+        foreach (preg_split('/\s+/', str_replace(',',' ', $config['extensions'])) as $ext) {
+            if (!$ext) {
+                continue;
+            }
+            elseif (strpos($ext, '/')) {
+                $mimetypes[$ext] = true;
+            }
+            else {
+                if ($ext[0] != '.')
+                    $ext = '.' . $ext;
+                // Add this to the MIME types list so it can be exported to
+                // the @accept attribute
+                if (!isset($extensions[$ext]))
+                    $mimetypes[$ext] = true;
+
+                $extensions[$ext] = true;
+            }
+        }
+        $config['__extensions'] = array_keys($extensions);
+
+        // 'mimetypes' is the array represented from the user interface,
+        // '__mimetypes' is a complete list of supported MIME types.
+        $config['__mimetypes'] = array_keys($mimetypes);
+        return $config;
+    }
+
     // When the field is saved to database, encode the ID listing as a json
     // array. Then, inspect the difference between the files actually
     // attached to this field
@@ -1835,7 +1892,8 @@ class FileUploadWidget extends Widget {
             <div class="dropzone"><i class="icon-upload"></i>
             Drop files here or <a href="#" class="manual">choose
             them</a>
-        <input type="file" class="multifile" multiple id="file-<?php echo $id; ?>" style="display:none;"/>
+        <input type="file" class="multifile" multiple id="file-<?php echo $id; ?>" style="display:none;"
+            accept="<?php echo implode(',', $config['__mimetypes']); ?>"/>
         </div></div>
         <script type="text/javascript">
         $(function(){$('#<?php echo $id; ?> .dropzone').filedropbox({
@@ -1843,8 +1901,10 @@ class FileUploadWidget extends Widget {
           link: $('#<?php echo $id; ?>').find('a.manual'),
           paramname: 'upload[]',
           fallback_id: 'file-<?php echo $id; ?>',
-          allowedfileextensions: '<?php echo $config['extensions'];
-          ?>'.split(/,\s*/),
+          allowedfileextensions: <?php echo JsonDataEncoder::encode(
+            $config['__extensions']); ?>,
+          allowedfiletypes: <?php echo JsonDataEncoder::encode(
+            $config['__mimetypes']); ?>,
           maxfiles: <?php echo $config['max'] ?: 20; ?>,
           maxfilesize: <?php echo ($config['size'] ?: 1048576) / 1048576; ?>,
           name: '<?php echo $name; ?>[]',
diff --git a/include/config/filetype.yaml b/include/config/filetype.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..dafd40109f0ece9aca82de1835373b36f652bed3
--- /dev/null
+++ b/include/config/filetype.yaml
@@ -0,0 +1,129 @@
+---
+image:
+  description: Images
+  types:
+    'image/bmp': ['bmp']
+    'image/gif': ['gif']
+    'image/jpeg': ['jpeg', 'jpg']
+    'image/png': ['png']
+    'image/svg+xml': ['svg']
+    'image/tiff': ['tiff']
+    'image/vnd.adobe.photoshop': ['psd']
+    'image/vnd.microsoft.icon': ['ico']
+    'image/x-ico': ['ico']
+    'application/postscript': ['eps']
+audio:
+  description: Audio and Music
+  types:
+    'audio/aiff': []
+    'audio/mpeg': ['mp3']
+    'audio/mp4': ['m4a', 'm4r', 'm4p']
+    'audio/ogg': ['ogg']
+    'audio/vorbis',
+    'audio/vnd.wav': ['wav']
+    'audio/wav': ['wav']
+    'audio/x-midi': ['mid', 'midi']
+text:
+  description: Text Documents
+  types:
+    'text/css': ['css']
+    'text/html': ['htm', 'html']
+    'text/javascript': ['js']
+    'text/plain': ['txt']
+    'text/xml': ['xml']
+    'application/json': ['json']
+    'application/javascript': ['js']
+office:
+  description: Common Office Documents
+  types:
+    # Microsoft Office
+    'application/msword': ['doc']
+    'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['docx']
+    'application/vnd.ms-word.document.macroEnabled.12': ['docm']
+    'application/vnd.ms-excel': ['xls']
+    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['xlsx']
+    'application/vnd.ms-excel.sheet.macroEnabled.12': ['xlsm']
+    'application/vnd.ms-excel.sheet.binary.macroEnabled.12': ['xlsb']
+    'application/vnd.ms-powerpoint': ['ppt']
+    'application/vnd.openxmlformats-officedocument.presentationml.presentation': ['pptx']
+    'application/vnd.openxmlformats-officedocument.presentationml.slideshow': ['ppsx']
+    'application/vnd.ms-powerpoint.presentation.macroEnabled.12': ['pptm']
+    'application/vnd.ms-powerpoint.slideshow.macroEnabled.12': ['ppsm']
+    'application/vnd.ms-access': ['mdb', 'accdb']
+    'application/vnd.ms-project': []
+    'application/msonenote': []
+    'application/vnd.ms-publisher': []
+    'application/rtf': ['rtf']
+    'application/vnd.ms-works': []
+
+    # iWork
+    'application/vnd.apple.keynote': ['keynote']
+    'application/vnd.apple.pages': ['pages']
+    'application/vnd.apple.numbers': ['numbers']
+
+    # OpenOffice
+    'application/vnd.oasis.opendocument.text': []
+    'application/vnd.oasis.opendocument.text-web': []
+    'application/vnd.oasis.opendocument.text-master': []
+    'application/vnd.oasis.opendocument.graphics': []
+    'application/vnd.oasis.opendocument.presentation': []
+    'application/vnd.oasis.opendocument.spreadsheet': []
+    'application/vnd.oasis.opendocument.chart': []
+    'application/vnd.oasis.opendocument.formula': []
+    'application/vnd.oasis.opendocument.database': []
+    'application/vnd.oasis.opendocument.image': []
+    'application/vnd.openofficeorg.extension': []
+
+    # Other office
+    'application/wordperfect': []
+    'application/vnd.kde.karbon': []
+    'application/vnd.kde.kchart': []
+    'application/vnd.kde.kformula': []
+    'application/vnd.kde.kivio': []
+    'application/vnd.kde.kontour': []
+    'application/vnd.kde.kpresenter': []
+    'application/vnd.kde.kspread': []
+    'application/vnd.kde.kword': []
+
+    # Creative / Common
+    'application/pdf': ['pdf']
+    '.csv': ['csv']
+    'application/illustrator': ['ai']
+    'application/x-director': []
+    'application/x-indesign': []
+
+    # Interchange
+    'text/vcard': []
+
+    # Other
+    'image/x-dwg': ['dwg']
+    'image/vnd.dwg': ['dwg']
+    'image/vnd.dxf': ['dxf']
+    'application/x-autocad': []
+    'application/x-mathcad': []
+    'application/x-msmoney': []
+
+    'application/x-latex': ['tex']
+video:
+  description: Video Files
+  types:
+    'video/avi': ['avi']
+    'video/mpeg': ['mpg','mpeg']
+    'video/mp4': ['mp4']
+    'video/ogg': ['ogg']
+    'video/quicktime': []
+    'video/webm': []
+    'video/x-ms-asf': []
+    'video/x-ms-wmv': []
+    'application/x-dvi': ['dvi']
+    'application/x-shockwave-flash': ['swf']
+archive:
+  description: Archives
+  types:
+    'application/tar': ['tar']
+    'application/gzip': ['gz']
+    'application/x-lha': []
+    'application/rar': ['rar']
+    'application/x-compress': ['z']
+    'application/zip': ['zip']
+    'application/x-7z-compressed': ['7z']
diff --git a/include/staff/dynamic-form.inc.php b/include/staff/dynamic-form.inc.php
index b160e2c253f9b993701ad18c7ad651bfcd88a358..e0bf6a4552b68b761ff0d78efb3fad9502acf4fa 100644
--- a/include/staff/dynamic-form.inc.php
+++ b/include/staff/dynamic-form.inc.php
@@ -277,17 +277,6 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 </div>
 
 <script type="text/javascript">
-$(function() {
-    var $this = $('#popup-loading').hide();
-    $(document).ajaxStart( function(event) {
-        console.log(1,event);
-        var $h1 = $this.find('h1');
-        $this.show();
-        $h1.css({'margin-top':$this.height()/3-$h1.height()/3});  // show Loading Div
-    }).ajaxStop ( function(){
-        $this.hide(); // hide loading div
-    });
-});
 $('form.manage-form').on('submit.inline', function(e) {
     var formObj = this, deleted = $('input.delete-box:checked', this);
     if (deleted.length) {
diff --git a/scp/css/scp.css b/scp/css/scp.css
index 27b80dfa0938eb7fdf3eaabb048f9269805d5a87..30c7dcb42c7ffea790b0ef27b0e963e75079ef88 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -1444,7 +1444,7 @@ time {
 }
 
 .dialog.draggable h3:hover {
-    cursor: crosshair;
+    cursor: move;
 }
 
 #advanced-search fieldset.span6 {