Basic file uploader with AJAX flow
Button based, old style.
This commit is contained in:
59
4dev/database/function/edit_log_partition_insert.sql
Normal file
59
4dev/database/function/edit_log_partition_insert.sql
Normal file
@@ -0,0 +1,59 @@
|
||||
CREATE OR REPLACE FUNCTION edit_log_insert_trigger ()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
start_date DATE := '2010-01-01';
|
||||
end_date DATE;
|
||||
timeformat TEXT := 'YYYY';
|
||||
selector TEXT := 'year';
|
||||
_interval INTERVAL;
|
||||
table_name TEXT;
|
||||
BEGIN
|
||||
-- get year and month from edit_log date so we can build the target edit_log table
|
||||
|
||||
-- move interval
|
||||
_interval := '1 ' || selector;
|
||||
-- current table name
|
||||
table_name := 'edit_log_' || to_char(NEW.event_date, timeformat);
|
||||
|
||||
-- we are in valid start time area
|
||||
IF (NEW.event_date >= start_date) THEN
|
||||
BEGIN
|
||||
EXECUTE 'INSERT INTO ' || quote_ident(table_name) || ' SELECT ($1).*' USING NEW;
|
||||
-- if insert failed because of missing table, create new below
|
||||
EXCEPTION
|
||||
WHEN undefined_table THEN
|
||||
-- another block, so in case the creation fails here too
|
||||
BEGIN
|
||||
-- create new talbe here + all indexes
|
||||
start_date := date_trunc(selector, NEW.event_date);
|
||||
end_date := date_trunc(selector, NEW.event_date + _interval);
|
||||
-- creat table
|
||||
EXECUTE 'CREATE TABLE IF NOT EXISTS ' || quote_ident(table_name) || ' ( CHECK ( event_date >= ' || quote_literal(start_date) || ' AND event_date < ' || quote_literal(end_date) || ' ) ) INHERITS (edit_log)';
|
||||
-- create all indexes and triggers
|
||||
EXECUTE 'ALTER TABLE ' || quote_ident(table_name) || ' ADD PRIMARY KEY (edit_log_id)';
|
||||
-- FK constraints
|
||||
EXECUTE 'ALTER TABLE ' || quote_ident(table_name) || ' ADD CONSTRAINT fk_' || quote_ident(table_name) || '_euid_fkey FOREIGN KEY (euid) REFERENCES edit_user (edit_user_id) MATCH FULL ON UPDATE CASCADE ON DELETE CASCADE';
|
||||
-- generic trigger
|
||||
EXECUTE 'CREATE TRIGGER trg_' || quote_ident(table_name) || ' BEFORE INSERT OR UPDATE ON ' || quote_ident(table_name) || ' FOR EACH ROW EXECUTE PROCEDURE set_edit_generic()';
|
||||
|
||||
-- insert try again
|
||||
EXECUTE 'INSERT INTO ' || quote_ident(table_name) || ' SELECT ($1).*' USING NEW;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
-- if this faled, throw it into the overflow table (so we don't loose anything)
|
||||
INSERT INTO edit_log_overflow VALUES (NEW.*);
|
||||
END;
|
||||
-- other errors, insert into overlow
|
||||
WHEN OTHERS THEN
|
||||
-- if this faled, throw it into the overflow table (so we don't loose anything)
|
||||
INSERT INTO edit_log_overflow VALUES (NEW.*);
|
||||
END;
|
||||
ELSE
|
||||
-- if outside valid date, insert into overflow
|
||||
INSERT INTO edit_log_overflow VALUES (NEW.*);
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
END
|
||||
$$
|
||||
LANGUAGE 'plpgsql'
|
||||
@@ -2,3 +2,8 @@ DROP TRIGGER trg_edit_log ON edit_log;
|
||||
CREATE TRIGGER trg_edit_log
|
||||
BEFORE INSERT OR UPDATE ON edit_log
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();
|
||||
|
||||
DROP TRIGGER trg_edit_log_insert_partition ON edit_log;
|
||||
CREATE TRIGGER trg_edit_log_insert_partition
|
||||
BEFORE INSERT OR UPDATE ON edit_log
|
||||
FOR EACH ROW EXECUTE PROCEDURE edit_log_insert_trigger();
|
||||
|
||||
37
www/admin/qq_file_upload_ajax.php
Executable file
37
www/admin/qq_file_upload_ajax.php
Executable file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
$DEBUG_ALL = 1;
|
||||
$ECHO_ALL = 0;
|
||||
$PRINT_ALL = 1;
|
||||
|
||||
// load the Basic && qq file uploader here
|
||||
require 'config.inc';
|
||||
// class load
|
||||
$base = new CoreLibs\Basic();
|
||||
// set max upload size
|
||||
$MAX_UPLOAD_SIZE = $base->StringByteFormat(ini_get('upload_max_filesize'));
|
||||
|
||||
// test for qqFileUploader (AJAX side)
|
||||
$allowedExtensions = array ('csv', 'zip', 'jpg', 'pdf');
|
||||
$sizeLimit = $MAX_UPLOAD_SIZE; // as set in php ini
|
||||
$base->debug('AJAX UPLOAD', 'Size: '.$sizeLimit.', Memory Limit: '.ini_get('memory_limit'));
|
||||
$uploader = new CoreLibs\Upload\qqFileUploader($allowedExtensions, $sizeLimit);
|
||||
|
||||
$upload_path = ROOT.MEDIA.UPLOADS;
|
||||
$get_post['result'] = $uploader->handleUpload($upload_path, false);
|
||||
$base->debug('AJAX UPLOAD', 'Memory peak: '.$base->ByteStringFormat(memory_get_usage()).' | '.$base->ByteStringFormat(memory_get_peak_usage()));
|
||||
|
||||
// set file name
|
||||
$get_post['filename'] = $uploader->uploadFileName;
|
||||
$get_post['type'] = $uploader->uploadFileExt;
|
||||
$get_post['filesize'] = filesize($uploader->uploadFileName);
|
||||
$get_post['filesize_formated'] = $base->ByteStringFormat($get_post['filesize']);
|
||||
|
||||
// return data
|
||||
$output = htmlspecialchars(json_encode($get_post), ENT_NOQUOTES);
|
||||
$base->debug('AJAX USAGE', $output);
|
||||
print $output;
|
||||
|
||||
$base->printErrorMsg();
|
||||
|
||||
// __END__
|
||||
161
www/admin/qq_file_upload_front.php
Executable file
161
www/admin/qq_file_upload_front.php
Executable file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
$DEBUG_ALL = 1;
|
||||
$ECHO_ALL = 0;
|
||||
$PRINT_ALL = 1;
|
||||
|
||||
// test file for qqFileUploader (HTML side)
|
||||
// load the Basic class here
|
||||
require 'config.inc';
|
||||
$base = new CoreLibs\Basic();
|
||||
// set max upload size
|
||||
$MAX_UPLOAD_SIZE = $base->StringByteFormat(ini_get('upload_max_filesize'));
|
||||
$base->debug('UPLOADED FRONT', 'With max size: '.$MAX_UPLOAD_SIZE);
|
||||
|
||||
// very basic template output with super basic div for two file upload
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<title>File upload AJAX</title>
|
||||
<style type="text/css">
|
||||
.normal {
|
||||
width: 25%;
|
||||
}
|
||||
.flx-s {
|
||||
align-content: stretch;
|
||||
display: flex;
|
||||
flex: 1 100%;
|
||||
}
|
||||
.uploadError {
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.qq-file-upload-button {
|
||||
border: 1px solid #999999;
|
||||
border-radius: 2px 2px 2px 2px;
|
||||
box-shadow: 0 10px rgba(255, 255, 255, 0.3) inset, 0 10px rgba(255, 255, 255, 0.2) inset, 0 10px 2px rgba(255, 255, 255, 0.25) inset, 0 -1px 2px rgba(0, 0, 0, 0.3) inset;
|
||||
height: 17px;
|
||||
text-align: center;
|
||||
padding: 3px 5px 3px;
|
||||
background-color: #cacaca;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.qq-file-upload-button:hover {
|
||||
box-shadow: 0 10px 2px rgba(107, 107, 107, 0.2) inset, 0 12px rgba(107, 107, 107, 0.05) inset, 0 12px 2px rgba(107, 107, 107, 0.1) inset, 0 -1px 2px rgba(255, 255, 255, 0.3) inset;
|
||||
}
|
||||
|
||||
.qq-file-upload-button:active {
|
||||
border: 1px solid red;
|
||||
background-color: rgba(80, 80, 80, 0.5);
|
||||
}
|
||||
</style>
|
||||
<script src="layout/default/javascript/prototype.js" type="text/javascript"></script>
|
||||
<script src="layout/default/javascript/file-uploader/fileuploader.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
function formatBytes(bytes)
|
||||
{
|
||||
var i = -1;
|
||||
do {
|
||||
bytes = bytes / 1024;
|
||||
i++;
|
||||
} while (bytes > 99);
|
||||
|
||||
// return Math.max(bytes, 0.1).toFixed(1) + ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'][i];
|
||||
return parseFloat(Math.round(bytes * Math.pow(10, 2)) / Math.pow(10, 2)) + ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'][i];
|
||||
}
|
||||
var MAX_UPLOAD_SIZE = <?=$MAX_UPLOAD_SIZE;?>;
|
||||
// function to add an AJAX uploadeder to the set
|
||||
function createUploaderSin(divName, divNumber) {
|
||||
divID = divName + divNumber;
|
||||
console.log('Div: %s, Number: %s => ID: %s', divName, divNumber, divID);
|
||||
|
||||
var uploader = new qq.FileUploaderBasic({
|
||||
// element: document.getElementById(divID),
|
||||
element: $(divID),
|
||||
action: 'qq_file_upload_ajax.php',
|
||||
multiple: false,
|
||||
button: $(divID),
|
||||
allowedExtensions: ['csv', 'zip', 'jpg', 'pdf'],
|
||||
sizeLimit: MAX_UPLOAD_SIZE, // size set from php ini
|
||||
name: divID,
|
||||
params: {
|
||||
'file_pos': divNumber, // we need to add here ID or something
|
||||
'action': 'upload'
|
||||
},
|
||||
onSubmit: function(id, filename, target) {
|
||||
console.log('File upload: "%s", ID: "%s" => "%s"', filename, id, target);
|
||||
// remove any assigned error classes and flags
|
||||
if ($(target + 'Progress').hasClassName('uploadError'))
|
||||
{
|
||||
$(target + 'Progress').className = '';
|
||||
$(target + 'Error').value = 0;
|
||||
}
|
||||
$(target + 'Progress').innerHTML = 'Start uploading file: ' + filename;
|
||||
// disabled stuff here
|
||||
},
|
||||
onProgress: function(id, filename, loaded, total, target) {
|
||||
console.log('Progress for file: "%s", ID: "%s", loaded: "%s", total: "%s" => "%s"', id, filename, loaded, total, target);
|
||||
var percent = Math.round((loaded / total) * 100);
|
||||
$(target + 'Progress').innerHTML = 'Uploading: ' + filename + ', ' + percent + '%' + ' (' + formatBytes(loaded) + '/' + formatBytes(total) + ')';
|
||||
},
|
||||
onComplete: function(id, filename, responseJSON, target) {
|
||||
console.log('File upload for file "%s", id "%s" done with status "%s" => "%s", And success: %s', filename, id, responseJSON, target, responseJSON.result.success);
|
||||
if (responseJSON.result.success)
|
||||
{
|
||||
$(target + 'Progress').innerHTML = 'Uploaded: ' + filename + ' (' + responseJSON.filesize_formated + ')';
|
||||
// also write hidden vars for this (file name, etc)
|
||||
// for that we replace the divName part from the target and get just the pos number ?
|
||||
// $(target + 'Name').value = filename;
|
||||
// $(target + 'NameUpload').value = responseJSON.filename;
|
||||
// $(target + 'Type').value = responseJSON.type;
|
||||
// $(target + 'Size').value = responseJSON.filesize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set the error class
|
||||
$(target + 'Progress').className = 'uploadError';
|
||||
// flag error
|
||||
$(target + 'Error').value = 1;
|
||||
// and write the error
|
||||
$(target + 'Progress').innerHTML = 'UPLOAD FAILED FOR FILE: ' + filename;
|
||||
}
|
||||
// renable stuff here
|
||||
},
|
||||
/*showMessage: function(message) {
|
||||
console.log('MESSAGE: %s', message);
|
||||
}, */
|
||||
debug: true
|
||||
});
|
||||
// console.log('INIT Nr %s => cnt: %s', divNumber, uploader);
|
||||
return uploader;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="masterGroup">
|
||||
<div>File upload via AJAX</div>
|
||||
<div class="flx-s">
|
||||
<div id="Uploader1" class="normal qq-file-upload-button">Upload File</div>
|
||||
<div id="Uploader1Progress"></div>
|
||||
<input type="hidden" name="Uploader1Error" id="Uploader1Error" value="">
|
||||
</div>
|
||||
<div class="flx-s">
|
||||
<div id="Uploader2" class="normal qq-file-upload-button">Upload File</div>
|
||||
<div id="Uploader2Progress"></div>
|
||||
<input type="hidden" name="Uploader2Error" id="Uploader2Error" value="">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<script type="text/javascript">
|
||||
// attach uploader to div areas
|
||||
createUploaderSin('Uploader', '1');
|
||||
createUploaderSin('Uploader', '2');
|
||||
</script>
|
||||
<?php
|
||||
$base->printErrorMsg();
|
||||
|
||||
// __END__
|
||||
88
www/layout/admin/default/css/file-uploader/fileuploader.css
Normal file
88
www/layout/admin/default/css/file-uploader/fileuploader.css
Normal file
@@ -0,0 +1,88 @@
|
||||
.qq-uploader {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.qq-upload-button {
|
||||
display: block; /* or inline-block */
|
||||
width: 105px;
|
||||
padding: 7px 0;
|
||||
text-align: center;
|
||||
background: #880000;
|
||||
border-bottom: 1px solid #ddd;
|
||||
color: #fff;
|
||||
}
|
||||
.qq-upload-button-hover {
|
||||
background: #cc0000;
|
||||
}
|
||||
.qq-upload-button-focus {
|
||||
outline: 1px dotted black;
|
||||
}
|
||||
|
||||
.qq-upload-drop-area {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 70px;
|
||||
z-index: 2;
|
||||
background: #FF9797;
|
||||
text-align: center;
|
||||
}
|
||||
.qq-upload-drop-area span {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 100%;
|
||||
margin-top: -8px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.qq-upload-drop-area-active {
|
||||
background:
|
||||
#FF7171;
|
||||
}
|
||||
|
||||
.qq-upload-list {
|
||||
margin:
|
||||
15px 35px;
|
||||
padding: 0;
|
||||
list-style: disc;
|
||||
}
|
||||
.qq-upload-list li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 15px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.qq-upload-file, .qq-upload-spinner, .qq-upload-size, .qq-upload-cancel, .qq-upload-failed-text {
|
||||
margin-right: 7px;
|
||||
}
|
||||
|
||||
.qq-upload-file {
|
||||
}
|
||||
.qq-upload-spinner {
|
||||
display: inline-block;
|
||||
/*background: url("loading.gif");*/
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
vertical-align: text-bottom;
|
||||
/* non gif css rotate */
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border: 2px solid rgba(255, 255, 255, 0.25);
|
||||
border-left-color: rgba(102, 102, 102 ,1);
|
||||
border-right-color: rgba(102, 102, 102 ,1);
|
||||
border-radius: 50%;
|
||||
animation: rotate 600ms infinite linear;
|
||||
}
|
||||
|
||||
.qq-upload-size, .qq-upload-cancel {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.qq-upload-failed-text {
|
||||
display: none;
|
||||
}
|
||||
.qq-upload-fail .qq-upload-failed-text {
|
||||
display: inline;
|
||||
}
|
||||
1282
www/layout/admin/default/javascript/file-uploader/fileuploader.js
Normal file
1282
www/layout/admin/default/javascript/file-uploader/fileuploader.js
Normal file
File diff suppressed because it is too large
Load Diff
2
www/media/uploads/.gitignore
vendored
Normal file
2
www/media/uploads/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
Reference in New Issue
Block a user