Revision ecc4b0c2
Von Sven Schöling vor mehr als 3 Jahren hinzugefügt
SL/Controller/ImageUpload.pm | ||
---|---|---|
my ($self) = @_;
|
||
|
||
$::request->layout->add_javascripts('kivi.File.js');
|
||
$::request->layout->add_javascripts('kivi.FileDB.js');
|
||
$::request->layout->add_javascripts('kivi.ImageUpload.js');
|
||
|
||
$self->render('image_upload/form');
|
||
$self->render('image_upload/local_list');
|
||
}
|
||
|
||
################# internal ###############
|
js/kivi.FileDB.js | ||
---|---|---|
namespace("kivi.FileDB", function(ns) {
|
||
"use strict";
|
||
|
||
const database = 'kivi';
|
||
const store = 'files';
|
||
const db_version = 1;
|
||
|
||
// IndexedDB
|
||
const indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.OIndexedDB || window.msIndexedDB;
|
||
|
||
// Create/open database
|
||
let db;
|
||
let request = indexedDB.open(database, db_version);
|
||
request.onupgradeneeded = (event) => {
|
||
ns.create_image_store(event.target.result);
|
||
};
|
||
request.onerror = ns.onerror;
|
||
request.onsuccess = () => {
|
||
db = request.result;
|
||
|
||
db.onerror = (event) => {
|
||
console.error("Error creating/accessing IndexedDB database");
|
||
console.error(event);
|
||
};
|
||
|
||
// Interim solution for Google Chrome to create an objectStore. Will be deprecated
|
||
if (db.setVersion) {
|
||
if (db.version != db_version) {
|
||
let setVersion = db.setVersion(db_version);
|
||
setVersion.onsuccess = () => {
|
||
ns.create_image_store(db);
|
||
};
|
||
}
|
||
}
|
||
};
|
||
|
||
ns.create_image_store = function (db) {
|
||
db.createObjectStore(store, { autoIncrement : true });
|
||
};
|
||
|
||
ns.store_image = function (blob, filename, success) {
|
||
let put_request = ns.open_store("readwrite").add(blob, filename);
|
||
|
||
put_request.onsuccess = success;
|
||
put_request.on_error = ns.onerror;
|
||
};
|
||
|
||
ns.retrieve_image = function(key, success) {
|
||
let get_request = ns.open_store().objectStore(store).get(key);
|
||
|
||
get_request.onsuccess = success;
|
||
get_request.onerror = request.onerror;
|
||
};
|
||
|
||
ns.retrieve_all = function(success) {
|
||
let request = ns.open_store().getAll();
|
||
request.onsuccess = (event) => { success(event.target.result); };
|
||
request.onerror = ns.error;
|
||
};
|
||
|
||
ns.retrieve_all_keys = function(success) {
|
||
let request = ns.open_store().getAllKeys();
|
||
request.onsuccess = (event) => { success(event.target.result); };
|
||
request.onerror = ns.error;
|
||
};
|
||
|
||
ns.delete_all= function() {
|
||
ns.retrieve_all_keys((keys) => {
|
||
keys.forEach((key) => ns.delete_key(key));
|
||
});
|
||
};
|
||
|
||
ns.delete_key= function(key, success) {
|
||
let request = ns.open_store("readwrite").delete(key);
|
||
request.onsuccess = (event) => { if (success) success(event.target.result); };
|
||
request.onerror = ns.error;
|
||
};
|
||
|
||
ns.open_store = function(mode = "readonly") {
|
||
return db.transaction([store], mode).objectStore(store);
|
||
};
|
||
|
||
ns.onerror = (event) => {
|
||
console.error("Error creating/accessing IndexedDB database");
|
||
console.error(event.errorState);
|
||
};
|
||
});
|
js/kivi.ImageUpload.js | ||
---|---|---|
namespace("kivi.ImageUpload", function(ns) {
|
||
"use strict";
|
||
|
||
ns.add_files = function(target) {
|
||
let files = [];
|
||
for (var i = 0; i < target.files.length; i++) {
|
||
files.push(target.files.item(i));
|
||
}
|
||
|
||
kivi.FileDB.store_image(files[0], files[0].name, () => {
|
||
ns.reload_images();
|
||
target.value = null;
|
||
});
|
||
};
|
||
|
||
ns.reload_images = function() {
|
||
kivi.FileDB.retrieve_all((data) => {
|
||
$('#stored-images').empty();
|
||
data.forEach(ns.create_thumb_row);
|
||
});
|
||
};
|
||
|
||
ns.create_thumb_row = function(file) {
|
||
let URL = window.URL || window.webkitURL;
|
||
let file_url = URL.createObjectURL(file);
|
||
|
||
let $row = $("<div>").addClass("row image-upload-row");
|
||
let $button = $("<a>")
|
||
.addClass("btn-floating btn-large waves-effect waves-light red")
|
||
.click((event) => ns.remove_image(event, file.name))
|
||
.append($("<i>delete</i>").addClass("material-icons"));
|
||
$row.append($("<div>").addClass("col s3").append($button));
|
||
|
||
let $image = $('<img>').attr("src", file_url).addClass("materialboxed responsive-img");
|
||
$row.append($("<div>").addClass("col s9").append($image));
|
||
|
||
$("#stored-images").append($row);
|
||
};
|
||
|
||
ns.remove_image = function(event, key) {
|
||
let $row = $(event.target).closest(".image-upload-row");
|
||
kivi.FileDB.delete_key(key, () => {
|
||
$row.remove();
|
||
});
|
||
};
|
||
|
||
ns.upload_selected_files = function(id,type,filetype,maxsize) {
|
||
kivi.FileDB.retrieve_all((myfiles) => {
|
||
let filesize = 0;
|
||
myfiles.forEach(file => {
|
||
filesize += file.size;
|
||
if (filesize > maxsize) {
|
||
$("#upload_result").html(kivi.t8("filesize too big: ") + filesize+ kivi.t8(" bytes, max=") + maxsize );
|
||
return;
|
||
}
|
||
|
||
let data = new FormData();
|
||
data.append(file);
|
||
data.append("action", "File/ajax_files_uploaded");
|
||
data.append("json", "1");
|
||
data.append("object_type", type);
|
||
data.append("object_id", id);
|
||
data.append("file_type", filetype);
|
||
|
||
$("#upload_result").html(kivi.t8("start upload"));
|
||
|
||
$.ajax({
|
||
url: "controller.pl",
|
||
data: data,
|
||
success: ns.attSuccess,
|
||
progress: ns.attProgress,
|
||
error: ns.attFailes,
|
||
abort: ns.attCanceled
|
||
});
|
||
});
|
||
});
|
||
};
|
||
|
||
ns.attProgress = function(event) {
|
||
if (event.lengthComputable) {
|
||
var percentComplete = (event.loaded / event.total) * 100;
|
||
$("#upload_result").html(percentComplete+" % "+ kivi.t8("uploaded"));
|
||
}
|
||
};
|
||
|
||
ns.attFailed = function() {
|
||
$('#upload_modal').modal('close');
|
||
$("#upload_result").html(kivi.t8("An error occurred while transferring the file."));
|
||
};
|
||
|
||
ns.attCanceled = function() {
|
||
$('#upload_modal').modal('close');
|
||
$("#upload_result").html(kivi.t8("The transfer has been canceled by the user."));
|
||
};
|
||
|
||
ns.attSuccess = function() {
|
||
$('#upload_modal').modal('close');
|
||
$("#upload_result").html(kivi.t8("Files have been uploaded successfully."));
|
||
};
|
||
|
||
ns.init = function() {
|
||
ns.reload_images();
|
||
};
|
||
|
||
|
||
});
|
||
|
||
$(kivi.ImageUpload.init);
|
js/kivi.Materialize.js | ||
---|---|---|
|
||
ns.init = function() {
|
||
ns.reinit_widgets();
|
||
}
|
||
};
|
||
|
||
ns.build_i18n = function(locale) {
|
||
ns.build_i18n = function() {
|
||
return {
|
||
months: [
|
||
kivi.t8('January'),
|
||
... | ... | |
// Accessibility labels
|
||
labelMonthNext: kivi.t8('Next month'),
|
||
labelMonthPrev: kivi.t8('Previous month')
|
||
}
|
||
}
|
||
};
|
||
};
|
||
|
||
ns.reinit_widgets = function() {
|
||
$('.sidenav').sidenav();
|
||
... | ... | |
i18n: ns.build_i18n()
|
||
});
|
||
$('.modal').modal();
|
||
$('.materialboxed').materialbox();
|
||
M.updateTextFields();
|
||
}
|
||
};
|
||
|
||
// alternative for kivi.popup_dialog.
|
||
// opens materialize modal instead.
|
||
//
|
||
// differences: M.modal can not load external content, so it needs to be fetched manually and inserted into the DOM.
|
||
ns.popup_dialog = function(params) {
|
||
console.log(params);
|
||
params = params || { };
|
||
let id = params.id || 'jqueryui_popup_dialog';
|
||
let $div;
|
||
... | ... | |
// unlike classic layout, there is not fixed size, and M.modal is always... modal
|
||
onCloseStart: custom_close
|
||
},
|
||
// User supplied options:
|
||
// User supplied options:
|
||
params.dialog || { },
|
||
{ // Options that must not be changed:
|
||
// close options already work
|
||
... | ... | |
params.data = undefined;
|
||
ns.popup_dialog(params);
|
||
},
|
||
error: function(x, status, error) { console.log(error); },
|
||
error: function(x, status, error) { console.error(error); },
|
||
dataType: 'text',
|
||
});
|
||
return 1;
|
||
... | ... | |
|
||
if (params.html) {
|
||
$div = $('<div>');
|
||
$div.attr('id', id)
|
||
$div.attr('id', id);
|
||
$div.addClass("modal");
|
||
let $modal_content = $('<div>');
|
||
$modal_content.addClass('modal-content');
|
||
... | ... | |
$div.append($modal_content);
|
||
$('body').append($div);
|
||
kivi.reinit_widgets();
|
||
dialog_params.onCloseEnd = function() { $div.remove(); }
|
||
dialog_params.onCloseEnd = function() { $div.remove(); };
|
||
|
||
$div.modal(dialog_params);
|
||
|
||
} else if(params.id) {
|
||
$div = $('#' + params.id);
|
||
} else {
|
||
... | ... | |
$div.modal('open');
|
||
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* upload file to local storage for later sync
|
||
*
|
||
* should be used with P.M.file_upload(..., local=>1)
|
||
*/
|
||
ns.LocalFileUpload = function(options) {
|
||
this.storage_token = options.storage_token; // used in localstorage to retrieve the file
|
||
this.dom_selector = options.dom_selector; // file inputs to listen on
|
||
|
||
this.init();
|
||
};
|
||
|
||
ns.LocalFileUpload.prototype = {
|
||
init: function() {
|
||
$(this.dom_selector).change(this.handle_file_upload);
|
||
},
|
||
handle_file_upload: function() {
|
||
|
||
},
|
||
load_files: function() {
|
||
return JSON.parse(localStorage.getImte(this.storage_token));
|
||
},
|
||
save_files: function() {
|
||
return JSON.parse(localStorage.getImte(this.storage_token));
|
||
},
|
||
|
||
};
|
||
|
||
}
|
||
});
|
package.json | ||
---|---|---|
{
|
||
"name": "dev",
|
||
"version": "1.0.0",
|
||
"description": "",
|
||
"main": "index.js",
|
||
"directories": {
|
||
"doc": "doc"
|
||
},
|
||
"scripts": {
|
||
"test": "echo \"Error: no test specified\" && exit 1"
|
||
},
|
||
"repository": {
|
||
"type": "git",
|
||
"url": "git+https://github.com/kivitendo/kivitendo-erp.git"
|
||
},
|
||
"author": "",
|
||
"license": "ISC",
|
||
"bugs": {
|
||
"url": "https://github.com/kivitendo/kivitendo-erp/issues"
|
||
},
|
||
"homepage": "https://github.com/kivitendo/kivitendo-erp#readme"
|
||
}
|
templates/mobile_webpages/image_upload/local_list.html | ||
---|---|---|
[%- USE LxERP -%] [%- USE L %]
|
||
[%- USE HTML %]
|
||
[%- USE P %]
|
||
[%- USE T8 %]
|
||
|
||
<h4>[% source.title | html %]</h4>
|
||
|
||
<div id="updoad_result"></div>
|
||
|
||
<div id="stored-images" class="container">
|
||
</div>
|
||
|
||
|
||
<div class="container">
|
||
<div class="row">
|
||
|
||
<div class="file-field input-field col">
|
||
<div class="btn m3 s12">
|
||
<span>[% 'Upload Image' | $T8 %]</span>
|
||
<input
|
||
name="uploadfiles[]" type="file" [% IF multiple %]multiple[% END %]
|
||
id="upload_files" accept="[% SELF.accept_types %]" capture="camera"
|
||
onchange="kivi.ImageUpload.add_files(this)">
|
||
</div>
|
||
<div class="file-path-wrapper m9 s12">
|
||
<input class="file-path validate" type="hidden">
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div class="row">
|
||
[% P.M.input_tag("object_number", "", label=LxERP.t8("Number")) %]
|
||
[% P.M.button_tag("submit", LxERP.t8("Upload")) %]
|
||
</div>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div id="upload_modal" class="modal">
|
||
<div class="modal-content">
|
||
<h4>Uploading</h4>
|
||
|
||
<p>A bunch of text</p>
|
||
</div>
|
||
</div>
|
Auch abrufbar als: Unified diff
ImageUpload: local storage erste Version