#9663 Update items with matching id option when uploading image
This commit is contained in:
parent
0ae35c2622
commit
6ec94de7a3
|
@ -1,4 +1,4 @@
|
|||
hedera-web (1.406.28) stable; urgency=low
|
||||
hedera-web (1.406.29) stable; urgency=low
|
||||
|
||||
* Initial Release.
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
Images: Imatges
|
||||
Collection: Col·lecció
|
||||
Click or drop files here: Prem o deixa anar els arxius aquí
|
||||
Pending upload: Pujada pendent
|
||||
Update items with matching id: Actualitzar els elements amb id coincident
|
||||
Clear all: Netejar tot
|
||||
Upload files: Pujar arxius
|
||||
Waiting for upload: Esperant per pujar
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
Images: Images
|
||||
Collection: Collection
|
||||
Click or drop files here: Click or drop files here
|
||||
Pending upload: Pending upload
|
||||
Update items with matching id: Update items with matching id
|
||||
Clear all: Clear all
|
||||
Upload files: Upload files
|
||||
Waiting for upload: Waiting for upload
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
Images: Imágenes
|
||||
Collection: Colección
|
||||
Click or drop files here: Pulsa o suelta los archivos aquí
|
||||
Pending upload: Subida pendiente
|
||||
Update items with matching id: Actualizar ítems con id coincidente
|
||||
Clear all: Limpiar todo
|
||||
Upload files: Subir archivos
|
||||
Waiting for upload: Esperando para subir
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
Images: Images
|
||||
Collection: Collection
|
||||
Click or drop files here: Cliquez ici ou déposer des fichiers
|
||||
Pending upload: Hausse en attente
|
||||
Update items with matching id: Mettre à jour les éléments avec l'identifiant correspondant
|
||||
Clear all: Tout effacer
|
||||
Upload files: Upload Files
|
||||
Waiting for upload: En attente de télécharger
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
Images: Imagens
|
||||
Collection: Coleção
|
||||
Click or drop files here: Clique ou solte arquivos aqui
|
||||
Pending upload: Ascensão pendente
|
||||
Update items with matching id: Atualizar itens com id correspondente
|
||||
Clear all: Limpar tudo
|
||||
Upload files: Fazer upload de arquivos
|
||||
Waiting for upload: Esperando para enviar
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
(function() {
|
||||
|
||||
var Status = {
|
||||
NONE : 0
|
||||
,WAITING : 1
|
||||
|
@ -16,220 +15,200 @@ Hedera.Photos = new Class
|
|||
,uploadQueue: []
|
||||
,isUploading: false
|
||||
|
||||
,activate: function ()
|
||||
{
|
||||
,activate: function() {
|
||||
this.$('schema').value = 'catalog';
|
||||
}
|
||||
|
||||
,addFiles: function (files)
|
||||
{
|
||||
,addFiles: function(files) {
|
||||
if (!files)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < files.length; i++)
|
||||
this.addFile (files[i]);
|
||||
this.addFile(files[i]);
|
||||
}
|
||||
|
||||
,addFile: function (file)
|
||||
{
|
||||
,addFile: function(file) {
|
||||
var doc = document;
|
||||
var div = doc.createElement ('div');
|
||||
var li = doc.createElement('div');
|
||||
|
||||
var button = new Htk.Button ({
|
||||
var div = doc.createElement('div');
|
||||
div.className = 'thumb';
|
||||
li.appendChild(div);
|
||||
|
||||
var thumb = doc.createElement('img');
|
||||
thumb.file = file;
|
||||
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);
|
||||
li.appendChild(name);
|
||||
|
||||
var statusNode = doc.createElement('div');
|
||||
statusNode.className = 'status';
|
||||
li.appendChild(statusNode);
|
||||
|
||||
var button = new Htk.Button({
|
||||
tip: 'Remove',
|
||||
icon: 'delete'
|
||||
});
|
||||
button.on ('click', this.onFileRemove, this);
|
||||
div.appendChild (button.node);
|
||||
|
||||
var thumb = doc.createElement ('img');
|
||||
thumb.file = file;
|
||||
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 statusNode = doc.createElement ('span');
|
||||
statusNode.className = 'status';
|
||||
div.appendChild (statusNode);
|
||||
button.on('click', this.onFileRemove, this);
|
||||
li.appendChild(button.node);
|
||||
|
||||
var fileData = {
|
||||
div: div,
|
||||
li: li,
|
||||
file: file,
|
||||
name: name,
|
||||
statusNode: statusNode,
|
||||
status: Status.NONE
|
||||
statusNode: statusNode
|
||||
};
|
||||
this.filesData.push (fileData);
|
||||
this.filesData.push(fileData);
|
||||
button.value = fileData;
|
||||
|
||||
this.$('file-list').appendChild (div);
|
||||
this.$('file-list').appendChild(li);
|
||||
this.setImageStatus(fileData, Status.NONE, 'add', _('Pending upload'));
|
||||
}
|
||||
|
||||
,onUploadClick: function ()
|
||||
{
|
||||
,onUploadClick: function() {
|
||||
var filesData = this.filesData;
|
||||
var count = 0;
|
||||
|
||||
for (var i = 0; i < filesData.length; i++)
|
||||
{
|
||||
for (var i = 0; i < filesData.length; i++) {
|
||||
var fileData = filesData[i];
|
||||
|
||||
if (fileData.status === Status.NONE)
|
||||
{
|
||||
this.setImageStatus (
|
||||
if (fileData.status === Status.NONE) {
|
||||
this.setImageStatus(
|
||||
fileData, Status.WAITING, 'cloud-upload', _('Waiting for upload'));
|
||||
fileData.name.disabled = true;
|
||||
this.uploadQueue.push (fileData);
|
||||
this.uploadQueue.push(fileData);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count === 0)
|
||||
Htk.Toast.showWarning (_('There are no files to upload'));
|
||||
Htk.Toast.showWarning(_('There are no files to upload'));
|
||||
else
|
||||
this.uploadNextFile ();
|
||||
this.uploadNextFile();
|
||||
}
|
||||
|
||||
,uploadNextFile: function ()
|
||||
{
|
||||
,uploadNextFile: function() {
|
||||
if (this.isUploading)
|
||||
return;
|
||||
|
||||
this.isUploading = true;
|
||||
|
||||
var fileData = this.uploadQueue.shift ();
|
||||
this.setImageStatus (
|
||||
var fileData = this.uploadQueue.shift();
|
||||
this.setImageStatus(
|
||||
fileData, Status.UPLOADING, 'upload', _('Uploading file'));
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append ('image', fileData.file);
|
||||
formData.append ('name', fileData.name.value);
|
||||
formData.append ('schema', this.$('schema').value);
|
||||
formData.append ('srv', 'json:image/upload');
|
||||
this.conn.sendFormData (formData,
|
||||
this.onFileUpload.bind (this, fileData));
|
||||
formData.append('updateMatching', this.$('update-matching').value);
|
||||
formData.append('image', fileData.file);
|
||||
formData.append('name', fileData.name.value);
|
||||
formData.append('schema', this.$('schema').value);
|
||||
formData.append('srv', 'json:image/upload');
|
||||
this.conn.sendFormData(formData,
|
||||
this.onFileUpload.bind(this, fileData));
|
||||
}
|
||||
|
||||
,onFileUpload: function (fileData, data, error)
|
||||
{
|
||||
,onFileUpload: function(fileData, data, error) {
|
||||
this.isUploading = false;
|
||||
|
||||
if (data)
|
||||
{
|
||||
this.setImageStatus (
|
||||
if (data) {
|
||||
this.setImageStatus(
|
||||
fileData, Status.UPLOADED, 'ok', _('Image uploaded'));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.setImageStatus (
|
||||
} else {
|
||||
this.setImageStatus(
|
||||
fileData, Status.NONE, 'error', error.message);
|
||||
fileData.name.disabled = false;
|
||||
this.errors = true;
|
||||
}
|
||||
|
||||
if (this.uploadQueue.length === 0)
|
||||
{
|
||||
if (this.uploadQueue.length === 0) {
|
||||
if (this.errors)
|
||||
Htk.Toast.showError (_('Some errors happened on upload'));
|
||||
Htk.Toast.showError(_('Some errors happened on upload'));
|
||||
else
|
||||
Htk.Toast.showMessage (_('Upload finished successfully'));
|
||||
Htk.Toast.showMessage(_('Upload finished successfully'));
|
||||
|
||||
this.errors = false;
|
||||
}
|
||||
else
|
||||
this.uploadNextFile ();
|
||||
} else
|
||||
this.uploadNextFile();
|
||||
}
|
||||
|
||||
,setImageStatus: function (fileData, status, icon, title)
|
||||
{
|
||||
,setImageStatus: function(fileData, status, icon, title) {
|
||||
fileData.status = status;
|
||||
|
||||
var statusNode = fileData.statusNode;
|
||||
Vn.Node.removeChilds (statusNode);
|
||||
Vn.Node.removeChilds(statusNode);
|
||||
|
||||
var iconNode = new Htk.Icon ({icon: icon});
|
||||
statusNode.appendChild (iconNode.node);
|
||||
var iconNode = new Htk.Icon({icon: icon});
|
||||
statusNode.appendChild(iconNode.node);
|
||||
statusNode.title = title ? title : '';
|
||||
}
|
||||
|
||||
,onFileRemove: function (button)
|
||||
{
|
||||
,onFileRemove: function(button) {
|
||||
var fileData = button.value;
|
||||
this.$('file-list').removeChild (fileData.div);
|
||||
this.$('file-list').removeChild(fileData.li);
|
||||
|
||||
for (var i = 0; i < this.filesData.length; i++)
|
||||
if (this.filesData[i] === fileData)
|
||||
{
|
||||
this.filesData.splice (i, 1);
|
||||
if (this.filesData[i] === fileData) {
|
||||
this.filesData.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
,onClearClick: function ()
|
||||
{
|
||||
,onClearClick: function() {
|
||||
this.filesData = [];
|
||||
Vn.Node.removeChilds (this.$('file-list'));
|
||||
Vn.Node.removeChilds(this.$('file-list'));
|
||||
}
|
||||
|
||||
,onDropzoneClick: function ()
|
||||
{
|
||||
this.$('file').click ();
|
||||
,onDropzoneClick: function() {
|
||||
this.$('file').click();
|
||||
}
|
||||
|
||||
,onFileChange: function ()
|
||||
{
|
||||
this.addFiles (this.$('file').files);
|
||||
,onFileChange: function() {
|
||||
this.addFiles(this.$('file').files);
|
||||
}
|
||||
|
||||
,onDragEnter: function (event)
|
||||
{
|
||||
Vn.Node.addClass (this.$('dropzone'), 'dragover');
|
||||
,onDragEnter: function() {
|
||||
this.$('dropzone').classList.add('dragover');
|
||||
}
|
||||
|
||||
,onDragLeave: function (event)
|
||||
{
|
||||
Vn.Node.removeClass (this.$('dropzone'), 'dragover');
|
||||
,onDragLeave: function() {
|
||||
this.$('dropzone').classList.remove('dragover');
|
||||
}
|
||||
|
||||
,onDragOver: function (event)
|
||||
{
|
||||
event.preventDefault ();
|
||||
,onDragOver: function(event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
,onDragEnd: function (event)
|
||||
{
|
||||
Vn.Node.removeClass (this.$('dropzone'), 'dragover');
|
||||
event.dataTransfer.clearData ();
|
||||
,onDragEnd: function(event) {
|
||||
this.$('dropzone').classList.remove('dragover');
|
||||
event.dataTransfer.clearData();
|
||||
}
|
||||
|
||||
,onDrop: function (event)
|
||||
{
|
||||
event.preventDefault ();
|
||||
this.addFiles (event.dataTransfer.files);
|
||||
,onDrop: function(event) {
|
||||
event.preventDefault();
|
||||
this.addFiles(event.dataTransfer.files);
|
||||
}
|
||||
});
|
||||
|
||||
function getFileName (path)
|
||||
{
|
||||
var barIndex = path.lastIndexOf ('/');
|
||||
function getFileName(path) {
|
||||
var barIndex = path.lastIndexOf('/');
|
||||
if (barIndex === -1)
|
||||
barIndex = path.lastIndexOf ('\\');
|
||||
barIndex = path.lastIndexOf('\\');
|
||||
if (barIndex === -1)
|
||||
barIndex = 0;
|
||||
|
||||
var dotIndex = path.lastIndexOf ('.');
|
||||
var dotIndex = path.lastIndexOf('.');
|
||||
if (dotIndex === -1)
|
||||
dotIndex = 0;
|
||||
|
||||
return path.substr (barIndex, dotIndex);
|
||||
return path.substr(barIndex, dotIndex);
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
|
||||
.photos
|
||||
{
|
||||
.photos {
|
||||
padding: 1em;
|
||||
}
|
||||
.photos .box
|
||||
{
|
||||
.photos .box {
|
||||
max-width: 25em;
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
/* Dropzone */
|
||||
|
||||
.photos .dropzone
|
||||
{
|
||||
.photos .dropzone {
|
||||
background-color: white;
|
||||
border-style: dashed;
|
||||
border-radius: .4em;
|
||||
|
@ -22,52 +19,71 @@
|
|||
color: #666;
|
||||
cursor: pointer;
|
||||
}
|
||||
.photos .dropzone.dragover
|
||||
{
|
||||
.photos .dropzone.dragover {
|
||||
color: #CCC;
|
||||
border-style: solid;
|
||||
}
|
||||
.photos input[type=file]
|
||||
{
|
||||
.photos input[type=file] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* File list */
|
||||
|
||||
.photos .file-list
|
||||
{
|
||||
.photos .file-list {
|
||||
margin-top: 1em;
|
||||
}
|
||||
.photos .file-list > div
|
||||
{
|
||||
.photos .file-list > div {
|
||||
height: 2.5em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.photos .file-list .thumb
|
||||
{
|
||||
.photos .file-list > div > * {
|
||||
overflow: hidden;
|
||||
}
|
||||
.photos .file-list .thumb {
|
||||
width: 2em;
|
||||
padding-right: .5em;
|
||||
text-align: center;
|
||||
}
|
||||
.photos .file-list .thumb > img {
|
||||
max-height: 2em;
|
||||
max-width: 2em;
|
||||
vertical-align: middle;
|
||||
margin: 0 1em;
|
||||
}
|
||||
.photos .file-list input
|
||||
{
|
||||
max-width: 10em;
|
||||
.photos .file-list input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.photos .file-list .status
|
||||
{
|
||||
margin-left: .5em;
|
||||
.photos .file-list .status {
|
||||
cursor: pointer;
|
||||
width: 1em;
|
||||
padding-left: .5em;
|
||||
padding-right: .5em;
|
||||
}
|
||||
.photos .file-list .status > img {
|
||||
display: block;
|
||||
}
|
||||
.photos .file-list .htk-button {
|
||||
opacity: .2;
|
||||
}
|
||||
.photos .file-list .htk-button:hover {
|
||||
background-color: transparent;
|
||||
opacity: 1;
|
||||
}
|
||||
.photos .file-list .htk-button > img {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
|
||||
.photos .footer
|
||||
{
|
||||
.photos .update-matching {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
.photos .footer {
|
||||
margin-top: 1.5em;
|
||||
text-align: center;
|
||||
}
|
||||
.photos .footer > button
|
||||
{
|
||||
.photos .footer > button {
|
||||
font-size: 1.2em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,12 @@
|
|||
name="image"
|
||||
on-change="onFileChange"/>
|
||||
<div id="file-list" class="file-list"/>
|
||||
<div class="update-matching">
|
||||
<label>
|
||||
<htk-check id="update-matching" value="true"/>
|
||||
<t>Update items with matching id</t>
|
||||
</label>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<button class="thin" on-click="onClearClick">
|
||||
<t>Clear all</t>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "hedera-web",
|
||||
"version": "1.406.28",
|
||||
"version": "1.406.29",
|
||||
"description": "Verdnatura web page",
|
||||
"license": "GPL-3.0",
|
||||
"repository": {
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
,"File save error": "Failed to save the file: %s"
|
||||
,"File size error": "The file must be no longer than %.2f MB"
|
||||
,"Bad file name": "The file name must contain only lowercase letters, digits or the '_' character"
|
||||
,"Bad schema name": "Invalid schema name"
|
||||
,"Schema not exists": "Schema does not exist"
|
||||
,"Bad collection name": "Invalid collection name"
|
||||
,"Collection not exists": "Collection does not exist"
|
||||
,"Unreferenced file": "The file is not referenced by the database"
|
||||
,"Cannot update matching id": "Cannot update matching id"
|
||||
,"Com error": "Error communicating with the server"
|
||||
,"Image open error": "Error opening the image file"
|
||||
,"Operation disabled": "Operation disabled for security"
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
,"File save error": "Error al guardar el fichero: %s"
|
||||
,"File size error": "El fichero no debe ocupar más de %.2f MB"
|
||||
,"Bad file name": "El nombre del archivo solo debe contener letras minúsculas, dígitos o el carácter '_'"
|
||||
,"Bad schema name": "Nombre de esquema no válido"
|
||||
,"Schema not exists": "El esquema no existe"
|
||||
,"Bad collection name": "Nombre de colección no válido"
|
||||
,"Collection not exists": "La colección no existe"
|
||||
,"Unreferenced file": "El archivo no está referenciado por la base de datos"
|
||||
,"Cannot update matching id": "No es posible actualizar los ítems con id coincidente"
|
||||
,"Com error": "Error en la comunicación con el servidor"
|
||||
,"Image open error": "Error al abrir el archivo de imagen"
|
||||
,"Operation disabled": "Operación deshabilitada por seguridad"
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
,"File save error": "Erro ao salvar o arquivo: %s"
|
||||
,"File size error": "O arquivo não deve ser maior que: %.2f MB"
|
||||
,"Bad file name": "O nome do arquivo deve conter somente letras minusculas, numeros ou '_' "
|
||||
,"Bad schema name": "Nome de esquema inválido"
|
||||
,"Schema not exists": "Esquema não existe"
|
||||
,"Bad collection name": "Nome de coleção inválido"
|
||||
,"Collection not exists": "Coleção não existe"
|
||||
,"Unreferenced file": "O arquivo não é referenciado pelo banco de dados"
|
||||
,"Cannot update matching id": "Não é possível atualizar os itens com id coincidente"
|
||||
,"Com error": "Erro de comunicação com o servidor"
|
||||
,"Image open error": "Erro ao abrir a imagem"
|
||||
,"Operation disabled": "Operação desativada por segurança"
|
||||
|
|
|
@ -11,25 +11,26 @@ use Vn\Lib\UserException;
|
|||
class Upload extends Vn\Web\JsonRequest {
|
||||
const PARAMS = [
|
||||
'name',
|
||||
'schema'
|
||||
'schema',
|
||||
'updateMatching'
|
||||
];
|
||||
|
||||
function run($db) {
|
||||
$util = new Util($this->app);
|
||||
|
||||
$schema = $_REQUEST['schema'];
|
||||
$collection = $_REQUEST['schema'];
|
||||
$name = $_REQUEST['name'];
|
||||
|
||||
// Checks schema
|
||||
|
||||
$info = $util->loadInfo($schema);
|
||||
$info = $util->loadInfo($collection);
|
||||
|
||||
if (!$info)
|
||||
throw new UserException(s('Schema not exists'));
|
||||
throw new UserException(s('Collection not exists'));
|
||||
|
||||
// Checks file name
|
||||
|
||||
if (preg_match('/[^a-z0-9_]/', $_REQUEST['name']) !== 0)
|
||||
if (preg_match('/[^a-z0-9_]/', $name) !== 0)
|
||||
throw new UserException(s('Bad file name'));
|
||||
|
||||
// Checks for file errors
|
||||
|
@ -73,19 +74,35 @@ class Upload extends Vn\Web\JsonRequest {
|
|||
if ($_FILES['image']['size'] > $maxSize * 1048576)
|
||||
throw new UserException(sprintf(s('File size error'), $maxSize));
|
||||
|
||||
// Updates items with matching id, when option is checked
|
||||
|
||||
if ($_REQUEST['updateMatching'] === 'true') {
|
||||
$schema = $db->quote($info['schema']);
|
||||
$table = $db->quote($info['table']);
|
||||
$column = $db->quote($info['column']);
|
||||
|
||||
$pk = $db->getRow ("SHOW INDEX FROM $schema.$table WHERE Key_name = 'PRIMARY'");
|
||||
if (!pk) throw new UserException(s('Cannot update matching id'));
|
||||
|
||||
$pkColumn = $db->quote($pk['Column_name']);
|
||||
|
||||
$query = "UPDATE $schema.$table SET $column = #name WHERE $pkColumn = #name LIMIT 1";
|
||||
$db->query ($query, ['name' => $name]);
|
||||
}
|
||||
|
||||
// Resizes and saves the image
|
||||
|
||||
$tmpName = $_FILES['image']['tmp_name'];
|
||||
$fileName = "{$name}.png";
|
||||
$schemaPath = "{$util->dataDir}/$schema";
|
||||
$fullFile = "$schemaPath/full/$fileName";
|
||||
$collectionPath = "{$util->dataDir}/$collection";
|
||||
$fullFile = "$collectionPath/full/$fileName";
|
||||
$symbolicSrc = "../full/$fileName";
|
||||
|
||||
$image = Image::create($tmpName);
|
||||
Image::resizeSave($image, $fullFile, $info['maxHeight'], $info['maxWidth']);
|
||||
|
||||
foreach ($info['sizes'] as $size => $i) {
|
||||
$dstFile = "$schemaPath/$size/$fileName";
|
||||
$dstFile = "$collectionPath/$size/$fileName";
|
||||
Image::resizeSave($image, $dstFile, $i['height'], $i['width'], $i['crop'], $symbolicSrc);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue