<!-- 
/*
Copyright 2017 apHarmony

This file is part of jsHarmony.

jsHarmony is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

jsHarmony is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this package.  If not, see <http://www.gnu.org/licenses/>.
*/
-->
<script type="text/x-tutorial-info">
{
  "ID": "field_control_file",
  "Title": "File / Image Controls",
  "Menu": ["Models","Fields / Controls","Built-in Controls"],
  "Code": [
    "/models/FieldFile_Upload_Form.json",
    "/models/FieldFile_Download_Form.json",
    "/models/FieldFile_Download_Grid.json",
    "/models/FieldFile_Upload_DB_Form.json",
    "/models/FieldFile_Download_DB_Form.json",
    "/models/FieldFile_Download_DB_Grid.json",
    "/models/FieldFile_Upload_Image_Form.json",
    "/models/FieldFile_Upload_ImageThumbnails_Form.json",
    "/models/FieldFile_ImageListing_Form.json",
    "/models/FieldFile_ImageListing_Grid.json",
    "/models/FieldFile_Upload_Validation_Form.json"
  ],
  "Demo": [
    { "url": "jsHarmonyTutorials/FieldFile_Upload_Form?action=update&x_primary=1", "title": "File Upload Control - Basic" },
    { "url": "jsHarmonyTutorials/FieldFile_Download_Form?action=update&x_primary=1", "title": "File Download Control - Basic Form" },
    { "url": "jsHarmonyTutorials/FieldFile_Download_Grid", "title": "File Download Control - Basic Grid" },
    { "url": "jsHarmonyTutorials/FieldFile_Upload_DB_Form?action=update&cust_id=1", "title": "File Upload Control - Database Optimized" },
    { "url": "jsHarmonyTutorials/FieldFile_Download_DB_Form?action=update&cust_id=1", "title": "File Download Control - Database Optimized - Form" },
    { "url": "jsHarmonyTutorials/FieldFile_Download_DB_Grid", "title": "File Download Control - Database Optimized - Grid" },
    { "url": "jsHarmonyTutorials/FieldFile_Upload_Image_Form?action=update&x_primary=1", "title": "File Upload Control - Image Processing" },
    { "url": "jsHarmonyTutorials/FieldFile_Upload_ImageThumbnails_Form?action=update&x_primary=1", "title": "File Upload Control - Thumbnail Generation" },
    { "url": "jsHarmonyTutorials/FieldFile_ImageListing_Form?action=update&x_primary=1", "title": "Image Control - Form" },
    { "url": "jsHarmonyTutorials/FieldFile_ImageListing_Grid", "title": "Image Control - Grid" },
    { "url": "jsHarmonyTutorials/FieldFile_Upload_Validation_Form?action=update&x_primary=1", "title": "File Upload Validation" }
  ]
}
</script>

<h3>File Upload Control</h3>
The "file_upload" control is used to save a file per database record.  Files are stored in the file system, in the "data" folder.<br/>
<br/>
A basic file upload control can be added as follows:
<%-getScreenshot('jsHarmonyTutorials/FieldFile_Upload_Form?action=update&x_primary=1&popup=1','File Upload - Basic')%>
<pre>
{ 
  "table":"all_controls",
  "layout":"form",
  "onecolumn":true,
  "caption": "File Upload",
  "fields": [
    {"name":"x_primary", "type":"int", "key":1},
    {"name":"x_file","type":"file","caption":"x_file", "controlparams": { "data_folder": "tutorials_all_controls" }}
  ]
}
</pre>
Each file field requires a field.controlparams.data_folder property.  This defines in which folder under jsh.Config.datadir the file will be saved.<br/>
<br/>
A field with field.type="file" will automatically be set with field.control="file_upload" in form / form-m / exec / report layouts, and field.control="file_download" on grid layouts.<br/>
<br/>
The "file_upload" control has the following options:
<pre>
{
  "control": "file_upload",
  "controlparams": {
    "data_folder": "D",            //Subfolder name under "config.datadir" for the files, should be unique per data_file_prefix
    "data_file_prefix": "cust_doc",   //File name prefix {{PREFIX}}_{{KEY}}{{.EXT}} (Prefix defaults to field name if blank or not set)

    //System Parameters
    "_data_file_has_extension": false, //Whether the data file is saved with an extension
                                       //Automatically set to true if sqlparams.file_extension not set.
                                       //Slower because a directory search is required on each request.  

    //Interface parameters (Button Captions)
    //  By default, if controlparams.image or controlparams.thumbnails is defined, preview_button is enabled and download_button is not set
    //  Otherwise, for regular files, download_button is enabled and preview_button is not set
    "download_button": "Download", //Text for the download button (for downloading files)
    "preview_button": "View",      //Text for the preview button (for viewing images, opens in new browser window)
    "upload_button": "Upload",     //Text for the upload button
    "delete_button": "Delete",     //Text for the delete button
    "show_thumbnail": "small",     //Whether to display an image thumbnail.  If no thumbnails are defined, set to "true" to display the image
    "preview_on_click":true,       //Whether to link the thumbnail to the full image on click

    //Database parameters
    "sqlparams": {
      "file_size": "doc_size",     //File Size (updated on save)
      "file_extension": "doc_ext",       //File Extension (updated on save)
      "file_upload_timestamp": "doc_uptstmp", //Upload Timestamp - (updated on save - set to jsHarmony.Config.map.timestamp)
      "file_upload_user": "doc_upuser",         //Upload User - (updated on save - set to jsHarmony.Config.map.current_user)
      "file_name": "doc_filename"  //Alternate file name for when user downloads the file (read, but not saved, to database)
    },

    //Image Processing Parameters
    "image": {
      "format": "jpg", //jpg or png

      //Use one of the following properties to process the image after upload
      "crop": [800,600],   //Resizes and then crops the image to the target box
      "resize": [800,600], //Resizes the image to fit within the target box
      "resize": [225,75,{ "upsize": true, "extend":  true }], //Upsize = increase size if smaller
                                                              //Extend = increase size to max, then center content
      
    },
    "thumbnails": {
      "D_Medium": { //Thumbnail ID is used in the thumbnail file name: {{PREFIX}}_{{THUMBNAIL_ID}}_{{KEY}}{{.EXT}} 
        "format": "jpg", //jpg or png

        //Use one of the following properties to process the image after upload
        "crop": [800,600],   //Resizes and then crops the image to the target box
        "resize": [800,600], //Resizes the image to fit within the target box
        "resize": [225,75,{ "upsize": true, "extend":  true }], //Upsize = increase size if smaller
                                                                //Extend = increase size to max, then center content
      } 
    },
}
</pre>
The field.controlparams._data_file_has_extension property is a system-only parameter.  The property is automatically set to "true" if field.controlparams.sqlparams.file_extension is not set, so that the system knows that it needs to save the file extension with each file.

<h3>File Download Control</h3>
The "file_download" control enables downloading a previously uploaded file.  For example:

<%-getScreenshot('jsHarmonyTutorials/FieldFile_Download_Grid?popup=1','File Download')%>
<pre>
{ 
  "table":"all_controls",
  "layout":"grid",
  "caption": "File Download",
  "fields": [
    {"name":"x_primary", "type":"int", "key":1},
    {"name":"x_file","type":"file","control":"file_download","controlparams": { "data_folder": "tutorials_all_controls" },"caption":"x_file"},
    {"control": "label", "value":"Download", "link": "download:FieldFile_Download_Form&x_file","caption":"Download Link"}
  ]
}
</pre>
This example has both a "file_download" control and a label with a link, to illustrate the two methods of linking to a previously uploaded file.<br/>
<br/>
The "file_download" control is hidden when the file does not exist, since the "file_download" control additionally checks the file system to see whether a file has been uploaded.  The link, on the other hand, does not check the file system and is always displayed - if the user clicks on the link, a message will show that the download file was not found.<br/>
<br/>
The "file_download" control has the following options:
<pre>
{
  "control": "file_download",
  "controlparams": {
    "data_folder": "D",            //Subfolder name under "config.datadir" for the files, should be unique per data_file_prefix
    "data_file_prefix": "cust_doc",   //File name prefix {{PREFIX}}_{{KEY}}{{.EXT}} (Prefix defaults to field name if blank or not set)

    //System Parameters
    "_data_file_has_extension": false, //Whether the data file is saved with an extension
                                       //Automatically set to true if sqlparams.file_extension not set.
                                       //Slower because a directory search is required on each request.  

    //Interface parameters (Button Captions)
    "download_button": "Download", //Text for the download button (for downloading files)

    //Database parameters
    "sqlparams": {
      "file_extension": "doc_ext",       //File Extension (updated on save)
      "file_name": "doc_filename"  //Alternate file name for when user downloads the file (read, but not saved, to database)
    },
}
</pre>

<h3>File Upload w/Database Optimization</h3>
Since the "file_download" and "file_upload" backend needs to check the file system to see whether a file exists, this can become an I/O bottleneck in high-performance applications.  To solve this, the database can be updated when a user uploads and downloads the file, to store the file state in the database.<br/>
<br/>
The following file attributes can be stored in the database:
<ul>
  <li>file_size (File Size, in bytes)</li>
  <li>file_extension (File extension)</li>
  <li>file_upload_timestamp (Upload timestamp)</li>
  <li>file_upload_user (Upload user)</li>
</ul>
Additionally, the following parameter can be generated by the database during a file download:
<ul>
  <li>file_name (File name for the download operation)</li>
</ul>
The file database attributes are defined in the field.controlparams.sqlparams object.  For example:
<%-getScreenshot('jsHarmonyTutorials/FieldFile_Upload_DB_Form?action=update&cust_id=1&popup=1','File Upload - DB Optimized')%>
<pre>
{ 
  "table":"cust",
  "layout":"form",
  "onecolumn":true,
  "caption": "File Upload - DB Optimized",
  "fields": [
    {"name":"cust_id", "key":1,"caption":"ID"},
    {"name":"cust_doc","type":"file","control":"file_upload","caption":"Client Document",
      "controlparams": { 
        "data_folder": "tutorials_cust_doc",
        "sqlparams": {
          "file_size":   "cust_doc_size",
          "file_extension":    "cust_doc_ext",
          "file_name":   "cust_doc_filename",
          "file_upload_user":     "cust_doc_upuser",
          "file_upload_timestamp": "cust_doc_uptstmp"
        }
      }
    },
   {"name":"cust_doc_filename","sqlselect":"cust_id||cust_doc_ext","control":"hidden"}
  ]
}
</pre>
Each of the field.controlparams.sqlparams properties references a database column name.  If the database column is not already defined as a field in the current model, it will be automatically added.<br/>
<br/>
As a result, in the above model, the following SQL is generated for the select and update statements:
<pre>
Select
------
select cust_id, (cust_id||cust_doc_ext) as "cust_doc_filename", cust_doc_ext, cust_doc_size, cust_doc_uptstmp, cust_doc_upuser from cust where  1=1 and cust_id=@cust_id


Update
------
update cust set cust_doc_ext=@cust_doc_ext, cust_doc_size=@cust_doc_size, cust_doc_uptstmp=datetime('now','localtime'), cust_doc_upuser=(select context from jsharmony_meta limit 1) where 1=1 and cust_id=@cust_id

</pre>
The file_upload_timestamp parameter records the timestamp after each upload, and is bound to jsHarmony.Config.map.timestamp, which is defined as "get_tstmp" in jsHarmony Factory implementations.  The "get_tstmp" sql expression is defined in jsharmony-factory\models\sql\_global.DB.json, and can be overridden in the local application.<br/>
<br/>
Similarly, the file_upload_user parameter records the ID of the upload user after each upload, and is bound to jsHarmony.Config.map.current_user, which is defined as "context_user" in jsHarmony Factory implementations.  The "context_user" sql expression is defined in jsharmony-factory\models\sql\_global.DB.json, and can be overridden in the local application.<br/>
<br/>
The file_name parameter is used when downloading the file - it defines the file name of the downloaded file on the client's device.<br/>
<br/>
Defining the file_extension parameter results in faster performance, since the file extension does not need to be looked up (using a wildcard) every time the file is accessed or checked to see whether it exists.  This can be especially important for large file datasets.<br/>
<br/>
The "file_download" control with the database optimization is implemented as follows:
<%-getScreenshot('jsHarmonyTutorials/FieldFile_Download_DB_Grid?popup=1','File Download - DB Optimized')%>
<pre>
{ 
  "table":"cust",
  "layout":"grid",
  "caption": "File Download - DB Optimized",
  "fields": [
    {"name":"cust_id", "key":1,"caption":"ID"},
    {"name":"cust_doc","type":"file","control":"file_download","caption":"Client Document",
      "controlparams": { 
        "data_folder": "tutorials_cust_doc",
        "sqlparams": {
          "file_extension":    "cust_doc_ext",
          "file_name":   "cust_doc_filename"
        }
      }
    },
   {"name":"cust_doc_filename","sqlselect":"cust_id||cust_doc_ext","control":"hidden"}
  ]
}
</pre>

<h3>File Management Architecture</h3>
Files are stored in the folder defined by jsh.Config.datadir.  Each file is stored in the folder defined by field.controlparams.data_folder and field.controlparams.data_file_prefix.  If data_file_prefix is not set, it will default to the name of the field.<br/>
<br/>
File names are set as follows:
<pre>
Without field.controlparams.sqlparams.file_extension:
  Standard file / image:
    {DATA_FOLDER}\{DATA_FILE_PREFIX}_{PRIMARY_KEY_VALUE}.{file_extensionENSION}
  Thumbnail:
    {DATA_FOLDER}\{DATA_FILE_PREFIX}_{THUMBNAIL_ID}_{PRIMARY_KEY_VALUE}.{file_extensionENSION}

With field.controlparams.sqlparams.file_extension:
  Standard file / image:
    {DATA_FOLDER}\{DATA_FILE_PREFIX}_{PRIMARY_KEY_VALUE}
  Thumbnail:
    {DATA_FOLDER}\{DATA_FILE_PREFIX}_{THUMBNAIL_ID}_{PRIMARY_KEY_VALUE}
</pre>

The following process is used to upload files:
<ol>
  <li>While editing the record, a file is uploaded as a temporary file, using /_ul/, and assigned a temporary ID ("tempid")
    <ul>
      <li>/_ul/ can be used for a JSONP interface</li>
      <li>/_ul/json can be used for a JSON interface</li>
    </ul>
  </li>
  <li>Before the record is saved, the file can be downloaded using /_dl/_temp/:tempid</li>
  <li>On save:
    <ul>
      <li>A new file can be added/replaced by setting the field to the temporary ID: field_name=_temp/tempid.jpg</li>
      <li>An existing file can be deleted by setting the field to blank: field_name=</li>
      <li>No changes can be made by omitting the field from the post data</li>
    </ul>
  </li>
  <li>After the record is saved, a file can be downloaded using /_dl/:modelid/:keyid/:fieldname</li>
  <li>Each user has their own temporary data store.  This can be cleared by accessing /_ul/clear</li>
</ol>

A full listing of file-related routes is as follows:
<pre>
/_ul/               :: JSONP route for uploading a file to the temporary user store
/_ul/json           :: JSON route for uploading a file to the temporary user store
/_ul/clear          :: Route for clearing the temporary user store
/_ul/ckeditor       :: Route for uploading a CKEditor file to the shared cmsfiles subfolder
/_dl/_temp/:tempid  :: Route for downloading a file from the temporary user store
/_dl/:modelid/:keyid/:fieldname :: Route for downloading a saved file from the data folder
</pre>
Older files are automatically deleted from the temporary user store.  The file expiration is defined by the "user_temp_expiration" config setting.

<h3>Image Upload / Resizing</h3>
The "file_upload" control can also be used to upload and automatically resize / resample images:
<%-getScreenshot('jsHarmonyTutorials/FieldFile_Upload_Image_Form?action=update&x_primary=1&popup=1','Image Processing')%>
<pre>
{ 
  "table":"all_controls",
  "layout":"form",
  "onecolumn":true,
  "caption": "Image Upload",
  "fields": [
    {"name":"x_primary", "type":"int", "key":1},
    {"name":"x_image_basic","type":"file",
      "controlparams": {
        "data_folder": "tutorials_all_controls", 
        "image": {
          "format": "jpg"
        }
      }
    },
    {"name":"x_image_crop","type":"file",
      "controlparams": {
        "data_folder": "tutorials_all_controls", 
        "image": {
          "crop": [300,300],
          "format": "jpg"
        }
      }
    },
    {"name":"x_image_resize","type":"file",
      "controlparams": {
        "data_folder": "tutorials_all_controls", 
        "image": {
          "resize": [300,300],
          "format": "jpg"
        }
      }
    },
    {"name":"x_image_resize_extend","type":"file",
      "controlparams": {
        "data_folder": "tutorials_all_controls", 
        "image": {
          "resize": [300,300,{ "upsize": true, "extend":  true }],
          "format": "jpg"
        }
      }
    }
  ]
}
</pre>

<style type="text/css">
.field_control_file_image_samples div {
  border:1px solid black;
  display:inline-block;
}
</style>

Either "resize" or "crop" can be added to post-process the image so that it fits a target dimension.  Crop will resize the image to be larger than the bounding box and then crop the edges, while resize will resize the image to fit within the bounding box.<br/>
<br/>
Resize has two additional options: upsize and extend.  Upsize will increase the size of the image if it is initially smaller than the box.  Extend will add a white background so that the resulting image will be centered within the target box.<br/>
<br/>
Below are samples of the resulting images from the above model definition:<br/>
<br/>
<div class="field_control_file_image_samples">
  Basic Image (No resize or crop):<br/>
  <div><img src="/_dl/jsHarmonyTutorials/FieldFile_Upload_Image_Form/1/x_image_basic?view=1&_=<%=Date.now()%>&thumb=true" /></div><br/>
  <br/>
  Crop to 300x300:<br/>
  <div><img src="/_dl/jsHarmonyTutorials/FieldFile_Upload_Image_Form/1/x_image_crop?view=1&_=<%=Date.now()%>&thumb=true" /></div><br/>
  <br/>
  Resize to 300x300:<br/>
  <div><img src="/_dl/jsHarmonyTutorials/FieldFile_Upload_Image_Form/1/x_image_resize?view=1&_=<%=Date.now()%>&thumb=true" /></div><br/>
  <br/>
  Resize + Extend to 300x300:<br/>
  <div><img src="/_dl/jsHarmonyTutorials/FieldFile_Upload_Image_Form/1/x_image_resize_extend?view=1&_=<%=Date.now()%>&thumb=true" /></div><br/>
</div>
<br/>
Uploaded images can be embedded using the following URL:
<pre>
/_dl/:modelid/:keyid/:fieldname?view=1

The view option returns the file directly, instead of setting the headers to download the file as an attachment.

Additionally, it is recommended to add an "_" parameter with the current timestamp in order to block caching, so that the latest version of the image is always downloaded.

For example:
&lt;img src="/_dl/jsHarmonyTutorials/FieldFile_Upload_Image_Form/1/x_image_resize_extend?view=1&_=<%=Date.now()%>" /&gt;
</pre>

<h3>Image Thumbnails</h3>
In addition to post-processing the primary image, additional thumbnails can be generated during the file upload process using the "thumbnails" property:
<%-getScreenshot('jsHarmonyTutorials/FieldFile_Upload_ImageThumbnails_Form?action=update&x_primary=1&popup=1','Image Processing')%>
<pre>
{ 
  "table":"all_controls",
  "layout":"form",
  "onecolumn":true,
  "caption": "Image Upload - Thumbnails",
  "fields": [
    {"name":"x_primary", "type":"int", "key":1},
    {"name":"x_image_with_thumbnails","type":"file",
      "controlparams": {
        "data_folder": "tutorials_all_controls", 
        "image": {
          "resize": [800,600],
          "format": "jpg"
        },
        "thumbnails": {
          "small": { "format": "jpg", "crop": [100, 100] },
          "medium": { "format": "jpg", "resize": [400, 400, { "upsize": true, "extend": true }] }
        }
      }
    }
  ]
}
</pre>
Each thumbnail has the same "crop" and "resize" options as the primary image.<br/>
<br/>
The first thumbnail is displayed on the form after upload.  An alternate thumbnail can be selected for the preview via the field.controlparams.show_thumbnail property.

<h3>Image Control / Listing</h3>
Images can be embedded in grids and forms by using the "image" control.  The "image" control only displays if the image exists, avoiding broken image links.
<%-getScreenshot('jsHarmonyTutorials/FieldFile_ImageListing_Grid?popup=1','Image Listing')%>
<pre>
{ 
  "table":"all_controls",
  "layout":"grid",
  "caption": "Image Listing",
  "fields": [
    {"name":"x_primary", "type":"int", "key":1},
    {"name":"x_image_with_thumbnails","control":"image","type":"file","caption":"Image",
      "controlparams": { "data_folder": "tutorials_all_controls" },
      "controlstyle": "max-width: 200px; max-height: 100px;"
    },
    {"control":"image","type":"file","caption":"Thumbnail",
      "controlparams": {
        "data_folder": "tutorials_all_controls",
        "data_file_prefix": "x_image_with_thumbnails",
        "show_thumbnail": "small"
      }
    }
  ]
}
</pre>
In the example above, two thumbnail columns are displayed.<br/>
<br/>
The first "Image" column displays the full-size image, and uses the field.controlstyle property to fit the image into a 300px by 150px box.<br/>
<br/>
The second "Thumbnail" column displays the thumbnail instead.<br/>
<br/>
Where possible, it is recommended to use thumbnail display, since the images will load more quickly.<br/>
<br/>
Both columns link to a popup with the original image on click.  This behavior can be changed by setting field.controlparams.preview_on_click to false.<br/>
<br/>
The "image" control has the following options:
<pre>
{
  "control": "image",
  "controlparams": {
    "data_folder": "D",            //Subfolder name under "config.datadir" for the files, should be unique per data_file_prefix
    "data_file_prefix": "cust_doc",   //File name prefix {{PREFIX}}_{{KEY}}{{.EXT}} (Prefix defaults to field name if blank or not set)

    //System Parameters
    "_data_file_has_extension": false, //Whether the data file is saved with an extension
                                       //Automatically set to true if sqlparams.file_extension not set.
                                       //Slower because a directory search is required on each request.  

    //Interface parameters
    "show_thumbnail": "small",     //Whether to display an image thumbnail.  If no thumbnails are defined, set to "true" to display the image
    "preview_on_click":true,       //Whether to link the thumbnail to the full image on click

    //Database parameters
    "sqlparams": {
      "file_extension": "doc_ext",       //File Extension (updated on save)
      "file_name": "doc_filename"  //Alternate file name for when user downloads the file (read, but not saved, to database)
    },
}
</pre>

<h3>File Upload Validation</h3>
The field.type="file" has additional extended validation options for working with files:
<ul>
  <li>Extension:['.ext1','.ext2']</li>
  <li>Extension:jsh.Config.supported_images</li>
  <li>MaxSize:########</li>
</ul>

<b>Validator: Extension</b><br/>
The Extension validator ensures that the uploaded file has a specific file extension.  This is primarily used to ensure that the user does not make a mistake in uploading the file.<br/>
<br/>
The Extension validator accepts an array of values.  Additionally, the "jsh.Config.supported_images" variable can be used to limit the Extension validator to any image type that is supported by the image processing component (currently JPEG, GIF, and PNG).  Other arrays of file extensions can also be defined in jsh.Config.app_settings.<br/>
<br/>

<b>Validator: MaxSize</b><br/>
The MaxSize validator specifies the maximum file size in bytes.
<br/>

The following example uses file validators on two file_upload fields:
<%-getScreenshot('jsHarmonyTutorials/FieldFile_Upload_Validation_Form?x_primary=1&action=update&popup=1','File Upload Validation')%>
<pre>
{ 
  "table":"all_controls",
  "layout":"form",
  "onecolumn":true,
  "caption": "File Upload Validation",
  "fields": [
    {"name":"x_primary", "type":"int", "key":1},
    {"name":"x_file1","type":"file","caption":"Small Image", "controlparams": { "data_folder": "tutorials_all_controls" },
      "validate": ["Extension:jsh.Config.supported_images","MaxSize:100000"]
    },
    {"name":"x_file2","type":"file","caption":"Excel File", "controlparams": { "data_folder": "tutorials_all_controls" },
      "validate": ["Extension:['.XLS','.XLSX','.XLSM']","Required"]
    }
  ]
}
</pre>

<h3>File System Parameters</h3>
The following file-related system config parameters are available:
<pre>
//Full list of valid extensions that can be uploaded into the system
jsh.Config.valid_extensions = [".jpg", ".jpeg", ".pdf", ".png", ".gif", ".txt", ".xlsm", ".xls", ".xlsx", ".bak", ".zip", ".csv"];

//Images supported for crop / resize / thumbnails
jsh.Config.supported_images = ['.jpg','.jpeg','.gif','.png'];

//Data folder (defaults to /data)
jsh.Config.datadir = '';

//Maximum file upload size (50MB)
jsh.Config.max_filesize = 50000000;

//Maximum file storage in User Temp Folder (50MB)
jsh.Config.max_user_temp_foldersize = 50000000;

//Seconds before Public Temp Folder files are deleted on next upload.  Default is 5 minutes
jsh.Config.public_temp_expiration = 5 * 60;

//Seconds before User Temp Folder files are deleted on next upload.  Default is 6 hours
jsh.Config.user_temp_expiration = 6 * 60 * 60;
</pre>