diff --git a/ckanext/odsh/fanstatic/odsh_guessformat.js b/ckanext/odsh/fanstatic/odsh_guessformat.js
new file mode 100644
index 0000000000000000000000000000000000000000..3efcbff85782b72b22f5dadc325a364ef6022ecf
--- /dev/null
+++ b/ckanext/odsh/fanstatic/odsh_guessformat.js
@@ -0,0 +1,36 @@
+
+ckan.module('odsh_guessformat', function ($)
+{
+    let known_formats = ['pdf', 'rdf', 'txt', 'doc', 'csv']
+
+
+    let c = $('#field-format')
+    let onChange = function (filename)
+    {
+        let ext = filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
+        if (ext !== undefined && known_formats.indexOf(ext) > -1)
+        {
+            c.val(ext.toUpperCase())
+        }
+    }
+    let onRemoved = function ()
+    {
+        c.val('')
+    }
+
+    return {
+        initialize: function ()
+        {
+            if (this.options.formats)
+                known_formats = this.options.formats
+
+            this.sandbox.subscribe('odsh_upload_filename_changed', onChange);
+            this.sandbox.subscribe('odsh_upload_filename_removed', onRemoved);
+        },
+        teardown: function ()
+        {
+            this.sandbox.unsubscribe('odsh_upload_filename_changed', onChange);
+            this.sandbox.unsubscribe('odsh_upload_filename_removed', onRemoved);
+        },
+    };
+});
\ No newline at end of file
diff --git a/ckanext/odsh/fanstatic/odsh_image-upload.js b/ckanext/odsh/fanstatic/odsh_image-upload.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b63a4250d4087717a85e9299b847c60e09dfaff
--- /dev/null
+++ b/ckanext/odsh/fanstatic/odsh_image-upload.js
@@ -0,0 +1,283 @@
+ /* Image Upload
+ *
+ */
+this.ckan.module('odsh_image-upload', function($) {
+  return {
+    /* options object can be extended using data-module-* attributes */
+    options: {
+      is_url: false,
+      is_upload: false,
+      field_upload: 'image_upload',
+      field_url: 'image_url',
+      field_clear: 'clear_upload',
+      field_name: 'name',
+      upload_label: ''
+    },
+
+    /* Should be changed to true if user modifies resource's name
+     *
+     * @type {Boolean}
+     */
+    _nameIsDirty: false,
+
+    /* Initialises the module setting up elements and event listeners.
+     *
+     * Returns nothing.
+     */
+    initialize: function () {
+      $.proxyAll(this, /_on/);
+      var options = this.options;
+
+      // firstly setup the fields
+      var field_upload = 'input[name="' + options.field_upload + '"]';
+      var field_url = 'input[name="' + options.field_url + '"]';
+      var field_clear = 'input[name="' + options.field_clear + '"]';
+      var field_name = 'input[name="' + options.field_name + '"]';
+
+      this.input = $(field_upload, this.el);
+      this.field_url = $(field_url, this.el).parents('.control-group');
+      this.field_image = this.input.parents('.control-group');
+      this.field_url_input = $('input', this.field_url);
+      this.field_name = this.el.parents('form').find(field_name);
+      // this is the location for the upload/link data/image label
+      this.label_location = $('label[for="field-image-url"]');
+      // determines if the resource is a data resource
+      this.is_data_resource = (this.options.field_url === 'url') && (this.options.field_upload === 'upload');
+
+      // Is there a clear checkbox on the form already?
+      var checkbox = $(field_clear, this.el);
+      if (checkbox.length > 0) {
+        checkbox.parents('.control-group').remove();
+      }
+
+      // Adds the hidden clear input to the form
+      this.field_clear = $('<input type="hidden" name="' + options.field_clear +'">')
+        .appendTo(this.el);
+
+      // Button to set the field to be a URL
+      this.button_url = $('<a href="javascript:;" class="btn">' +
+                          '<i class="fa fa-globe"></i>' +
+                          this._('Link') + '</a>')
+        .prop('title', this._('Link to a URL on the internet (you can also link to an API)'))
+        .on('click', this._onFromWeb)
+        .insertAfter(this.input);
+
+      // Button to attach local file to the form
+      this.button_upload = $('<a href="javascript:;" class="btn">' +
+                             '<i class="fa fa-cloud-upload"></i>' +
+                             this._('Upload') + '</a>')
+        .insertAfter(this.input);
+
+      // Button for resetting the form when there is a URL set
+      var removeText = this._('Remove');
+      $('<a href="javascript:;" class="btn btn-danger btn-remove-url">'
+        + removeText + '</a>')
+        .prop('title', removeText)
+        .on('click', this._onRemove)
+        .insertBefore(this.field_url_input);
+
+      // Update the main label (this is displayed when no data/image has been uploaded/linked)
+      $('label[for="field-image-upload"]').text(options.upload_label || this._('Image'));
+
+      // Setup the file input
+      this.input
+        .on('mouseover', this._onInputMouseOver)
+        .on('mouseout', this._onInputMouseOut)
+        .on('change', this._onInputChange)
+        .prop('title', this._('Upload a file on your computer'))
+        .css('width', this.button_upload.outerWidth());
+
+      // Fields storage. Used in this.changeState
+      this.fields = $('<i />')
+        .add(this.button_upload)
+        .add(this.button_url)
+        .add(this.input)
+        .add(this.field_url)
+        .add(this.field_image);
+
+      // Disables autoName if user modifies name field
+      this.field_name
+        .on('change', this._onModifyName);
+      // Disables autoName if resource name already has value,
+      // i.e. we on edit page
+      if (this.field_name.val()){
+        this._nameIsDirty = true;
+      }
+
+      if (options.is_url) {
+        this._showOnlyFieldUrl();
+
+        this._updateUrlLabel(this._('URL'));
+      } else if (options.is_upload) {
+        this._showOnlyFieldUrl();
+
+        this.field_url_input.prop('readonly', true);
+        // If the data is an uploaded file, the filename will display rather than whole url of the site
+        var filename = this._fileNameFromUpload(this.field_url_input.val());
+        this.field_url_input.val(filename);
+
+        this._updateUrlLabel(this._('File'));
+      } else {
+        this._showOnlyButtons();
+      }
+    },
+
+    /* Quick way of getting just the filename from the uri of the resource data
+     *
+     * url - The url of the uploaded data file
+     *
+     * Returns String.
+     */
+    _fileNameFromUpload: function(url) {
+      // remove fragment (#)
+      url = url.substring(0, (url.indexOf("#") === -1) ? url.length : url.indexOf("#"));
+      // remove query string
+      url = url.substring(0, (url.indexOf("?") === -1) ? url.length : url.indexOf("?"));
+      // extract the filename
+      url = url.substring(url.lastIndexOf("/") + 1, url.length);
+
+      return url; // filename
+    },
+
+    /* Update the `this.label_location` text
+     *
+     * If the upload/link is for a data resource, rather than an image,
+     * the text for label[for="field-image-url"] will be updated.
+     *
+     * label_text - The text for the label of an uploaded/linked resource
+     *
+     * Returns nothing.
+     */
+    _updateUrlLabel: function(label_text) {
+      if (! this.is_data_resource) {
+        return;
+      }
+
+      this.label_location.text(label_text);
+
+    },
+
+    /* Event listener for when someone sets the field to URL mode
+     *
+     * Returns nothing.
+     */
+    _onFromWeb: function() {
+      this._showOnlyFieldUrl();
+
+      this.field_url_input.focus()
+        .on('blur', this._onFromWebBlur);
+
+      if (this.options.is_upload) {
+        this.field_clear.val('true');
+      }
+
+      this._updateUrlLabel(this._('URL'));
+    },
+
+    /* Event listener for resetting the field back to the blank state
+     *
+     * Returns nothing.
+     */
+    _onRemove: function() {
+      this._showOnlyButtons();
+
+      this.field_url_input.val('');
+      this.field_url_input.prop('readonly', false);
+
+      this.field_clear.val('true');
+
+      this.sandbox.publish('odsh_upload_filename_removed');
+    },
+
+    /* Event listener for when someone chooses a file to upload
+     *
+     * Returns nothing.
+     */
+    _onInputChange: function() {
+      var file_name = this.input.val().split(/^C:\\fakepath\\/).pop();
+      this.field_url_input.val(file_name);
+      this.field_url_input.prop('readonly', true);
+
+      this.field_clear.val('');
+
+      this._showOnlyFieldUrl();
+
+      this._autoName(file_name);
+
+      this._updateUrlLabel(this._('File'));
+
+      this.sandbox.publish('odsh_upload_filename_changed', file_name);
+    },
+
+    /* Show only the buttons, hiding all others
+     *
+     * Returns nothing.
+     */
+    _showOnlyButtons: function() {
+      this.fields.hide();
+      this.button_upload
+        .add(this.field_image)
+        .add(this.button_url)
+        .add(this.input)
+        .show();
+    },
+
+    /* Show only the URL field, hiding all others
+     *
+     * Returns nothing.
+     */
+    _showOnlyFieldUrl: function() {
+      this.fields.hide();
+      this.field_url.show();
+    },
+
+    /* Event listener for when a user mouseovers the hidden file input
+     *
+     * Returns nothing.
+     */
+    _onInputMouseOver: function() {
+      this.button_upload.addClass('hover');
+    },
+
+    /* Event listener for when a user mouseouts the hidden file input
+     *
+     * Returns nothing.
+     */
+    _onInputMouseOut: function() {
+      this.button_upload.removeClass('hover');
+    },
+
+    /* Event listener for changes in resource's name by direct input from user
+     *
+     * Returns nothing
+     */
+    _onModifyName: function() {
+      this._nameIsDirty = true;
+    },
+
+    /* Event listener for when someone loses focus of URL field
+     *
+     * Returns nothing
+     */
+    _onFromWebBlur: function() {
+      var url = this.field_url_input.val().match(/([^\/]+)\/?$/)
+      if (url) {
+        this._autoName(url.pop());
+      }
+      let file_name = this.field_url_input.val();
+      console.log(file_name)
+      this.sandbox.publish('odsh_upload_filename_changed', file_name);
+    },
+
+    /* Automatically add file name into field Name
+     *
+     * Select by attribute [name] to be on the safe side and allow to change field id
+     * Returns nothing
+     */
+     _autoName: function(name) {
+        if (!this._nameIsDirty){
+          this.field_name.val(name);
+        }
+     }
+  };
+});
diff --git a/ckanext/odsh/helpers.py b/ckanext/odsh/helpers.py
index c40980224a522b36388162287e9560000099357e..e467ecc67ec7437596d973ab416f7fb837c65afe 100644
--- a/ckanext/odsh/helpers.py
+++ b/ckanext/odsh/helpers.py
@@ -8,6 +8,7 @@ import json
 from ckan.common import  c
 import  datetime
 from dateutil import parser
+from ckan.common import config
 
 get_action = logic.get_action
 log = logging.getLogger(__name__)
@@ -97,4 +98,9 @@ def odsh_get_spatial_text(pkg_dict):
 
 def odsh_render_datetime(datetime_, date_format='%d.%m.%Y'):
     dt = parser.parse(datetime_)
-    return dt.strftime(date_format)
\ No newline at end of file
+    return dt.strftime(date_format)
+
+def odsh_upload_known_formats():
+    value = config.get('ckanext.odsh.upload_formats', [])
+    value = toolkit.aslist(value)
+    return value
\ No newline at end of file
diff --git a/ckanext/odsh/plugin.py b/ckanext/odsh/plugin.py
index 4dcff1703b219f6a9bc6e910e2a5bf5bc0b8f4e3..93aff5c8d2ce526a2c214584482f417f3c2a154c 100644
--- a/ckanext/odsh/plugin.py
+++ b/ckanext/odsh/plugin.py
@@ -167,7 +167,8 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm
                 'odsh_get_resource_views': odsh_helpers.odsh_get_resource_views,
                 'odsh_get_bounding_box': odsh_helpers.odsh_get_bounding_box,
                 'odsh_get_spatial_text': odsh_helpers.odsh_get_spatial_text,
-                'odsh_render_datetime': odsh_helpers.odsh_render_datetime
+                'odsh_render_datetime': odsh_helpers.odsh_render_datetime,
+                'odsh_upload_known_formats': odsh_helpers.odsh_upload_known_formats
         }
 
     def before_map(self, map):
diff --git a/ckanext/odsh/public/odsh.css b/ckanext/odsh/public/odsh.css
index 17a7c1ba404c833abbd2dd431db9964970892e5e..c9a2418c526512f6993953016088150a255ea043 100644
--- a/ckanext/odsh/public/odsh.css
+++ b/ckanext/odsh/public/odsh.css
@@ -607,6 +607,9 @@ label:after {
     background-color: rgb(212,0,75);
     color:white;
 }
+.js .image-upload #field-image-url {
+   padding-right: 0px;
+}
 
 .btn {
     border-bottom-color: none;
@@ -1237,4 +1240,4 @@ display: none;
     /* text-align:center; */
     margin-top: 40px;
     margin-left: 400px;
-}
\ No newline at end of file
+}
diff --git a/ckanext/odsh/templates/ajax_snippets/fileformat.html b/ckanext/odsh/templates/ajax_snippets/fileformat.html
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/ckanext/odsh/templates/macros/form.html b/ckanext/odsh/templates/macros/form.html
index 2a847d9de6302115edfec0fe2e80cda288c31348..5e8607d825eb05221c950d27d68848f7975314a9 100644
--- a/ckanext/odsh/templates/macros/form.html
+++ b/ckanext/odsh/templates/macros/form.html
@@ -473,7 +473,7 @@ options - A list/tuple of fields to be used as <options>.
         {% set upload_label = upload_label or _('Image') %}
 
         {% if is_upload_enabled %}
-        <div class="image-upload" data-module="image-upload" data-module-is_url="{{ 'true' if is_url else 'false' }}"
+        <div class="image-upload" data-module="odsh_image-upload" data-module-is_url="{{ 'true' if is_url else 'false' }}"
             data-module-is_upload="{{ 'true' if is_upload else 'false' }}" data-module-field_url="{{ field_url }}"
             data-module-field_upload="{{ field_upload }}" data-module-field_clear="{{ field_clear }}"
             data-module-upload_label="{{ upload_label }}" data-module-field_name="{{ field_name }}">
diff --git a/ckanext/odsh/templates/package/snippets/resource_form.html b/ckanext/odsh/templates/package/snippets/resource_form.html
index 7c7a963fc11c7598adbd045290e7fe74297cb292..417553c637e3e490b5214a1aeb44d63ddac82529 100644
--- a/ckanext/odsh/templates/package/snippets/resource_form.html
+++ b/ckanext/odsh/templates/package/snippets/resource_form.html
@@ -1,3 +1,5 @@
+
+{% resource 'odsh/odsh_image-upload.js' %}
 {% import 'macros/form.html' as form %}
 
 {% set data = data or {} %}
@@ -64,6 +66,20 @@
     {{ form.input('mimetype_inner', id='field-mimetype-inner', label=_('MIME Type'), placeholder=_('eg.
     application/json'), value=data.mimetype_inner, error=errors.mimetype_inner, classes=[]) }}
     {% endif %}
+
+    
+    {% block basic_fields_format %}
+      {% resource 'odsh/odsh_guessformat.js' %}
+
+      {% set format_attrs = {'data-module': 'odsh_guessformat', 'data-module-formats':h.odsh_upload_known_formats()} %}
+
+      {% call form.input('format', id='field-format', label=_('Format'), placeholder=_('eg. CSV, XML or JSON'), value=data.format, error=errors.format, classes=['control-medium'],attrs=format_attrs) %}
+        <span class="info-block info-block-small">
+          <i class="fa fa-info-circle"></i>
+          {{ _('This will be guessed automatically. Leave blank if you wish') }}
+        </span>
+      {% endcall %}
+    {% endblock %}
     {% endblock %}
 
     <div class='row-fluid'>