Subida de fotos múltiple

This commit is contained in:
Juan Ferrer Toribio 2017-05-08 17:54:35 +02:00
parent 871a089114
commit da007ff7c0
7 changed files with 312 additions and 131 deletions

View File

@ -2,36 +2,203 @@
Hedera.Photos = new Class Hedera.Photos = new Class
({ ({
Extends: Hedera.Form Extends: Hedera.Form
,filesData: []
,uploadCount: 0
,errors: false
,activate: function () ,activate: function ()
{ {
this.$('schema').value = 'catalog'; this.$('schema').value = 'catalog';
this.$('photo-id').focus ();
var self = this;
this.$('html-form').onsubmit = function ()
{ self._onSubmit (); return false; };
} }
,_onSubmit: function ()
{
this.$('schema-field').value = this.$('schema').value;
this.$('submit').disabled = true;
this.conn.sendFormMultipart (this.$('html-form'), ,addFiles: function (files)
this._onResponse.bind (this)); {
if (!files)
return;
for (var i = 0; i < files.length; i++)
this.addFile (files[i]);
} }
,_onResponse: function (json, error) ,addFile: function (file)
{ {
this.$('submit').disabled = false; var doc = document;
var div = doc.createElement ('div');
if (error) var button = new Htk.Button ({
throw error; tip: 'Remove',
icon: 'delete'
});
button.on ('click', this.onFileRemove, this);
div.appendChild (button.node);
this.$('photo-id').value = ''; var thumb = doc.createElement ('img');
this.$('photo-id').focus (); thumb.file = file;
Htk.Toast.showMessage (_('ImageAdded')); thumb.className = 'thumb';
div.appendChild (thumb);
var reader = new FileReader ();
reader.onload = function (e) { thumb.src = e.target.result; };
reader.readAsDataURL(file);
var name = doc.createElement ('input');
name.type = 'text';
name.value = getFileName (file.name);
div.appendChild (name);
var status = doc.createElement ('span');
status.className = 'status';
div.appendChild (status);
var fileData = {
div: div,
file: file,
name: name,
status: status,
sent: false,
loading : false
};
this.filesData.push (fileData);
button.value = fileData;
this.$('file-list').appendChild (div);
}
,onUploadClick: function ()
{
var filesData = this.filesData;
var formData = new FormData();
var count = 0;
for (var i = 0; i < filesData.length; i++)
{
var fileData = filesData[i];
if (!(fileData.sent || fileData.loading))
{
formData.set ('image', fileData.file);
formData.set ('name', fileData.name.value);
formData.set ('schema', this.$('schema').value);
formData.set ('srv', 'json:image/upload');
this.conn.sendFormData (formData,
this.onFileUpload.bind (this, fileData));
fileData.loading = true;
this.uploadCount++;
count++;
}
}
if (count === 0)
Htk.Toast.showWarning ('There are no files to upload');
}
,onFileUpload: function (fileData, data, error)
{
fileData.loading = false;
if (data)
{
var iconName = 'ok';
var title = _('ImageAdded');
fileData.sent = true;
fileData.name.disabled = true;
}
else
{
var iconName = 'error';
var title = error.message;
this.errors = true;
}
var status = fileData.status;
Vn.Node.removeChilds (status);
var icon = new Htk.Icon ({icon: iconName});
status.appendChild (icon.node);
status.title = title;
this.uploadCount--;
if (this.uploadCount === 0)
{
if (!this.errors)
Htk.Toast.showMessage (_('Upload finished successfully'));
else
Htk.Toast.showError (_('Some errors happened on upload'));
this.errors = false;
}
}
,onFileRemove: function (button)
{
var fileData = button.value;
this.$('file-list').removeChild (fileData.div);
for (var i = 0; i < this.filesData.length; i++)
if (this.filesData[i] === fileData)
{
this.filesData.splice (i, 1);
break;
}
}
,onClearClick: function ()
{
this.filesData = [];
Vn.Node.removeChilds (this.$('file-list'));
}
,onDropzoneClick: function ()
{
this.$('file').click ();
}
,onFileChange: function ()
{
this.addFiles (this.$('file').files);
}
,onDragEnter: function (event)
{
Vn.Node.addClass (this.$('dropzone'), 'dragover');
}
,onDragLeave: function (event)
{
Vn.Node.removeClass (this.$('dropzone'), 'dragover');
}
,onDragOver: function (event)
{
event.preventDefault ();
}
,onDragEnd: function (event)
{
Vn.Node.removeClass (this.$('dropzone'), 'dragover');
event.dataTransfer.clearData ();
}
,onDrop: function (event)
{
event.preventDefault ();
this.addFiles (event.dataTransfer.files);
} }
}); });
function getFileName (path)
{
var barIndex = path.lastIndexOf ('/');
if (barIndex === -1)
barIndex = path.lastIndexOf ('\\');
if (barIndex === -1)
barIndex = 0;
var dotIndex = path.lastIndexOf ('.');
if (dotIndex === -1)
dotIndex = 0;
return path.substr (barIndex, dotIndex);
}

View File

@ -5,27 +5,69 @@
} }
.photos .box .photos .box
{ {
max-width: 30em; max-width: 25em;
padding: 2em; padding: 2em;
} }
.photos .form
/* Dropzone */
.photos .dropzone
{ {
margin: 0 auto; background-color: white;
max-width: 25em; border-style: dashed;
border-radius: .4em;
border-color: #2196F3;
padding: 2em 1em;
text-align: center;
color: #666;
cursor: pointer;
} }
.photos iframe .photos .dropzone.dragover
{
color: #CCC;
border-style: solid;
}
.photos input[type=file]
{ {
display: none; display: none;
} }
/* Footer */ /* File list */
.photos input[type=submit] .photos .file-list
{ {
display: block; margin-top: 1em;
margin: 0 auto; }
padding: 0.6em; .photos .file-list > div
margin-top: 1.5em; {
font-size: 1.2em; height: 2.5em;
}
.photos .file-list .thumb
{
max-height: 2em;
max-width: 2em;
vertical-align: middle;
margin: 0 1em;
}
.photos .file-list input
{
max-width: 10em;
}
.photos .file-list .status
{
margin-left: .5em;
cursor: pointer;
} }
/* Footer */
.photos .footer
{
margin-top: 1.5em;
text-align: center;
}
.photos .footer > button
{
font-size: 1.2em;
margin-left: 1em;
}

View File

@ -4,36 +4,40 @@
</div> </div>
<div id="form" class="photos"> <div id="form" class="photos">
<div class="box"> <div class="box">
<div class="form"> <div class="form-group">
<form <label><t>Collection</t></label>
id="html-form" <htk-combo id="schema">
enctype="multipart/form-data"> <db-model property="model">
<input type="hidden" name="srv" value="json:image/upload"/> <custom>
<div class="form-group"> SELECT name, `desc` FROM image_schema ORDER BY `desc`
<label><t>Id</t></label> </custom>
<input type="number" name="id" id="photo-id"/> </db-model>
</div> </htk-combo>
<div class="form-group"> </div>
<label><t>ImageName</t></label> <div id="dropzone" class="dropzone"
<input type="text" name="name"/> on-dragenter="onDragEnter"
</div> on-dragleave="onDragLeave"
<div class="form-group"> on-mouseout="onDragLeave"
<label><t>Collection</t></label> on-dragover="onDragOver"
<htk-combo id="schema"> on-drop="onDrop"
<db-model property="model"> on-dragend="onDragEnd"
<custom> on-click="onDropzoneClick">
SELECT name, `desc` FROM image_schema ORDER BY `desc` Click or drop files here!
</custom> </div>
</db-model> <input
</htk-combo> id="file"
<input type="hidden" name="schema" id="schema-field"/> type="file"
</div> multiple="true"
<div class="form-group"> name="image"
<label><t>ImageFile</t></label> on-change="onFileChange"/>
<input type="file" name="image"/> <div id="file-list" class="file-list"/>
</div> <div class="footer">
<input id="submit" type="submit" class="thin"/> <button class="thin" on-click="onClearClick">
</form> <t>Clear all</t>
</button>
<button class="thin" on-click="onUploadClick">
<t>Upload files</t>
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -183,7 +183,7 @@ module.exports = new Class
if (this.token) if (this.token)
formData.append ('token', this.token); formData.append ('token', this.token);
var request = new XMLHttpRequest (); var request = new XMLHttpRequest ();
request.open ('post', form.action, true); request.open ('post', form.action, true);
request.onreadystatechange = request.onreadystatechange =
@ -193,6 +193,20 @@ module.exports = new Class
this._addRequest (); this._addRequest ();
} }
,sendFormData: function (formData, callback)
{
if (this.token)
formData.append ('token', this.token);
var request = new XMLHttpRequest ();
request.open ('post', '', true);
request.onreadystatechange =
this._onStateChange.bind (this, request, callback);
request.send (formData);
this._addRequest ();
}
/* /*
* Called when REST response is received. * Called when REST response is received.
*/ */

View File

@ -5,7 +5,7 @@ require_once (__DIR__.'/util.php');
/** /**
* Syncronizes the data directory with the database, this may take * Syncronizes the data directory with the database, this may take
* some time. * some time.
**/ */
class Sync extends Vn\Lib\Method class Sync extends Vn\Lib\Method
{ {
private $trashSubdir; private $trashSubdir;
@ -20,7 +20,7 @@ class Sync extends Vn\Lib\Method
function run () function run ()
{ {
$db = $this->getSysConn () $db = $this->getSysConn ();
set_time_limit (0); set_time_limit (0);
$this->$trashSubdir = date ('YmdHis'); $this->$trashSubdir = date ('YmdHis');
@ -111,7 +111,7 @@ class Sync extends Vn\Lib\Method
* Moves a data directory to the trash. * Moves a data directory to the trash.
* *
* @param string $file The file to move to the trash * @param string $file The file to move to the trash
**/ */
function moveTrash ($file) function moveTrash ($file)
{ {
$trashBasedir = "{$this->dataDir}/.trash/". $this->$trashSubdir; $trashBasedir = "{$this->dataDir}/.trash/". $this->$trashSubdir;

View File

@ -9,7 +9,7 @@ require_once (__DIR__.'/util.php');
* @param string $file The file name * @param string $file The file name
* @param integer $width The width of the thumb * @param integer $width The width of the thumb
* @param integer $height The height of the thumb * @param integer $height The height of the thumb
**/ */
class Thumb extends Vn\Web\RestRequest class Thumb extends Vn\Web\RestRequest
{ {
function run () function run ()
@ -64,7 +64,6 @@ class Thumb extends Vn\Web\RestRequest
throw new Exception ('Size not allowed'); throw new Exception ('Size not allowed');
// Creates the thumb. // Creates the thumb.
$util = new Util ($this->app); $util = new Util ($this->app);
$baseDir = "{$util->dataDir}/$schema"; $baseDir = "{$util->dataDir}/$schema";

View File

@ -7,80 +7,34 @@ use Vn\Lib\UserException;
/** /**
* Uploads a file creating its corresponding sizes. * Uploads a file creating its corresponding sizes.
**/ */
class Upload extends Vn\Web\JsonRequest class Upload extends Vn\Web\JsonRequest
{ {
const PARAMS = [
'name',
'schema'
];
function run ($db) function run ($db)
{ {
$util = new Util ($this->app); $util = new Util ($this->app);
// Checks schema.
$regexp = '/[^a-z0-9_]/';
if (empty ($_REQUEST['schema']) || preg_match ($regexp, $_REQUEST['schema']) !== 0)
throw new UserException (s('Bad schema name'));
$schema = $_REQUEST['schema']; $schema = $_REQUEST['schema'];
$name = $_REQUEST['name'];
// Checks schema
$info = $util->loadInfo ($schema); $info = $util->loadInfo ($schema);
if (!$info) if (!$info)
throw new UserException (s('Schema not exists')); throw new UserException (s('Schema not exists'));
// Checks file name and identifier. // Checks file name
$query = sprintf ( if (preg_match ('/[^a-z0-9_]/', $_REQUEST['name']) !== 0)
'SHOW INDEX FROM `%1$s`.`%2$s` WHERE Key_name = \'PRIMARY\''
,$info['schema']
,$info['table']
);
$pk = $db->getRow ($query);
if (!empty ($_REQUEST['id']) && empty ($_REQUEST['name']))
{
$query = sprintf (
'SELECT `%3$s` FROM `%1$s`.`%2$s` WHERE `%4$s` = #id'
,$info['schema']
,$info['table']
,$info['column']
,$pk['Column_name']
);
$_REQUEST['name'] = $db->getValue ($query,
['id' => $_REQUEST['id']]);
}
if (empty ($_REQUEST['name']) || preg_match ($regexp, $_REQUEST['name']) !== 0)
throw new UserException (s('Bad file name')); throw new UserException (s('Bad file name'));
// Checks permissions. // Checks for file errors
if (!empty ($_REQUEST['id']))
{
$filterColumn = $pk['Column_name'];
$filterValue = $_REQUEST['id'];
}
else
{
$filterColumn = $info['column'];
$filterValue = $_REQUEST['name'];
}
$query = sprintf (
'UPDATE `%1$s`.`%2$s` SET `%3$s` = #name WHERE `%4$s` = #filter LIMIT 1'
,$info['schema']
,$info['table']
,$info['column']
,$filterColumn
);
$params = [
'name' => $_REQUEST['name'],
'filter' => $filterValue
];
if (!$db->query ($query, $params))
throw new UserException (s('Permission denied'));
// Checks for file errors.
if (empty ($_FILES['image']['name'])) if (empty ($_FILES['image']['name']))
throw new UserException (s('File not choosed')); throw new UserException (s('File not choosed'));
@ -123,14 +77,15 @@ class Upload extends Vn\Web\JsonRequest
if ($_FILES['image']['size'] > $maxSize * 1048576) if ($_FILES['image']['size'] > $maxSize * 1048576)
throw new UserException (sprintf (s('File size error'), $maxSize)); throw new UserException (sprintf (s('File size error'), $maxSize));
// Resizes and saves the image. // Resizes and saves the image
$fileName = "{$_REQUEST['name']}.png"; $tmpName = $_FILES['image']['tmp_name'];
$fileName = "{$name}.png";
$schemaPath = "{$util->dataDir}/$schema"; $schemaPath = "{$util->dataDir}/$schema";
$fullFile = "$schemaPath/full/$fileName"; $fullFile = "$schemaPath/full/$fileName";
$symbolicSrc = "../full/$fileName"; $symbolicSrc = "../full/$fileName";
$image = Image::create ($_FILES['image']['tmp_name']); $image = Image::create ($tmpName);
Image::resizeSave ($image, $fullFile, $info['max_height'], $info['max_width']); Image::resizeSave ($image, $fullFile, $info['max_height'], $info['max_width']);
foreach ($info['sizes'] as $size => $i) foreach ($info['sizes'] as $size => $i)
@ -140,7 +95,7 @@ class Upload extends Vn\Web\JsonRequest
} }
imagedestroy ($image); imagedestroy ($image);
unlink ($_FILES['image']['tmp_name']); unlink ($tmpName);
return TRUE; return TRUE;
} }
} }