Compare commits
No commits in common. "master" and "copy_img_tag" have entirely different histories.
master
...
copy_img_t
|
@ -1,11 +1,4 @@
|
|||
{
|
||||
db_file => 'sql/fotostore.db',
|
||||
invite_code => 'very_secure_invite_code',
|
||||
thumbnails_size => 200,
|
||||
image_scales => {
|
||||
640 => 1,
|
||||
800 => 1,
|
||||
1024 => 1,
|
||||
2048 => 1,
|
||||
},
|
||||
}
|
2
cpanfile
|
@ -1,4 +1,4 @@
|
|||
requires 'Mojolicious', '>= 7.88';
|
||||
requires 'Mojolicious';
|
||||
requires 'Mojolicious::Plugin::Authentication';
|
||||
requires 'Imager';
|
||||
requires 'File::Basename';
|
||||
|
|
260
fotostore.pl
|
@ -4,14 +4,11 @@ use warnings;
|
|||
|
||||
use lib 'lib';
|
||||
use Mojolicious::Lite; # app, get, post is exported.
|
||||
use Mojo::Promise;
|
||||
use Mojo::IOLoop;
|
||||
|
||||
use File::Basename qw/basename fileparse/;
|
||||
use File::Basename 'basename';
|
||||
use File::Path 'mkpath';
|
||||
use File::Spec 'catfile';
|
||||
use Cwd;
|
||||
use POSIX;
|
||||
|
||||
use Imager;
|
||||
use DBI;
|
||||
|
@ -20,7 +17,7 @@ use Digest::SHA;
|
|||
use FotoStore::DB;
|
||||
|
||||
use Data::Dumper;
|
||||
$Data::Dumper::Maxdepth = 2;
|
||||
$Data::Dumper::Maxdepth = 3;
|
||||
|
||||
my $config = plugin 'Config' => { file => 'application.conf' };
|
||||
|
||||
|
@ -30,24 +27,16 @@ my $db = FotoStore::DB->new( $config->{'db_file'} );
|
|||
my $IMAGE_BASE = 'images';
|
||||
my $ORIG_DIR = 'orig';
|
||||
|
||||
# set allowed thumbnails scale and image scales
|
||||
my $thumbs_size = $config->{'thumbnails_size'};
|
||||
my $thumbs_size = 200;
|
||||
|
||||
my $scales_map = $config->{'image_scales'};
|
||||
$scales_map->{$thumbs_size} = 1;
|
||||
|
||||
#Sort and filter values for array of available scales
|
||||
my @scale_width =
|
||||
map { $scales_map->{$_} == 1 ? $_ : undef }
|
||||
sort { $a <=> $b } keys(%$scales_map);
|
||||
my @scale_width = ( $thumbs_size, 640, 800, 1024 );
|
||||
|
||||
my $sha = Digest::SHA->new('sha256');
|
||||
|
||||
# Directory to save image files
|
||||
# (app is Mojolicious object. static is MojoX::Dispatcher::Static object)
|
||||
my $IMAGE_DIR = File::Spec->catfile( getcwd(), 'public', $IMAGE_BASE );
|
||||
|
||||
my $log = Mojo::Log->new();
|
||||
|
||||
plugin 'authentication', {
|
||||
autoload_user => 1,
|
||||
load_user => sub {
|
||||
|
@ -65,6 +54,7 @@ plugin 'authentication', {
|
|||
my $digest = $sha->add($password);
|
||||
|
||||
my $user_id = $db->check_user( $username, $digest->hexdigest() );
|
||||
# $self->app->log->debug("user id: [$user_id]");
|
||||
|
||||
return $user_id;
|
||||
},
|
||||
|
@ -96,44 +86,39 @@ get '/register' => ( authenticated => 0 ) => sub {
|
|||
};
|
||||
|
||||
post '/register' => ( authenticated => 0 ) => sub {
|
||||
my $self = shift;
|
||||
my $username = $self->req->param('username') || "";
|
||||
my $password = $self->req->param('password') || "";
|
||||
my $fullname = $self->req->param('fullname') || "";
|
||||
my $invite = $self->req->param('invite') || "";
|
||||
|
||||
if ( $invite eq $config->{'invite_code'} ) {
|
||||
my $self = shift;
|
||||
my $username = $self->req->param('username');
|
||||
my $password = $self->req->param('password');
|
||||
my $fullname = $self->req->param('fullname');
|
||||
my $invite = $self->req->param('invite');
|
||||
|
||||
if ($invite eq $config->{'invite_code'}) {
|
||||
#chek that username is not taken
|
||||
my $user = $db->get_user($username);
|
||||
if ( $user->{'user_id'} > 0 ) {
|
||||
$self->render(
|
||||
template => 'error',
|
||||
message => 'Username already taken!'
|
||||
);
|
||||
return 0;
|
||||
if ($user->{'user_id'} > 0) {
|
||||
$self->render(template => 'error', message => 'Username already taken!');
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( $fullname eq '' ) {
|
||||
if ($fullname eq '') {
|
||||
$fullname = $username;
|
||||
}
|
||||
|
||||
my $digest = $sha->add($password);
|
||||
$db->add_user( $username, $digest->hexdigest(), $fullname );
|
||||
$db->add_user($username, $digest->hexdigest(), $fullname);
|
||||
|
||||
#Authenticate user after add
|
||||
if ( $self->authenticate( $username, $password ) ) {
|
||||
$self->redirect_to('/');
|
||||
}
|
||||
else {
|
||||
$self->render( template => 'error', message => 'Login failed :(' );
|
||||
$self->render( text => 'Login failed :(' );
|
||||
}
|
||||
|
||||
} else {
|
||||
$self->render(template => 'error', message => 'invalid invite code');
|
||||
}
|
||||
else {
|
||||
$self->render( template => 'error', message => 'invalid invite code' );
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
# Display top page
|
||||
get '/' => sub {
|
||||
|
@ -146,70 +131,35 @@ get '/' => sub {
|
|||
get '/get_images' => ( authenticated => 1 ) => sub {
|
||||
my $self = shift;
|
||||
|
||||
#Getting current user
|
||||
my $current_user = $self->current_user;
|
||||
my $user_id = $current_user->{'user_id'};
|
||||
|
||||
#Getting images list with paging
|
||||
my $page = $self->param('page') || 1;
|
||||
my $items = $self->param('per-page') || 20;
|
||||
|
||||
if (($page !~ /^\d+$/) || ($page <= 1)) { $page = 1}
|
||||
if (($items !~ /^\d+$/) || ($items <= 0)) { $items = 20}
|
||||
my $files_list = $db->get_files($current_user->{'user_id'}, 20);
|
||||
|
||||
my $thumbs_dir = File::Spec->catfile( $IMAGE_DIR, $current_user->{'user_id'}, $thumbs_size );
|
||||
|
||||
# process images list
|
||||
my $req_result = $db->get_files( $current_user->{'user_id'}, $items , $page);
|
||||
my $files_list = $req_result->{'images_list'};
|
||||
my $pages_count = ceil($req_result->{'total_rows'}/$items);
|
||||
|
||||
my $thumbs_dir =
|
||||
File::Spec->catfile( $IMAGE_DIR, $current_user->{'user_id'},
|
||||
$thumbs_size );
|
||||
|
||||
my @images = map { $_->{'file_name'} } @$files_list;
|
||||
|
||||
my $images = [];
|
||||
|
||||
for my $img_item (@$files_list) {
|
||||
my $file = $img_item->{'file_name'};
|
||||
my $file = $img_item->{'file_name'};
|
||||
my $img_hash = {};
|
||||
$img_hash->{'id'} = $img_item->{'file_id'};
|
||||
$img_hash->{'filename'} = $img_item->{'original_filename'};
|
||||
$img_hash->{'original_url'} =
|
||||
File::Spec->catfile( '/', $IMAGE_BASE, $current_user->{'user_id'},
|
||||
$ORIG_DIR, $file );
|
||||
$img_hash->{'thumbnail_url'} =
|
||||
File::Spec->catfile( '/', $IMAGE_BASE, $current_user->{'user_id'},
|
||||
$thumbs_size, $file );
|
||||
$img_hash->{'original_url'} = File::Spec->catfile( '/', $IMAGE_BASE, $current_user->{'user_id'}, $ORIG_DIR, $file );
|
||||
$img_hash->{'thumbnail_url'} = File::Spec->catfile( '/', $IMAGE_BASE, $current_user->{'user_id'}, $thumbs_size, $file );
|
||||
|
||||
my @scaled = ();
|
||||
for my $scale (@scale_width) {
|
||||
if ( -r File::Spec->catfile( get_path( $user_id, $scale ), $file ) )
|
||||
{
|
||||
push(
|
||||
@scaled,
|
||||
{
|
||||
'size' => $scale,
|
||||
'url' => File::Spec->catfile(
|
||||
'/', $IMAGE_BASE, $user_id, $scale, $file
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
push(@scaled, {'size' => $scale, 'url' => File::Spec->catfile( '/', $IMAGE_BASE, $current_user->{'user_id'}, $scale, $file )}) ;
|
||||
}
|
||||
|
||||
$img_hash->{'scales'} = \@scaled;
|
||||
|
||||
push( @$images, $img_hash );
|
||||
push(@$images, $img_hash);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
my $reply_data = { current_page => $page, items_per_page => $items, pages_count => $pages_count, images_list => $images };
|
||||
|
||||
# Render
|
||||
return $self->render( json => $reply_data );
|
||||
return $self->render( json => $images );
|
||||
};
|
||||
|
||||
# Upload image file
|
||||
|
@ -220,8 +170,9 @@ post '/upload' => ( authenticated => 1 ) => sub {
|
|||
# Uploaded image(Mojo::Upload object)
|
||||
my $image = $self->req->upload('image');
|
||||
|
||||
my $user = $self->current_user();
|
||||
my $user = $self->current_user();
|
||||
my $user_id = $user->{'user_id'};
|
||||
$self->app->log->debug( "user:" . Dumper($user) );
|
||||
|
||||
# Not upload
|
||||
unless ($image) {
|
||||
|
@ -233,11 +184,7 @@ post '/upload' => ( authenticated => 1 ) => sub {
|
|||
|
||||
# Check file type
|
||||
my $image_type = $image->headers->content_type;
|
||||
my %valid_types = (
|
||||
'image/gif' => 'gif',
|
||||
'image/jpeg' => 'jpg',
|
||||
'image/png' => 'png'
|
||||
);
|
||||
my %valid_types = map { $_ => 1 } qw(image/gif image/jpeg image/png);
|
||||
|
||||
# Content type is wrong
|
||||
unless ( $valid_types{$image_type} ) {
|
||||
|
@ -247,34 +194,65 @@ post '/upload' => ( authenticated => 1 ) => sub {
|
|||
);
|
||||
}
|
||||
|
||||
my $ext = $valid_types{$image_type};
|
||||
# Extention
|
||||
my $exts = {
|
||||
'image/gif' => 'gif',
|
||||
'image/jpeg' => 'jpg',
|
||||
'image/png' => 'png'
|
||||
};
|
||||
my $ext = $exts->{$image_type};
|
||||
|
||||
# Image file
|
||||
my $filename = sprintf( '%s.%s', create_hash( $image->slurp() ), $ext );
|
||||
my $image_file =
|
||||
File::Spec->catfile( get_path( $user_id, $ORIG_DIR ), $filename );
|
||||
my $image_file = File::Spec->catfile( get_path($user_id, $ORIG_DIR), $filename );
|
||||
|
||||
# Save to file
|
||||
$image->move_to($image_file);
|
||||
|
||||
|
||||
my $promise = store_image($image_file, $image->filename, $user_id);
|
||||
|
||||
#TODO: add errors handling
|
||||
Mojo::Promise->all($promise)->then(sub {
|
||||
$self->render(
|
||||
json => {
|
||||
files => [
|
||||
{
|
||||
name => $image->filename,
|
||||
size => $image->size,
|
||||
url => sprintf( '/images/orig/%s', $filename ),
|
||||
thumbnailUrl => sprintf( '/images/200/%s', $filename ),
|
||||
}
|
||||
]
|
||||
my $imager = Imager->new();
|
||||
$imager->read( file => $image_file ) or die $imager->errstr;
|
||||
|
||||
#http://sylvana.net/jpegcrop/exif_orientation.html
|
||||
#http://myjaphoo.de/docs/exifidentifiers.html
|
||||
my $rotation_angle = $imager->tags( name => "exif_orientation" ) || 1;
|
||||
$self->app->log->info(
|
||||
"Rotation angle [" . $rotation_angle . "] [" . $image->filename . "]" );
|
||||
|
||||
if ( $rotation_angle == 3 ) {
|
||||
$imager = $imager->rotate( degrees => 180 );
|
||||
}
|
||||
elsif ( $rotation_angle == 6 ) {
|
||||
$imager = $imager->rotate( degrees => 90 );
|
||||
}
|
||||
|
||||
for my $scale (@scale_width) {
|
||||
my $scaled = $imager->scale( xpixels => $scale );
|
||||
|
||||
$scaled->write(
|
||||
file => File::Spec->catfile( get_path($user_id, $scale), $filename ) )
|
||||
or die $scaled->errstr;
|
||||
}
|
||||
|
||||
if ( !$db->add_file( $user->{'user_id'}, $filename ) ) {
|
||||
|
||||
#TODO: Send error msg
|
||||
}
|
||||
|
||||
$self->render(
|
||||
json => {
|
||||
files => [
|
||||
{
|
||||
name => $image->filename,
|
||||
size => $image->size,
|
||||
url => sprintf( '/images/orig/%s', $filename ),
|
||||
thumbnailUrl => sprintf( '/images/200/%s', $filename ),
|
||||
}
|
||||
);
|
||||
})->wait;
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
# Redirect to top page
|
||||
# $self->redirect_to('index');
|
||||
|
||||
} => 'upload';
|
||||
|
||||
|
@ -286,76 +264,12 @@ sub create_hash {
|
|||
}
|
||||
|
||||
sub get_path {
|
||||
my ( $user_id, $size ) = @_;
|
||||
my ($user_id, $size) = @_;
|
||||
my $path = File::Spec->catfile( $IMAGE_DIR, $user_id, $size );
|
||||
unless ( -d $path ) {
|
||||
unless (-d $path) {
|
||||
mkpath $path or die "Cannot create directory: $path";
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
sub store_image {
|
||||
my $image_file = shift;
|
||||
my $original_filename = shift;
|
||||
my $user_id = shift;
|
||||
|
||||
my $promise = Mojo::Promise->new;
|
||||
# Process and store uploaded file in a separate process
|
||||
Mojo::IOLoop->subprocess(
|
||||
sub {
|
||||
my $subprocess = shift;
|
||||
|
||||
my $filename = fileparse($image_file);
|
||||
my $imager = Imager->new();
|
||||
$imager->read( file => $image_file ) or die $imager->errstr;
|
||||
|
||||
#http://sylvana.net/jpegcrop/exif_orientation.html
|
||||
#http://myjaphoo.de/docs/exifidentifiers.html
|
||||
my $rotation_angle = $imager->tags( name => "exif_orientation" ) || 1;
|
||||
$log->debug(
|
||||
"Rotation angle [" . $rotation_angle . "]" );
|
||||
|
||||
if ( $rotation_angle == 3 ) {
|
||||
$imager = $imager->rotate( degrees => 180 );
|
||||
}
|
||||
elsif ( $rotation_angle == 6 ) {
|
||||
$imager = $imager->rotate( degrees => 90 );
|
||||
}
|
||||
|
||||
my $original_width = $imager->getwidth();
|
||||
|
||||
for my $scale (@scale_width) {
|
||||
|
||||
#Skip sizes which more than original image
|
||||
if ( $scale >= $original_width ) {
|
||||
next;
|
||||
}
|
||||
|
||||
my $scaled = $imager->scale( xpixels => $scale );
|
||||
|
||||
$scaled->write( file =>
|
||||
File::Spec->catfile( get_path( $user_id, $scale ), $filename ) )
|
||||
or die $scaled->errstr;
|
||||
}
|
||||
|
||||
if ( !$db->add_file( $user_id, $filename, $original_filename ) ) {
|
||||
|
||||
$log->error(sprintf('Can\'t save file %s', $filename));
|
||||
die sprintf('Can\'t save file %s', $filename);
|
||||
}
|
||||
|
||||
return $filename;
|
||||
},
|
||||
sub {
|
||||
my ($subprocess, $err, @results) = @_;
|
||||
$log->error("Subprocess error: $err") and return if $err;
|
||||
$promise->reject("Subprocess error: $err @results") if $err;
|
||||
$promise->resolve(1, @results);
|
||||
}
|
||||
);
|
||||
|
||||
return $promise;
|
||||
}
|
||||
|
||||
Mojo::IOLoop->start;
|
||||
app->start;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package FotoStore::DB;
|
||||
|
||||
use v5.20;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
|
@ -52,25 +51,16 @@ sub add_user($self, $username, $password, $fullname) {
|
|||
}
|
||||
|
||||
|
||||
sub add_file($self, $user_id, $filename, $original_filename) {
|
||||
my $rows = $self->{'dbh'}->do(q~insert into images (owner_id, file_name, original_filename) values (?, ?, ?)~, undef, ($user_id, $filename, $original_filename));
|
||||
sub add_file($self, $user_id, $filename) {
|
||||
my $rows = $self->{'dbh'}->do(q~insert into images (owner_id, file_name) values (?, ?)~, undef, ($user_id, $filename));
|
||||
if ($self->{'dbh'}->errstr) {
|
||||
die $self->{'dbh'}->errstr;
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
sub get_files($self, $user_id, $items_count=20, $page=1) {
|
||||
|
||||
# Calculate offset
|
||||
# Pages in UI starts from 1, but here we need it to start from 0
|
||||
$page = 1 if ($page < 1);
|
||||
my $start_at = --$page * $items_count;
|
||||
|
||||
my ($rows_count) = $self->{'dbh'}->selectrow_array(q~select count(*) from images where owner_id=? ~, undef , $user_id);
|
||||
my $images_list = $self->{'dbh'}->selectall_arrayref(q~select * from images where owner_id=? order by created_time desc LIMIT ? OFFSET ? ~, { Slice => {} }, $user_id, $items_count, $start_at );
|
||||
|
||||
return { total_rows => $rows_count, images_list => $images_list };
|
||||
sub get_files($self, $user_id, $count=20, $start_at=0) {
|
||||
return $self->{'dbh'}->selectall_arrayref(q~select * from images where owner_id=? order by created_time desc~, { Slice => {} }, $user_id );
|
||||
}
|
||||
|
||||
1;
|
|
@ -1,63 +1,15 @@
|
|||
.progress-bar {
|
||||
height: 18px;
|
||||
background: green;
|
||||
}
|
||||
|
||||
.foto-block {
|
||||
/* border: 1px solid black; */
|
||||
}
|
||||
|
||||
.foto-block .image {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.foto-block .foto-notes {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.copy-img:before {
|
||||
content: url(/img/copy_icon.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.copy-img {
|
||||
content: url(/img/copy_icon.png);
|
||||
content:url(/img/copy_icon.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.copy-bb-more:before {
|
||||
content: url(/img/more_icon.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.copy-bb-more {
|
||||
content: url(/img/more_icon.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.image-scale {
|
||||
float: left;
|
||||
padding-right: 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.upload-form {
|
||||
height: 100px;
|
||||
padding: 10px;
|
||||
}
|
3
public/file_uploader/.gitignore
vendored
Executable file
|
@ -0,0 +1,3 @@
|
|||
.DS_Store
|
||||
*.pyc
|
||||
node_modules
|
81
public/file_uploader/.jshintrc
Executable file
|
@ -0,0 +1,81 @@
|
|||
{
|
||||
"bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
|
||||
"camelcase" : true, // true: Identifiers must be in camelCase
|
||||
"curly" : true, // true: Require {} for every new block or scope
|
||||
"eqeqeq" : true, // true: Require triple equals (===) for comparison
|
||||
"forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
|
||||
"immed" : true, // true: Require immediate invocations to be wrapped in parens
|
||||
// e.g. `(function () { } ());`
|
||||
"indent" : 4, // {int} Number of spaces to use for indentation
|
||||
"latedef" : true, // true: Require variables/functions to be defined before being used
|
||||
"newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()`
|
||||
"noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
|
||||
"noempty" : true, // true: Prohibit use of empty blocks
|
||||
"nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment)
|
||||
"plusplus" : false, // true: Prohibit use of `++` & `--`
|
||||
"quotmark" : "single", // Quotation mark consistency:
|
||||
// false : do nothing (default)
|
||||
// true : ensure whatever is used is consistent
|
||||
// "single" : require single quotes
|
||||
// "double" : require double quotes
|
||||
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
|
||||
"unused" : true, // true: Require all defined variables be used
|
||||
"strict" : true, // true: Requires all functions run in ES5 Strict Mode
|
||||
"trailing" : true, // true: Prohibit trailing whitespaces
|
||||
"maxparams" : false, // {int} Max number of formal params allowed per function
|
||||
"maxdepth" : false, // {int} Max depth of nested blocks (within functions)
|
||||
"maxstatements" : false, // {int} Max number statements per function
|
||||
"maxcomplexity" : false, // {int} Max cyclomatic complexity per function
|
||||
"maxlen" : false, // {int} Max number of characters per line
|
||||
|
||||
// Relaxing
|
||||
"asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
|
||||
"boss" : false, // true: Tolerate assignments where comparisons would be expected
|
||||
"debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
|
||||
"eqnull" : false, // true: Tolerate use of `== null`
|
||||
"es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
|
||||
"esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
|
||||
"moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
|
||||
// (ex: `for each`, multiple try/catch, function expression…)
|
||||
"evil" : false, // true: Tolerate use of `eval` and `new Function()`
|
||||
"expr" : false, // true: Tolerate `ExpressionStatement` as Programs
|
||||
"funcscope" : false, // true: Tolerate defining variables inside control statements"
|
||||
"globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
|
||||
"iterator" : false, // true: Tolerate using the `__iterator__` property
|
||||
"lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
|
||||
"laxbreak" : false, // true: Tolerate possibly unsafe line breakings
|
||||
"laxcomma" : false, // true: Tolerate comma-first style coding
|
||||
"loopfunc" : false, // true: Tolerate functions being defined in loops
|
||||
"multistr" : false, // true: Tolerate multi-line strings
|
||||
"proto" : false, // true: Tolerate using the `__proto__` property
|
||||
"scripturl" : false, // true: Tolerate script-targeted URLs
|
||||
"smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment
|
||||
"shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
|
||||
"sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
|
||||
"supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
|
||||
"validthis" : false, // true: Tolerate using this in a non-constructor function
|
||||
|
||||
// Environments
|
||||
"browser" : false, // Web Browser (window, document, etc)
|
||||
"couch" : false, // CouchDB
|
||||
"devel" : false, // Development/debugging (alert, confirm, etc)
|
||||
"dojo" : false, // Dojo Toolkit
|
||||
"jquery" : false, // jQuery
|
||||
"mootools" : false, // MooTools
|
||||
"node" : false, // Node.js
|
||||
"nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
|
||||
"prototypejs" : false, // Prototype and Scriptaculous
|
||||
"rhino" : false, // Rhino
|
||||
"worker" : false, // Web Workers
|
||||
"wsh" : false, // Windows Scripting Host
|
||||
"yui" : false, // Yahoo User Interface
|
||||
|
||||
// Legacy
|
||||
"nomen" : true, // true: Prohibit dangling `_` in variables
|
||||
"onevar" : true, // true: Allow only one `var` statement per function
|
||||
"passfail" : false, // true: Stop on first error
|
||||
"white" : true, // true: Check against strict whitespace and indentation rules
|
||||
|
||||
// Custom Globals
|
||||
"globals" : {} // additional predefined global variables
|
||||
}
|
20
public/file_uploader/.npmignore
Executable file
|
@ -0,0 +1,20 @@
|
|||
*
|
||||
!css/jquery.fileupload-noscript.css
|
||||
!css/jquery.fileupload-ui-noscript.css
|
||||
!css/jquery.fileupload-ui.css
|
||||
!css/jquery.fileupload.css
|
||||
!img/loading.gif
|
||||
!img/progressbar.gif
|
||||
!js/cors/jquery.postmessage-transport.js
|
||||
!js/cors/jquery.xdr-transport.js
|
||||
!js/vendor/jquery.ui.widget.js
|
||||
!js/jquery.fileupload-angular.js
|
||||
!js/jquery.fileupload-audio.js
|
||||
!js/jquery.fileupload-image.js
|
||||
!js/jquery.fileupload-jquery-ui.js
|
||||
!js/jquery.fileupload-process.js
|
||||
!js/jquery.fileupload-ui.js
|
||||
!js/jquery.fileupload-validate.js
|
||||
!js/jquery.fileupload-video.js
|
||||
!js/jquery.fileupload.js
|
||||
!js/jquery.iframe-transport.js
|
15
public/file_uploader/CONTRIBUTING.md
Executable file
|
@ -0,0 +1,15 @@
|
|||
Please follow these pull request guidelines:
|
||||
|
||||
1. Update your fork to the latest upstream version.
|
||||
|
||||
2. Follow the coding conventions of the original source files (indentation, spaces, brackets layout).
|
||||
|
||||
3. Code changes must pass JSHint validation with the `.jshintrc` settings of this project.
|
||||
|
||||
4. Code changes must pass the QUnit tests defined in the `test` folder.
|
||||
|
||||
5. New features should be covered by accompanying QUnit tests.
|
||||
|
||||
6. Keep your commits as atomic as possible, i.e. create a new commit for every single bug fix or feature added.
|
||||
|
||||
7. Always add meaningful commit messages.
|
20
public/file_uploader/LICENSE
Executable file
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 jQuery-File-Upload Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
107
public/file_uploader/README.md
Executable file
|
@ -0,0 +1,107 @@
|
|||
# jQuery File Upload Plugin
|
||||
|
||||
## Demo
|
||||
[Demo File Upload](https://blueimp.github.io/jQuery-File-Upload/)
|
||||
|
||||
## Description
|
||||
File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for jQuery.
|
||||
Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.
|
||||
|
||||
## Setup
|
||||
* [How to setup the plugin on your website](https://github.com/blueimp/jQuery-File-Upload/wiki/Setup)
|
||||
* [How to use only the basic plugin (minimal setup guide).](https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin)
|
||||
|
||||
## Features
|
||||
* **Multiple file upload:**
|
||||
Allows to select multiple files at once and upload them simultaneously.
|
||||
* **Drag & Drop support:**
|
||||
Allows to upload files by dragging them from your desktop or filemanager and dropping them on your browser window.
|
||||
* **Upload progress bar:**
|
||||
Shows a progress bar indicating the upload progress for individual files and for all uploads combined.
|
||||
* **Cancelable uploads:**
|
||||
Individual file uploads can be canceled to stop the upload progress.
|
||||
* **Resumable uploads:**
|
||||
Aborted uploads can be resumed with browsers supporting the Blob API.
|
||||
* **Chunked uploads:**
|
||||
Large files can be uploaded in smaller chunks with browsers supporting the Blob API.
|
||||
* **Client-side image resizing:**
|
||||
Images can be automatically resized on client-side with browsers supporting the required JS APIs.
|
||||
* **Preview images, audio and video:**
|
||||
A preview of image, audio and video files can be displayed before uploading with browsers supporting the required APIs.
|
||||
* **No browser plugins (e.g. Adobe Flash) required:**
|
||||
The implementation is based on open standards like HTML5 and JavaScript and requires no additional browser plugins.
|
||||
* **Graceful fallback for legacy browsers:**
|
||||
Uploads files via XMLHttpRequests if supported and uses iframes as fallback for legacy browsers.
|
||||
* **HTML file upload form fallback:**
|
||||
Allows progressive enhancement by using a standard HTML file upload form as widget element.
|
||||
* **Cross-site file uploads:**
|
||||
Supports uploading files to a different domain with cross-site XMLHttpRequests or iframe redirects.
|
||||
* **Multiple plugin instances:**
|
||||
Allows to use multiple plugin instances on the same webpage.
|
||||
* **Customizable and extensible:**
|
||||
Provides an API to set individual options and define callBack methods for various upload events.
|
||||
* **Multipart and file contents stream uploads:**
|
||||
Files can be uploaded as standard "multipart/form-data" or file contents stream (HTTP PUT file upload).
|
||||
* **Compatible with any server-side application platform:**
|
||||
Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Mandatory requirements
|
||||
* [jQuery](https://jquery.com/) v. 1.6+
|
||||
* [jQuery UI widget factory](https://api.jqueryui.com/jQuery.widget/) v. 1.9+ (included): Required for the basic File Upload plugin, but very lightweight without any other dependencies from the jQuery UI suite.
|
||||
* [jQuery Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) (included): Required for [browsers without XHR file upload support](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support).
|
||||
|
||||
### Optional requirements
|
||||
* [JavaScript Templates engine](https://github.com/blueimp/JavaScript-Templates) v. 2.5.4+: Used to render the selected and uploaded files for the Basic Plus UI and jQuery UI versions.
|
||||
* [JavaScript Load Image library](https://github.com/blueimp/JavaScript-Load-Image) v. 1.13.0+: Required for the image previews and resizing functionality.
|
||||
* [JavaScript Canvas to Blob polyfill](https://github.com/blueimp/JavaScript-Canvas-to-Blob) v. 2.1.1+:Required for the image previews and resizing functionality.
|
||||
* [blueimp Gallery](https://github.com/blueimp/Gallery) v. 2.15.1+: Used to display the uploaded images in a lightbox.
|
||||
* [Bootstrap](http://getbootstrap.com/) v. 3.2.0+
|
||||
* [Glyphicons](http://glyphicons.com/)
|
||||
|
||||
The user interface of all versions except the jQuery UI version is built with [Bootstrap](http://getbootstrap.com/) and icons from [Glyphicons](http://glyphicons.com/).
|
||||
|
||||
### Cross-domain requirements
|
||||
[Cross-domain File Uploads](https://github.com/blueimp/jQuery-File-Upload/wiki/Cross-domain-uploads) using the [Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) require a redirect back to the origin server to retrieve the upload results. The [example implementation](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/main.js) makes use of [result.html](https://github.com/blueimp/jQuery-File-Upload/blob/master/cors/result.html) as a static redirect page for the origin server.
|
||||
|
||||
The repository also includes the [jQuery XDomainRequest Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/cors/jquery.xdr-transport.js), which enables limited cross-domain AJAX requests in Microsoft Internet Explorer 8 and 9 (IE 10 supports cross-domain XHR requests).
|
||||
The XDomainRequest object allows GET and POST requests only and doesn't support file uploads. It is used on the [Demo](https://blueimp.github.io/jQuery-File-Upload/) to delete uploaded files from the cross-domain demo file upload service.
|
||||
|
||||
### Custom Backends
|
||||
|
||||
You can add support for various backends by adhering to the specification [outlined here](https://github.com/blueimp/jQuery-File-Upload/wiki/JSON-Response).
|
||||
|
||||
## Browsers
|
||||
|
||||
### Desktop browsers
|
||||
The File Upload plugin is regularly tested with the latest browser versions and supports the following minimal versions:
|
||||
|
||||
* Google Chrome
|
||||
* Apple Safari 4.0+
|
||||
* Mozilla Firefox 3.0+
|
||||
* Opera 11.0+
|
||||
* Microsoft Internet Explorer 6.0+
|
||||
|
||||
### Mobile browsers
|
||||
The File Upload plugin has been tested with and supports the following mobile browsers:
|
||||
|
||||
* Apple Safari on iOS 6.0+
|
||||
* Google Chrome on iOS 6.0+
|
||||
* Google Chrome on Android 4.0+
|
||||
* Default Browser on Android 2.3+
|
||||
* Opera Mobile 12.0+
|
||||
|
||||
### Supported features
|
||||
For a detailed overview of the features supported by each browser version, please have a look at the [Extended browser support information](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support).
|
||||
|
||||
## Contributing
|
||||
**Bug fixes** and **new features** can be proposed using [pull requests](https://github.com/blueimp/jQuery-File-Upload/pulls).
|
||||
Please read the [contribution guidelines](https://github.com/blueimp/jQuery-File-Upload/blob/master/CONTRIBUTING.md) before submitting a pull request.
|
||||
|
||||
## Support
|
||||
This project is actively maintained, but there is no official support channel.
|
||||
If you have a question that another developer might help you with, please post to [Stack Overflow](http://stackoverflow.com/questions/tagged/blueimp+jquery+file-upload) and tag your question with `blueimp jquery file upload`.
|
||||
|
||||
## License
|
||||
Released under the [MIT license](https://opensource.org/licenses/MIT).
|
211
public/file_uploader/angularjs.html
Executable file
|
@ -0,0 +1,211 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
/*
|
||||
* jQuery File Upload Plugin AngularJS Demo
|
||||
* https://github.com/blueimp/jQuery-File-Upload
|
||||
*
|
||||
* Copyright 2013, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Force latest IE rendering engine or ChromeFrame if installed -->
|
||||
<!--[if IE]>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<![endif]-->
|
||||
<meta charset="utf-8">
|
||||
<title>jQuery File Upload Demo - AngularJS version</title>
|
||||
<meta name="description" content="File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for AngularJS. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- Bootstrap styles -->
|
||||
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
|
||||
<!-- Generic page styles -->
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<!-- blueimp Gallery styles -->
|
||||
<link rel="stylesheet" href="//blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
|
||||
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
|
||||
<link rel="stylesheet" href="css/jquery.fileupload.css">
|
||||
<link rel="stylesheet" href="css/jquery.fileupload-ui.css">
|
||||
<!-- CSS adjustments for browsers with JavaScript disabled -->
|
||||
<noscript><link rel="stylesheet" href="css/jquery.fileupload-noscript.css"></noscript>
|
||||
<noscript><link rel="stylesheet" href="css/jquery.fileupload-ui-noscript.css"></noscript>
|
||||
<style>
|
||||
/* Hide Angular JS elements before initializing */
|
||||
.ng-cloak {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="navbar navbar-default navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-fixed-top .navbar-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="https://github.com/blueimp/jQuery-File-Upload">jQuery File Upload</a>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload/tags">Download</a></li>
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload">Source Code</a></li>
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki">Documentation</a></li>
|
||||
<li><a href="https://blueimp.net">© Sebastian Tschan</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<h1>jQuery File Upload Demo</h1>
|
||||
<h2 class="lead">AngularJS version</h2>
|
||||
<ul class="nav nav-tabs">
|
||||
<li><a href="basic.html">Basic</a></li>
|
||||
<li><a href="basic-plus.html">Basic Plus</a></li>
|
||||
<li><a href="index.html">Basic Plus UI</a></li>
|
||||
<li class="active"><a href="angularjs.html">AngularJS</a></li>
|
||||
<li><a href="jquery-ui.html">jQuery UI</a></li>
|
||||
</ul>
|
||||
<br>
|
||||
<blockquote>
|
||||
<p>File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for AngularJS.<br>
|
||||
Supports cross-domain, chunked and resumable file uploads and client-side image resizing.<br>
|
||||
Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.</p>
|
||||
</blockquote>
|
||||
<br>
|
||||
<!-- The file upload form used as target for the file upload widget -->
|
||||
<form id="fileupload" action="//jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data" data-ng-app="demo" data-ng-controller="DemoFileUploadController" data-file-upload="options" data-ng-class="{'fileupload-processing': processing() || loadingFiles}">
|
||||
<!-- Redirect browsers with JavaScript disabled to the origin page -->
|
||||
<noscript><input type="hidden" name="redirect" value="https://blueimp.github.io/jQuery-File-Upload/"></noscript>
|
||||
<!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
|
||||
<div class="row fileupload-buttonbar">
|
||||
<div class="col-lg-7">
|
||||
<!-- The fileinput-button span is used to style the file input field as button -->
|
||||
<span class="btn btn-success fileinput-button" ng-class="{disabled: disabled}">
|
||||
<i class="glyphicon glyphicon-plus"></i>
|
||||
<span>Add files...</span>
|
||||
<input type="file" name="files[]" multiple ng-disabled="disabled">
|
||||
</span>
|
||||
<button type="button" class="btn btn-primary start" data-ng-click="submit()">
|
||||
<i class="glyphicon glyphicon-upload"></i>
|
||||
<span>Start upload</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-warning cancel" data-ng-click="cancel()">
|
||||
<i class="glyphicon glyphicon-ban-circle"></i>
|
||||
<span>Cancel upload</span>
|
||||
</button>
|
||||
<!-- The global file processing state -->
|
||||
<span class="fileupload-process"></span>
|
||||
</div>
|
||||
<!-- The global progress state -->
|
||||
<div class="col-lg-5 fade" data-ng-class="{in: active()}">
|
||||
<!-- The global progress bar -->
|
||||
<div class="progress progress-striped active" data-file-upload-progress="progress()"><div class="progress-bar progress-bar-success" data-ng-style="{width: num + '%'}"></div></div>
|
||||
<!-- The extended global progress state -->
|
||||
<div class="progress-extended"> </div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- The table listing the files available for upload/download -->
|
||||
<table class="table table-striped files ng-cloak">
|
||||
<tr data-ng-repeat="file in queue" data-ng-class="{'processing': file.$processing()}">
|
||||
<td data-ng-switch data-on="!!file.thumbnailUrl">
|
||||
<div class="preview" data-ng-switch-when="true">
|
||||
<a data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}" data-gallery><img data-ng-src="{{file.thumbnailUrl}}" alt=""></a>
|
||||
</div>
|
||||
<div class="preview" data-ng-switch-default data-file-upload-preview="file"></div>
|
||||
</td>
|
||||
<td>
|
||||
<p class="name" data-ng-switch data-on="!!file.url">
|
||||
<span data-ng-switch-when="true" data-ng-switch data-on="!!file.thumbnailUrl">
|
||||
<a data-ng-switch-when="true" data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}" data-gallery>{{file.name}}</a>
|
||||
<a data-ng-switch-default data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}">{{file.name}}</a>
|
||||
</span>
|
||||
<span data-ng-switch-default>{{file.name}}</span>
|
||||
</p>
|
||||
<strong data-ng-show="file.error" class="error text-danger">{{file.error}}</strong>
|
||||
</td>
|
||||
<td>
|
||||
<p class="size">{{file.size | formatFileSize}}</p>
|
||||
<div class="progress progress-striped active fade" data-ng-class="{pending: 'in'}[file.$state()]" data-file-upload-progress="file.$progress()"><div class="progress-bar progress-bar-success" data-ng-style="{width: num + '%'}"></div></div>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-primary start" data-ng-click="file.$submit()" data-ng-hide="!file.$submit || options.autoUpload" data-ng-disabled="file.$state() == 'pending' || file.$state() == 'rejected'">
|
||||
<i class="glyphicon glyphicon-upload"></i>
|
||||
<span>Start</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-warning cancel" data-ng-click="file.$cancel()" data-ng-hide="!file.$cancel">
|
||||
<i class="glyphicon glyphicon-ban-circle"></i>
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
<button data-ng-controller="FileDestroyController" type="button" class="btn btn-danger destroy" data-ng-click="file.$destroy()" data-ng-hide="!file.$destroy">
|
||||
<i class="glyphicon glyphicon-trash"></i>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<br>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Demo Notes</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<ul>
|
||||
<li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
|
||||
<li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
|
||||
<li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
|
||||
<li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
|
||||
<li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
|
||||
<li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- The blueimp Gallery widget -->
|
||||
<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls" data-filter=":even">
|
||||
<div class="slides"></div>
|
||||
<h3 class="title"></h3>
|
||||
<a class="prev">‹</a>
|
||||
<a class="next">›</a>
|
||||
<a class="close">×</a>
|
||||
<a class="play-pause"></a>
|
||||
<ol class="indicator"></ol>
|
||||
</div>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
|
||||
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
|
||||
<script src="js/vendor/jquery.ui.widget.js"></script>
|
||||
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
|
||||
<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
|
||||
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
|
||||
<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
|
||||
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
|
||||
<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
|
||||
<!-- blueimp Gallery script -->
|
||||
<script src="//blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
|
||||
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
|
||||
<script src="js/jquery.iframe-transport.js"></script>
|
||||
<!-- The basic File Upload plugin -->
|
||||
<script src="js/jquery.fileupload.js"></script>
|
||||
<!-- The File Upload processing plugin -->
|
||||
<script src="js/jquery.fileupload-process.js"></script>
|
||||
<!-- The File Upload image preview & resize plugin -->
|
||||
<script src="js/jquery.fileupload-image.js"></script>
|
||||
<!-- The File Upload audio preview plugin -->
|
||||
<script src="js/jquery.fileupload-audio.js"></script>
|
||||
<!-- The File Upload video preview plugin -->
|
||||
<script src="js/jquery.fileupload-video.js"></script>
|
||||
<!-- The File Upload validation plugin -->
|
||||
<script src="js/jquery.fileupload-validate.js"></script>
|
||||
<!-- The File Upload Angular JS module -->
|
||||
<script src="js/jquery.fileupload-angular.js"></script>
|
||||
<!-- The main application script -->
|
||||
<script src="js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
226
public/file_uploader/basic-plus.html
Executable file
|
@ -0,0 +1,226 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
/*
|
||||
* jQuery File Upload Plugin Basic Plus Demo
|
||||
* https://github.com/blueimp/jQuery-File-Upload
|
||||
*
|
||||
* Copyright 2013, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Force latest IE rendering engine or ChromeFrame if installed -->
|
||||
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><![endif]-->
|
||||
<meta charset="utf-8">
|
||||
<title>jQuery File Upload Demo - Basic Plus version</title>
|
||||
<meta name="description" content="File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- Bootstrap styles -->
|
||||
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
|
||||
<!-- Generic page styles -->
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
|
||||
<link rel="stylesheet" href="css/jquery.fileupload.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="navbar navbar-default navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-fixed-top .navbar-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="https://github.com/blueimp/jQuery-File-Upload">jQuery File Upload</a>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload/tags">Download</a></li>
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload">Source Code</a></li>
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki">Documentation</a></li>
|
||||
<li><a href="https://blueimp.net">© Sebastian Tschan</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<h1>jQuery File Upload Demo</h1>
|
||||
<h2 class="lead">Basic Plus version</h2>
|
||||
<ul class="nav nav-tabs">
|
||||
<li><a href="basic.html">Basic</a></li>
|
||||
<li class="active"><a href="basic-plus.html">Basic Plus</a></li>
|
||||
<li><a href="index.html">Basic Plus UI</a></li>
|
||||
<li><a href="angularjs.html">AngularJS</a></li>
|
||||
<li><a href="jquery-ui.html">jQuery UI</a></li>
|
||||
</ul>
|
||||
<br>
|
||||
<blockquote>
|
||||
<p>File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery.<br>
|
||||
Supports cross-domain, chunked and resumable file uploads and client-side image resizing.<br>
|
||||
Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.</p>
|
||||
</blockquote>
|
||||
<br>
|
||||
<!-- The fileinput-button span is used to style the file input field as button -->
|
||||
<span class="btn btn-success fileinput-button">
|
||||
<i class="glyphicon glyphicon-plus"></i>
|
||||
<span>Add files...</span>
|
||||
<!-- The file input field used as target for the file upload widget -->
|
||||
<input id="fileupload" type="file" name="files[]" multiple>
|
||||
</span>
|
||||
<br>
|
||||
<br>
|
||||
<!-- The global progress bar -->
|
||||
<div id="progress" class="progress">
|
||||
<div class="progress-bar progress-bar-success"></div>
|
||||
</div>
|
||||
<!-- The container for the uploaded files -->
|
||||
<div id="files" class="files"></div>
|
||||
<br>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Demo Notes</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<ul>
|
||||
<li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
|
||||
<li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
|
||||
<li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
|
||||
<li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
|
||||
<li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
|
||||
<li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
||||
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
|
||||
<script src="js/vendor/jquery.ui.widget.js"></script>
|
||||
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
|
||||
<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
|
||||
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
|
||||
<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
|
||||
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
|
||||
<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
|
||||
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
|
||||
<script src="js/jquery.iframe-transport.js"></script>
|
||||
<!-- The basic File Upload plugin -->
|
||||
<script src="js/jquery.fileupload.js"></script>
|
||||
<!-- The File Upload processing plugin -->
|
||||
<script src="js/jquery.fileupload-process.js"></script>
|
||||
<!-- The File Upload image preview & resize plugin -->
|
||||
<script src="js/jquery.fileupload-image.js"></script>
|
||||
<!-- The File Upload audio preview plugin -->
|
||||
<script src="js/jquery.fileupload-audio.js"></script>
|
||||
<!-- The File Upload video preview plugin -->
|
||||
<script src="js/jquery.fileupload-video.js"></script>
|
||||
<!-- The File Upload validation plugin -->
|
||||
<script src="js/jquery.fileupload-validate.js"></script>
|
||||
<script>
|
||||
/*jslint unparam: true, regexp: true */
|
||||
/*global window, $ */
|
||||
$(function () {
|
||||
'use strict';
|
||||
// Change this to the location of your server-side upload handler:
|
||||
var url = window.location.hostname === 'blueimp.github.io' ?
|
||||
'//jquery-file-upload.appspot.com/' : 'server/php/',
|
||||
uploadButton = $('<button/>')
|
||||
.addClass('btn btn-primary')
|
||||
.prop('disabled', true)
|
||||
.text('Processing...')
|
||||
.on('click', function () {
|
||||
var $this = $(this),
|
||||
data = $this.data();
|
||||
$this
|
||||
.off('click')
|
||||
.text('Abort')
|
||||
.on('click', function () {
|
||||
$this.remove();
|
||||
data.abort();
|
||||
});
|
||||
data.submit().always(function () {
|
||||
$this.remove();
|
||||
});
|
||||
});
|
||||
$('#fileupload').fileupload({
|
||||
url: url,
|
||||
dataType: 'json',
|
||||
autoUpload: false,
|
||||
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
|
||||
maxFileSize: 999000,
|
||||
// Enable image resizing, except for Android and Opera,
|
||||
// which actually support image resizing, but fail to
|
||||
// send Blob objects via XHR requests:
|
||||
disableImageResize: /Android(?!.*Chrome)|Opera/
|
||||
.test(window.navigator.userAgent),
|
||||
previewMaxWidth: 100,
|
||||
previewMaxHeight: 100,
|
||||
previewCrop: true
|
||||
}).on('fileuploadadd', function (e, data) {
|
||||
data.context = $('<div/>').appendTo('#files');
|
||||
$.each(data.files, function (index, file) {
|
||||
var node = $('<p/>')
|
||||
.append($('<span/>').text(file.name));
|
||||
if (!index) {
|
||||
node
|
||||
.append('<br>')
|
||||
.append(uploadButton.clone(true).data(data));
|
||||
}
|
||||
node.appendTo(data.context);
|
||||
});
|
||||
}).on('fileuploadprocessalways', function (e, data) {
|
||||
var index = data.index,
|
||||
file = data.files[index],
|
||||
node = $(data.context.children()[index]);
|
||||
if (file.preview) {
|
||||
node
|
||||
.prepend('<br>')
|
||||
.prepend(file.preview);
|
||||
}
|
||||
if (file.error) {
|
||||
node
|
||||
.append('<br>')
|
||||
.append($('<span class="text-danger"/>').text(file.error));
|
||||
}
|
||||
if (index + 1 === data.files.length) {
|
||||
data.context.find('button')
|
||||
.text('Upload')
|
||||
.prop('disabled', !!data.files.error);
|
||||
}
|
||||
}).on('fileuploadprogressall', function (e, data) {
|
||||
var progress = parseInt(data.loaded / data.total * 100, 10);
|
||||
$('#progress .progress-bar').css(
|
||||
'width',
|
||||
progress + '%'
|
||||
);
|
||||
}).on('fileuploaddone', function (e, data) {
|
||||
$.each(data.result.files, function (index, file) {
|
||||
if (file.url) {
|
||||
var link = $('<a>')
|
||||
.attr('target', '_blank')
|
||||
.prop('href', file.url);
|
||||
$(data.context.children()[index])
|
||||
.wrap(link);
|
||||
} else if (file.error) {
|
||||
var error = $('<span class="text-danger"/>').text(file.error);
|
||||
$(data.context.children()[index])
|
||||
.append('<br>')
|
||||
.append(error);
|
||||
}
|
||||
});
|
||||
}).on('fileuploadfail', function (e, data) {
|
||||
$.each(data.files, function (index) {
|
||||
var error = $('<span class="text-danger"/>').text('File upload failed.');
|
||||
$(data.context.children()[index])
|
||||
.append('<br>')
|
||||
.append(error);
|
||||
});
|
||||
}).prop('disabled', !$.support.fileInput)
|
||||
.parent().addClass($.support.fileInput ? undefined : 'disabled');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
136
public/file_uploader/basic.html
Executable file
|
@ -0,0 +1,136 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
/*
|
||||
* jQuery File Upload Plugin Basic Demo
|
||||
* https://github.com/blueimp/jQuery-File-Upload
|
||||
*
|
||||
* Copyright 2013, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Force latest IE rendering engine or ChromeFrame if installed -->
|
||||
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><![endif]-->
|
||||
<meta charset="utf-8">
|
||||
<title>jQuery File Upload Demo - Basic version</title>
|
||||
<meta name="description" content="File Upload widget with multiple file selection, drag&drop support and progress bar for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- Bootstrap styles -->
|
||||
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
|
||||
<!-- Generic page styles -->
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
|
||||
<link rel="stylesheet" href="css/jquery.fileupload.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="navbar navbar-default navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-fixed-top .navbar-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="https://github.com/blueimp/jQuery-File-Upload">jQuery File Upload</a>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload/tags">Download</a></li>
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload">Source Code</a></li>
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki">Documentation</a></li>
|
||||
<li><a href="https://blueimp.net">© Sebastian Tschan</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<h1>jQuery File Upload Demo</h1>
|
||||
<h2 class="lead">Basic version</h2>
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="basic.html">Basic</a></li>
|
||||
<li><a href="basic-plus.html">Basic Plus</a></li>
|
||||
<li><a href="index.html">Basic Plus UI</a></li>
|
||||
<li><a href="angularjs.html">AngularJS</a></li>
|
||||
<li><a href="jquery-ui.html">jQuery UI</a></li>
|
||||
</ul>
|
||||
<br>
|
||||
<blockquote>
|
||||
<p>File Upload widget with multiple file selection, drag&drop support and progress bar for jQuery.<br>
|
||||
Supports cross-domain, chunked and resumable file uploads.<br>
|
||||
Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.</p>
|
||||
</blockquote>
|
||||
<br>
|
||||
<!-- The fileinput-button span is used to style the file input field as button -->
|
||||
<span class="btn btn-success fileinput-button">
|
||||
<i class="glyphicon glyphicon-plus"></i>
|
||||
<span>Select files...</span>
|
||||
<!-- The file input field used as target for the file upload widget -->
|
||||
<input id="fileupload" type="file" name="files[]" multiple>
|
||||
</span>
|
||||
<br>
|
||||
<br>
|
||||
<!-- The global progress bar -->
|
||||
<div id="progress" class="progress">
|
||||
<div class="progress-bar progress-bar-success"></div>
|
||||
</div>
|
||||
<!-- The container for the uploaded files -->
|
||||
<div id="files" class="files"></div>
|
||||
<br>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Demo Notes</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<ul>
|
||||
<li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
|
||||
<li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
|
||||
<li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
|
||||
<li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
|
||||
<li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
|
||||
<li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
||||
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
|
||||
<script src="js/vendor/jquery.ui.widget.js"></script>
|
||||
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
|
||||
<script src="js/jquery.iframe-transport.js"></script>
|
||||
<!-- The basic File Upload plugin -->
|
||||
<script src="js/jquery.fileupload.js"></script>
|
||||
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
|
||||
<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
|
||||
<script>
|
||||
/*jslint unparam: true */
|
||||
/*global window, $ */
|
||||
$(function () {
|
||||
'use strict';
|
||||
// Change this to the location of your server-side upload handler:
|
||||
var url = window.location.hostname === 'blueimp.github.io' ?
|
||||
'//jquery-file-upload.appspot.com/' : 'server/php/';
|
||||
$('#fileupload').fileupload({
|
||||
url: url,
|
||||
dataType: 'json',
|
||||
done: function (e, data) {
|
||||
$.each(data.result.files, function (index, file) {
|
||||
$('<p/>').text(file.name).appendTo('#files');
|
||||
});
|
||||
},
|
||||
progressall: function (e, data) {
|
||||
var progress = parseInt(data.loaded / data.total * 100, 10);
|
||||
$('#progress .progress-bar').css(
|
||||
'width',
|
||||
progress + '%'
|
||||
);
|
||||
}
|
||||
}).prop('disabled', !$.support.fileInput)
|
||||
.parent().addClass($.support.fileInput ? undefined : 'disabled');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
16
public/file_uploader/bower-version-update.js
Executable file
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var packageJSON = require(path.join(__dirname, 'package.json'));
|
||||
var bowerFile = path.join(__dirname, 'bower.json');
|
||||
var bowerJSON = require('bower-json').parse(
|
||||
require(bowerFile),
|
||||
{normalize: true}
|
||||
);
|
||||
bowerJSON.version = packageJSON.version;
|
||||
require('fs').writeFileSync(
|
||||
bowerFile,
|
||||
JSON.stringify(bowerJSON, null, 2) + '\n'
|
||||
);
|
64
public/file_uploader/bower.json
Executable file
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"name": "blueimp-file-upload",
|
||||
"version": "9.18.0",
|
||||
"title": "jQuery File Upload",
|
||||
"description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images.",
|
||||
"keywords": [
|
||||
"jquery",
|
||||
"file",
|
||||
"upload",
|
||||
"widget",
|
||||
"multiple",
|
||||
"selection",
|
||||
"drag",
|
||||
"drop",
|
||||
"progress",
|
||||
"preview",
|
||||
"cross-domain",
|
||||
"cross-site",
|
||||
"chunk",
|
||||
"resume",
|
||||
"gae",
|
||||
"go",
|
||||
"python",
|
||||
"php",
|
||||
"bootstrap"
|
||||
],
|
||||
"homepage": "https://github.com/blueimp/jQuery-File-Upload",
|
||||
"author": {
|
||||
"name": "Sebastian Tschan",
|
||||
"url": "https://blueimp.net"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Sebastian Tschan",
|
||||
"url": "https://blueimp.net"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/blueimp/jQuery-File-Upload.git"
|
||||
},
|
||||
"bugs": "https://github.com/blueimp/jQuery-File-Upload/issues",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jquery": ">=1.6",
|
||||
"blueimp-tmpl": ">=2.5.4",
|
||||
"blueimp-load-image": ">=1.13.0",
|
||||
"blueimp-canvas-to-blob": ">=2.1.1"
|
||||
},
|
||||
"main": [
|
||||
"js/jquery.fileupload.js"
|
||||
],
|
||||
"ignore": [
|
||||
"/*.*",
|
||||
"/cors",
|
||||
"css/demo-ie8.css",
|
||||
"css/demo.css",
|
||||
"css/style.css",
|
||||
"js/app.js",
|
||||
"js/main.js",
|
||||
"server",
|
||||
"test"
|
||||
]
|
||||
}
|
75
public/file_uploader/cors/postmessage.html
Executable file
|
@ -0,0 +1,75 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
/*
|
||||
* jQuery File Upload Plugin postMessage API
|
||||
* https://github.com/blueimp/jQuery-File-Upload
|
||||
*
|
||||
* Copyright 2011, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>jQuery File Upload Plugin postMessage API</title>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
/*jslint unparam: true, regexp: true */
|
||||
/*global $, Blob, FormData, location */
|
||||
'use strict';
|
||||
var origin = /^http:\/\/example.org/,
|
||||
target = new RegExp('^(http(s)?:)?\\/\\/' + location.host + '\\/');
|
||||
$(window).on('message', function (e) {
|
||||
e = e.originalEvent;
|
||||
var s = e.data,
|
||||
xhr = $.ajaxSettings.xhr(),
|
||||
f;
|
||||
if (!origin.test(e.origin)) {
|
||||
throw new Error('Origin "' + e.origin + '" does not match ' + origin);
|
||||
}
|
||||
if (!target.test(e.data.url)) {
|
||||
throw new Error('Target "' + e.data.url + '" does not match ' + target);
|
||||
}
|
||||
$(xhr.upload).on('progress', function (ev) {
|
||||
ev = ev.originalEvent;
|
||||
e.source.postMessage({
|
||||
id: s.id,
|
||||
type: ev.type,
|
||||
timeStamp: ev.timeStamp,
|
||||
lengthComputable: ev.lengthComputable,
|
||||
loaded: ev.loaded,
|
||||
total: ev.total
|
||||
}, e.origin);
|
||||
});
|
||||
s.xhr = function () {
|
||||
return xhr;
|
||||
};
|
||||
if (!(s.data instanceof Blob)) {
|
||||
f = new FormData();
|
||||
$.each(s.data, function (i, v) {
|
||||
f.append(v.name, v.value);
|
||||
});
|
||||
s.data = f;
|
||||
}
|
||||
$.ajax(s).always(function (result, statusText, jqXHR) {
|
||||
if (!jqXHR.done) {
|
||||
jqXHR = result;
|
||||
result = null;
|
||||
}
|
||||
e.source.postMessage({
|
||||
id: s.id,
|
||||
status: jqXHR.status,
|
||||
statusText: statusText,
|
||||
result: result,
|
||||
headers: jqXHR.getAllResponseHeaders()
|
||||
}, e.origin);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
24
public/file_uploader/cors/result.html
Executable file
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
/*
|
||||
* jQuery Iframe Transport Plugin Redirect Page
|
||||
* https://github.com/blueimp/jQuery-File-Upload
|
||||
*
|
||||
* Copyright 2010, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>jQuery Iframe Transport Plugin Redirect Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
document.body.innerText=document.body.textContent=decodeURIComponent(window.location.search.slice(1));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
0
public/file_uploader/css/jquery-ui-demo-ie8.css → public/file_uploader/css/demo-ie8.css
Normal file → Executable file
0
public/file_uploader/css/jquery-ui-demo.css → public/file_uploader/css/demo.css
Normal file → Executable file
0
public/file_uploader/css/jquery.fileupload-noscript.css
Normal file → Executable file
0
public/file_uploader/css/jquery.fileupload-ui-noscript.css
Normal file → Executable file
0
public/file_uploader/css/jquery.fileupload-ui.css
Normal file → Executable file
0
public/file_uploader/css/jquery.fileupload.css
Normal file → Executable file
0
public/file_uploader/css/style.css
Normal file → Executable file
0
public/file_uploader/img/loading.gif
Normal file → Executable file
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
0
public/file_uploader/img/progressbar.gif
Normal file → Executable file
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
255
public/file_uploader/index.html
Executable file
|
@ -0,0 +1,255 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
/*
|
||||
* jQuery File Upload Plugin Demo
|
||||
* https://github.com/blueimp/jQuery-File-Upload
|
||||
*
|
||||
* Copyright 2010, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Force latest IE rendering engine or ChromeFrame if installed -->
|
||||
<!--[if IE]>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<![endif]-->
|
||||
<meta charset="utf-8">
|
||||
<title>jQuery File Upload Demo</title>
|
||||
<meta name="description" content="File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- Bootstrap styles -->
|
||||
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
|
||||
<!-- Generic page styles -->
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<!-- blueimp Gallery styles -->
|
||||
<link rel="stylesheet" href="//blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
|
||||
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
|
||||
<link rel="stylesheet" href="css/jquery.fileupload.css">
|
||||
<link rel="stylesheet" href="css/jquery.fileupload-ui.css">
|
||||
<!-- CSS adjustments for browsers with JavaScript disabled -->
|
||||
<noscript><link rel="stylesheet" href="css/jquery.fileupload-noscript.css"></noscript>
|
||||
<noscript><link rel="stylesheet" href="css/jquery.fileupload-ui-noscript.css"></noscript>
|
||||
</head>
|
||||
<body>
|
||||
<div class="navbar navbar-default navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-fixed-top .navbar-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="https://github.com/blueimp/jQuery-File-Upload">jQuery File Upload</a>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload/tags">Download</a></li>
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload">Source Code</a></li>
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki">Documentation</a></li>
|
||||
<li><a href="https://blueimp.net">© Sebastian Tschan</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<h1>jQuery File Upload Demo</h1>
|
||||
<h2 class="lead">Basic Plus UI version</h2>
|
||||
<ul class="nav nav-tabs">
|
||||
<li><a href="basic.html">Basic</a></li>
|
||||
<li><a href="basic-plus.html">Basic Plus</a></li>
|
||||
<li class="active"><a href="index.html">Basic Plus UI</a></li>
|
||||
<li><a href="angularjs.html">AngularJS</a></li>
|
||||
<li><a href="jquery-ui.html">jQuery UI</a></li>
|
||||
</ul>
|
||||
<br>
|
||||
<blockquote>
|
||||
<p>File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for jQuery.<br>
|
||||
Supports cross-domain, chunked and resumable file uploads and client-side image resizing.<br>
|
||||
Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.</p>
|
||||
</blockquote>
|
||||
<br>
|
||||
<!-- The file upload form used as target for the file upload widget -->
|
||||
<form id="fileupload" action="//jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data">
|
||||
<!-- Redirect browsers with JavaScript disabled to the origin page -->
|
||||
<noscript><input type="hidden" name="redirect" value="https://blueimp.github.io/jQuery-File-Upload/"></noscript>
|
||||
<!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
|
||||
<div class="row fileupload-buttonbar">
|
||||
<div class="col-lg-7">
|
||||
<!-- The fileinput-button span is used to style the file input field as button -->
|
||||
<span class="btn btn-success fileinput-button">
|
||||
<i class="glyphicon glyphicon-plus"></i>
|
||||
<span>Add files...</span>
|
||||
<input type="file" name="files[]" multiple>
|
||||
</span>
|
||||
<button type="submit" class="btn btn-primary start">
|
||||
<i class="glyphicon glyphicon-upload"></i>
|
||||
<span>Start upload</span>
|
||||
</button>
|
||||
<button type="reset" class="btn btn-warning cancel">
|
||||
<i class="glyphicon glyphicon-ban-circle"></i>
|
||||
<span>Cancel upload</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger delete">
|
||||
<i class="glyphicon glyphicon-trash"></i>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
<input type="checkbox" class="toggle">
|
||||
<!-- The global file processing state -->
|
||||
<span class="fileupload-process"></span>
|
||||
</div>
|
||||
<!-- The global progress state -->
|
||||
<div class="col-lg-5 fileupload-progress fade">
|
||||
<!-- The global progress bar -->
|
||||
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100">
|
||||
<div class="progress-bar progress-bar-success" style="width:0%;"></div>
|
||||
</div>
|
||||
<!-- The extended global progress state -->
|
||||
<div class="progress-extended"> </div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- The table listing the files available for upload/download -->
|
||||
<table role="presentation" class="table table-striped"><tbody class="files"></tbody></table>
|
||||
</form>
|
||||
<br>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Demo Notes</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<ul>
|
||||
<li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
|
||||
<li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
|
||||
<li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
|
||||
<li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
|
||||
<li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
|
||||
<li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- The blueimp Gallery widget -->
|
||||
<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls" data-filter=":even">
|
||||
<div class="slides"></div>
|
||||
<h3 class="title"></h3>
|
||||
<a class="prev">‹</a>
|
||||
<a class="next">›</a>
|
||||
<a class="close">×</a>
|
||||
<a class="play-pause"></a>
|
||||
<ol class="indicator"></ol>
|
||||
</div>
|
||||
<!-- The template to display files available for upload -->
|
||||
<script id="template-upload" type="text/x-tmpl">
|
||||
{% for (var i=0, file; file=o.files[i]; i++) { %}
|
||||
<tr class="template-upload fade">
|
||||
<td>
|
||||
<span class="preview"></span>
|
||||
</td>
|
||||
<td>
|
||||
<p class="name">{%=file.name%}</p>
|
||||
<strong class="error text-danger"></strong>
|
||||
</td>
|
||||
<td>
|
||||
<p class="size">Processing...</p>
|
||||
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="progress-bar progress-bar-success" style="width:0%;"></div></div>
|
||||
</td>
|
||||
<td>
|
||||
{% if (!i && !o.options.autoUpload) { %}
|
||||
<button class="btn btn-primary start" disabled>
|
||||
<i class="glyphicon glyphicon-upload"></i>
|
||||
<span>Start</span>
|
||||
</button>
|
||||
{% } %}
|
||||
{% if (!i) { %}
|
||||
<button class="btn btn-warning cancel">
|
||||
<i class="glyphicon glyphicon-ban-circle"></i>
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
{% } %}
|
||||
</td>
|
||||
</tr>
|
||||
{% } %}
|
||||
</script>
|
||||
<!-- The template to display files available for download -->
|
||||
<script id="template-download" type="text/x-tmpl">
|
||||
{% for (var i=0, file; file=o.files[i]; i++) { %}
|
||||
<tr class="template-download fade">
|
||||
<td>
|
||||
<span class="preview">
|
||||
{% if (file.thumbnailUrl) { %}
|
||||
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a>
|
||||
{% } %}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<p class="name">
|
||||
{% if (file.url) { %}
|
||||
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a>
|
||||
{% } else { %}
|
||||
<span>{%=file.name%}</span>
|
||||
{% } %}
|
||||
</p>
|
||||
{% if (file.error) { %}
|
||||
<div><span class="label label-danger">Error</span> {%=file.error%}</div>
|
||||
{% } %}
|
||||
</td>
|
||||
<td>
|
||||
<span class="size">{%=o.formatFileSize(file.size)%}</span>
|
||||
</td>
|
||||
<td>
|
||||
{% if (file.deleteUrl) { %}
|
||||
<button class="btn btn-danger delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>
|
||||
<i class="glyphicon glyphicon-trash"></i>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
<input type="checkbox" name="delete" value="1" class="toggle">
|
||||
{% } else { %}
|
||||
<button class="btn btn-warning cancel">
|
||||
<i class="glyphicon glyphicon-ban-circle"></i>
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
{% } %}
|
||||
</td>
|
||||
</tr>
|
||||
{% } %}
|
||||
</script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
||||
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
|
||||
<script src="js/vendor/jquery.ui.widget.js"></script>
|
||||
<!-- The Templates plugin is included to render the upload/download listings -->
|
||||
<script src="//blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
|
||||
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
|
||||
<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
|
||||
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
|
||||
<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
|
||||
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
|
||||
<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
|
||||
<!-- blueimp Gallery script -->
|
||||
<script src="//blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
|
||||
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
|
||||
<script src="js/jquery.iframe-transport.js"></script>
|
||||
<!-- The basic File Upload plugin -->
|
||||
<script src="js/jquery.fileupload.js"></script>
|
||||
<!-- The File Upload processing plugin -->
|
||||
<script src="js/jquery.fileupload-process.js"></script>
|
||||
<!-- The File Upload image preview & resize plugin -->
|
||||
<script src="js/jquery.fileupload-image.js"></script>
|
||||
<!-- The File Upload audio preview plugin -->
|
||||
<script src="js/jquery.fileupload-audio.js"></script>
|
||||
<!-- The File Upload video preview plugin -->
|
||||
<script src="js/jquery.fileupload-video.js"></script>
|
||||
<!-- The File Upload validation plugin -->
|
||||
<script src="js/jquery.fileupload-validate.js"></script>
|
||||
<!-- The File Upload user interface plugin -->
|
||||
<script src="js/jquery.fileupload-ui.js"></script>
|
||||
<!-- The main application script -->
|
||||
<script src="js/main.js"></script>
|
||||
<!-- The XDomainRequest Transport is included for cross-domain file deletion for IE 8 and IE 9 -->
|
||||
<!--[if (gte IE 8)&(lt IE 10)]>
|
||||
<script src="js/cors/jquery.xdr-transport.js"></script>
|
||||
<![endif]-->
|
||||
</body>
|
||||
</html>
|
250
public/file_uploader/jquery-ui.html
Executable file
|
@ -0,0 +1,250 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
/*
|
||||
* jQuery File Upload Plugin jQuery UI Demo
|
||||
* https://github.com/blueimp/jQuery-File-Upload
|
||||
*
|
||||
* Copyright 2013, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Force latest IE rendering engine or ChromeFrame if installed -->
|
||||
<!--[if IE]>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<![endif]-->
|
||||
<meta charset="utf-8">
|
||||
<title>jQuery File Upload Demo - jQuery UI version</title>
|
||||
<meta name="description" content="File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- jQuery UI styles -->
|
||||
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/themes/dark-hive/jquery-ui.css" id="theme">
|
||||
<!-- Demo styles -->
|
||||
<link rel="stylesheet" href="css/demo.css">
|
||||
<!--[if lte IE 8]>
|
||||
<link rel="stylesheet" href="css/demo-ie8.css">
|
||||
<![endif]-->
|
||||
<style>
|
||||
/* Adjust the jQuery UI widget font-size: */
|
||||
.ui-widget {
|
||||
font-size: 0.95em;
|
||||
}
|
||||
</style>
|
||||
<!-- blueimp Gallery styles -->
|
||||
<link rel="stylesheet" href="//blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
|
||||
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
|
||||
<link rel="stylesheet" href="css/jquery.fileupload.css">
|
||||
<link rel="stylesheet" href="css/jquery.fileupload-ui.css">
|
||||
<!-- CSS adjustments for browsers with JavaScript disabled -->
|
||||
<noscript><link rel="stylesheet" href="css/jquery.fileupload-noscript.css"></noscript>
|
||||
<noscript><link rel="stylesheet" href="css/jquery.fileupload-ui-noscript.css"></noscript>
|
||||
</head>
|
||||
<body>
|
||||
<ul class="navigation">
|
||||
<li><h3><a href="https://github.com/blueimp/jQuery-File-Upload">jQuery File Upload</a></h3></li>
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload/tags">Download</a></li>
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload">Source Code</a></li>
|
||||
<li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki">Documentation</a></li>
|
||||
<li><a href="https://blueimp.net">© blueimp.net</a></li>
|
||||
</ul>
|
||||
<h1>jQuery File Upload Demo</h1>
|
||||
<h2>jQuery UI version</h2>
|
||||
<form>
|
||||
<label for="theme-switcher">Theme:</label>
|
||||
<select id="theme-switcher" class="pull-right">
|
||||
<option value="black-tie">Black Tie</option>
|
||||
<option value="blitzer">Blitzer</option>
|
||||
<option value="cupertino">Cupertino</option>
|
||||
<option value="dark-hive" selected>Dark Hive</option>
|
||||
<option value="dot-luv">Dot Luv</option>
|
||||
<option value="eggplant">Eggplant</option>
|
||||
<option value="excite-bike">Excite Bike</option>
|
||||
<option value="flick">Flick</option>
|
||||
<option value="hot-sneaks">Hot sneaks</option>
|
||||
<option value="humanity">Humanity</option>
|
||||
<option value="le-frog">Le Frog</option>
|
||||
<option value="mint-choc">Mint Choc</option>
|
||||
<option value="overcast">Overcast</option>
|
||||
<option value="pepper-grinder">Pepper Grinder</option>
|
||||
<option value="redmond">Redmond</option>
|
||||
<option value="smoothness">Smoothness</option>
|
||||
<option value="south-street">South Street</option>
|
||||
<option value="start">Start</option>
|
||||
<option value="sunny">Sunny</option>
|
||||
<option value="swanky-purse">Swanky Purse</option>
|
||||
<option value="trontastic">Trontastic</option>
|
||||
<option value="ui-darkness">UI Darkness</option>
|
||||
<option value="ui-lightness">UI Lightness</option>
|
||||
<option value="vader">Vader</option>
|
||||
</select>
|
||||
</form>
|
||||
<ul class="navigation">
|
||||
<li><a href="basic.html">Basic</a></li>
|
||||
<li><a href="basic-plus.html">Basic Plus</a></li>
|
||||
<li><a href="index.html">Basic Plus UI</a></li>
|
||||
<li><a href="angularjs.html">AngularJS</a></li>
|
||||
<li class="active"><a href="jquery-ui.html">jQuery UI</a></li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for jQuery UI.<br>
|
||||
Supports cross-domain, chunked and resumable file uploads and client-side image resizing.<br>
|
||||
Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.</p>
|
||||
</blockquote>
|
||||
<!-- The file upload form used as target for the file upload widget -->
|
||||
<form id="fileupload" action="//jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data">
|
||||
<!-- Redirect browsers with JavaScript disabled to the origin page -->
|
||||
<noscript><input type="hidden" name="redirect" value="https://blueimp.github.io/jQuery-File-Upload/"></noscript>
|
||||
<!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
|
||||
<div class="fileupload-buttonbar">
|
||||
<div class="fileupload-buttons">
|
||||
<!-- The fileinput-button span is used to style the file input field as button -->
|
||||
<span class="fileinput-button">
|
||||
<span>Add files...</span>
|
||||
<input type="file" name="files[]" multiple>
|
||||
</span>
|
||||
<button type="submit" class="start">Start upload</button>
|
||||
<button type="reset" class="cancel">Cancel upload</button>
|
||||
<button type="button" class="delete">Delete</button>
|
||||
<input type="checkbox" class="toggle">
|
||||
<!-- The global file processing state -->
|
||||
<span class="fileupload-process"></span>
|
||||
</div>
|
||||
<!-- The global progress state -->
|
||||
<div class="fileupload-progress fade" style="display:none">
|
||||
<!-- The global progress bar -->
|
||||
<div class="progress" role="progressbar" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
<!-- The extended global progress state -->
|
||||
<div class="progress-extended"> </div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- The table listing the files available for upload/download -->
|
||||
<table role="presentation"><tbody class="files"></tbody></table>
|
||||
</form>
|
||||
<br>
|
||||
<h3>Demo Notes</h3>
|
||||
<ul>
|
||||
<li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li>
|
||||
<li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
|
||||
<li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li>
|
||||
<li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
|
||||
<li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
|
||||
<li>Built with <a href="https://jqueryui.com">jQuery UI</a>.</li>
|
||||
</ul>
|
||||
<!-- The blueimp Gallery widget -->
|
||||
<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls" data-filter=":even">
|
||||
<div class="slides"></div>
|
||||
<h3 class="title"></h3>
|
||||
<a class="prev">‹</a>
|
||||
<a class="next">›</a>
|
||||
<a class="close">×</a>
|
||||
<a class="play-pause"></a>
|
||||
<ol class="indicator"></ol>
|
||||
</div>
|
||||
<!-- The template to display files available for upload -->
|
||||
<script id="template-upload" type="text/x-tmpl">
|
||||
{% for (var i=0, file; file=o.files[i]; i++) { %}
|
||||
<tr class="template-upload fade">
|
||||
<td>
|
||||
<span class="preview"></span>
|
||||
</td>
|
||||
<td>
|
||||
<p class="name">{%=file.name%}</p>
|
||||
<strong class="error"></strong>
|
||||
</td>
|
||||
<td>
|
||||
<p class="size">Processing...</p>
|
||||
<div class="progress"></div>
|
||||
</td>
|
||||
<td>
|
||||
{% if (!i && !o.options.autoUpload) { %}
|
||||
<button class="start" disabled>Start</button>
|
||||
{% } %}
|
||||
{% if (!i) { %}
|
||||
<button class="cancel">Cancel</button>
|
||||
{% } %}
|
||||
</td>
|
||||
</tr>
|
||||
{% } %}
|
||||
</script>
|
||||
<!-- The template to display files available for download -->
|
||||
<script id="template-download" type="text/x-tmpl">
|
||||
{% for (var i=0, file; file=o.files[i]; i++) { %}
|
||||
<tr class="template-download fade">
|
||||
<td>
|
||||
<span class="preview">
|
||||
{% if (file.thumbnailUrl) { %}
|
||||
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a>
|
||||
{% } %}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<p class="name">
|
||||
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a>
|
||||
</p>
|
||||
{% if (file.error) { %}
|
||||
<div><span class="error">Error</span> {%=file.error%}</div>
|
||||
{% } %}
|
||||
</td>
|
||||
<td>
|
||||
<span class="size">{%=o.formatFileSize(file.size)%}</span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>Delete</button>
|
||||
<input type="checkbox" name="delete" value="1" class="toggle">
|
||||
</td>
|
||||
</tr>
|
||||
{% } %}
|
||||
</script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
|
||||
<!-- The Templates plugin is included to render the upload/download listings -->
|
||||
<script src="//blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
|
||||
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
|
||||
<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
|
||||
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
|
||||
<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
|
||||
<!-- blueimp Gallery script -->
|
||||
<script src="//blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
|
||||
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
|
||||
<script src="js/jquery.iframe-transport.js"></script>
|
||||
<!-- The basic File Upload plugin -->
|
||||
<script src="js/jquery.fileupload.js"></script>
|
||||
<!-- The File Upload processing plugin -->
|
||||
<script src="js/jquery.fileupload-process.js"></script>
|
||||
<!-- The File Upload image preview & resize plugin -->
|
||||
<script src="js/jquery.fileupload-image.js"></script>
|
||||
<!-- The File Upload audio preview plugin -->
|
||||
<script src="js/jquery.fileupload-audio.js"></script>
|
||||
<!-- The File Upload video preview plugin -->
|
||||
<script src="js/jquery.fileupload-video.js"></script>
|
||||
<!-- The File Upload validation plugin -->
|
||||
<script src="js/jquery.fileupload-validate.js"></script>
|
||||
<!-- The File Upload user interface plugin -->
|
||||
<script src="js/jquery.fileupload-ui.js"></script>
|
||||
<!-- The File Upload jQuery UI plugin -->
|
||||
<script src="js/jquery.fileupload-jquery-ui.js"></script>
|
||||
<!-- The main application script -->
|
||||
<script src="js/main.js"></script>
|
||||
<script>
|
||||
// Initialize the jQuery UI theme switcher:
|
||||
$('#theme-switcher').change(function () {
|
||||
var theme = $('#theme');
|
||||
theme.prop(
|
||||
'href',
|
||||
theme.prop('href').replace(
|
||||
/[\w\-]+\/jquery-ui.css/,
|
||||
$(this).val() + '/jquery-ui.css'
|
||||
)
|
||||
);
|
||||
});
|
||||
</script>
|
||||
<!-- The XDomainRequest Transport is included for cross-domain file deletion for IE 8 and IE 9 -->
|
||||
<!--[if (gte IE 8)&(lt IE 10)]>
|
||||
<script src="js/cors/jquery.xdr-transport.js"></script>
|
||||
<![endif]-->
|
||||
</body>
|
||||
</html>
|
0
public/file_uploader/js/app.js
Normal file → Executable file
0
public/file_uploader/js/cors/jquery.postmessage-transport.js
Normal file → Executable file
0
public/file_uploader/js/cors/jquery.xdr-transport.js
Normal file → Executable file
0
public/file_uploader/js/jquery.fileupload-angular.js
vendored
Normal file → Executable file
0
public/file_uploader/js/jquery.fileupload-audio.js
vendored
Normal file → Executable file
0
public/file_uploader/js/jquery.fileupload-image.js
vendored
Normal file → Executable file
0
public/file_uploader/js/jquery.fileupload-jquery-ui.js
Normal file → Executable file
0
public/file_uploader/js/jquery.fileupload-process.js
vendored
Normal file → Executable file
1
public/file_uploader/js/jquery.fileupload-ui.js
vendored
Normal file → Executable file
|
@ -30,7 +30,6 @@
|
|||
require('jquery'),
|
||||
require('blueimp-tmpl'),
|
||||
require('./jquery.fileupload-image'),
|
||||
require('./jquery.fileupload-audio'),
|
||||
require('./jquery.fileupload-video'),
|
||||
require('./jquery.fileupload-validate')
|
||||
);
|
||||
|
|
0
public/file_uploader/js/jquery.fileupload-validate.js
vendored
Normal file → Executable file
0
public/file_uploader/js/jquery.fileupload-video.js
vendored
Normal file → Executable file
16
public/file_uploader/js/jquery.fileupload.js
vendored
Normal file → Executable file
|
@ -43,7 +43,7 @@
|
|||
'|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
|
||||
).test(window.navigator.userAgent) ||
|
||||
// Feature detection for all other devices:
|
||||
$('<input type="file"/>').prop('disabled'));
|
||||
$('<input type="file">').prop('disabled'));
|
||||
|
||||
// The FileReader API is not actually used, but works as feature detection,
|
||||
// as some Safari versions (5?) support XHR file uploads via the FormData API,
|
||||
|
@ -453,7 +453,7 @@
|
|||
}
|
||||
if (!multipart || options.blob || !this._isInstanceOf('File', file)) {
|
||||
options.headers['Content-Disposition'] = 'attachment; filename="' +
|
||||
encodeURI(file.uploadName || file.name) + '"';
|
||||
encodeURI(file.name) + '"';
|
||||
}
|
||||
if (!multipart) {
|
||||
options.contentType = file.type || 'application/octet-stream';
|
||||
|
@ -489,11 +489,7 @@
|
|||
});
|
||||
}
|
||||
if (options.blob) {
|
||||
formData.append(
|
||||
paramName,
|
||||
options.blob,
|
||||
file.uploadName || file.name
|
||||
);
|
||||
formData.append(paramName, options.blob, file.name);
|
||||
} else {
|
||||
$.each(options.files, function (index, file) {
|
||||
// This check allows the tests to run with
|
||||
|
@ -734,7 +730,7 @@
|
|||
promise = dfd.promise(),
|
||||
jqXHR,
|
||||
upload;
|
||||
if (!(this._isXHRUpload(options) && slice && (ub || ($.type(mcs) === 'function' ? mcs(options) : mcs) < fs)) ||
|
||||
if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) ||
|
||||
options.data) {
|
||||
return false;
|
||||
}
|
||||
|
@ -757,7 +753,7 @@
|
|||
o.blob = slice.call(
|
||||
file,
|
||||
ub,
|
||||
ub + ($.type(mcs) === 'function' ? mcs(o) : mcs),
|
||||
ub + mcs,
|
||||
file.type
|
||||
);
|
||||
// Store the current chunk size, as the blob itself
|
||||
|
@ -1130,7 +1126,7 @@
|
|||
dirReader = entry.createReader();
|
||||
readEntries();
|
||||
} else {
|
||||
// Return an empty list for file system items
|
||||
// Return an empy list for file system items
|
||||
// other than files or directories:
|
||||
dfd.resolve([]);
|
||||
}
|
||||
|
|
0
public/file_uploader/js/jquery.iframe-transport.js
Normal file → Executable file
0
public/file_uploader/js/main.js
Normal file → Executable file
1304
public/file_uploader/js/vendor/jquery.ui.widget.js
vendored
Normal file → Executable file
55
public/file_uploader/package.json
Executable file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "blueimp-file-upload",
|
||||
"version": "9.18.0",
|
||||
"title": "jQuery File Upload",
|
||||
"description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.",
|
||||
"keywords": [
|
||||
"jquery",
|
||||
"file",
|
||||
"upload",
|
||||
"widget",
|
||||
"multiple",
|
||||
"selection",
|
||||
"drag",
|
||||
"drop",
|
||||
"progress",
|
||||
"preview",
|
||||
"cross-domain",
|
||||
"cross-site",
|
||||
"chunk",
|
||||
"resume",
|
||||
"gae",
|
||||
"go",
|
||||
"python",
|
||||
"php",
|
||||
"bootstrap"
|
||||
],
|
||||
"homepage": "https://github.com/blueimp/jQuery-File-Upload",
|
||||
"author": {
|
||||
"name": "Sebastian Tschan",
|
||||
"url": "https://blueimp.net"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/blueimp/jQuery-File-Upload.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"blueimp-canvas-to-blob": "3.5.0",
|
||||
"blueimp-load-image": "2.12.2",
|
||||
"blueimp-tmpl": "3.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bower-json": "0.8.1",
|
||||
"jshint": "2.9.3"
|
||||
},
|
||||
"scripts": {
|
||||
"bower-version-update": "./bower-version-update.js",
|
||||
"lint": "jshint *.js js/*.js js/cors/*.js",
|
||||
"test": "npm run lint",
|
||||
"preversion": "npm test",
|
||||
"version": "npm run bower-version-update && git add bower.json",
|
||||
"postversion": "git push --tags origin master && npm publish"
|
||||
},
|
||||
"main": "js/jquery.fileupload.js"
|
||||
}
|
12
public/file_uploader/server/gae-go/app.yaml
Executable file
|
@ -0,0 +1,12 @@
|
|||
application: jquery-file-upload
|
||||
version: 2
|
||||
runtime: go
|
||||
api_version: go1
|
||||
|
||||
handlers:
|
||||
- url: /(favicon\.ico|robots\.txt)
|
||||
static_files: static/\1
|
||||
upload: static/(.*)
|
||||
expiration: '1d'
|
||||
- url: /.*
|
||||
script: _go_app
|
361
public/file_uploader/server/gae-go/app/main.go
Executable file
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
* jQuery File Upload Plugin GAE Go Example
|
||||
* https://github.com/blueimp/jQuery-File-Upload
|
||||
*
|
||||
* Copyright 2011, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/disintegration/gift"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/appengine"
|
||||
"google.golang.org/appengine/memcache"
|
||||
"hash/crc32"
|
||||
"image"
|
||||
"image/gif"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
WEBSITE = "https://blueimp.github.io/jQuery-File-Upload/"
|
||||
MIN_FILE_SIZE = 1 // bytes
|
||||
// Max file size is memcache limit (1MB) minus key size minus overhead:
|
||||
MAX_FILE_SIZE = 999000 // bytes
|
||||
IMAGE_TYPES = "image/(gif|p?jpeg|(x-)?png)"
|
||||
ACCEPT_FILE_TYPES = IMAGE_TYPES
|
||||
THUMB_MAX_WIDTH = 80
|
||||
THUMB_MAX_HEIGHT = 80
|
||||
EXPIRATION_TIME = 300 // seconds
|
||||
// If empty, only allow redirects to the referer protocol+host.
|
||||
// Set to a regexp string for custom pattern matching:
|
||||
REDIRECT_ALLOW_TARGET = ""
|
||||
)
|
||||
|
||||
var (
|
||||
imageTypes = regexp.MustCompile(IMAGE_TYPES)
|
||||
acceptFileTypes = regexp.MustCompile(ACCEPT_FILE_TYPES)
|
||||
thumbSuffix = "." + fmt.Sprint(THUMB_MAX_WIDTH) + "x" +
|
||||
fmt.Sprint(THUMB_MAX_HEIGHT)
|
||||
)
|
||||
|
||||
func escape(s string) string {
|
||||
return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
|
||||
}
|
||||
|
||||
func extractKey(r *http.Request) string {
|
||||
// Use RequestURI instead of r.URL.Path, as we need the encoded form:
|
||||
path := strings.Split(r.RequestURI, "?")[0]
|
||||
// Also adjust double encoded slashes:
|
||||
return strings.Replace(path[1:], "%252F", "%2F", -1)
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
Key string `json:"-"`
|
||||
ThumbnailKey string `json:"-"`
|
||||
Url string `json:"url,omitempty"`
|
||||
ThumbnailUrl string `json:"thumbnailUrl,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Size int64 `json:"size"`
|
||||
Error string `json:"error,omitempty"`
|
||||
DeleteUrl string `json:"deleteUrl,omitempty"`
|
||||
DeleteType string `json:"deleteType,omitempty"`
|
||||
}
|
||||
|
||||
func (fi *FileInfo) ValidateType() (valid bool) {
|
||||
if acceptFileTypes.MatchString(fi.Type) {
|
||||
return true
|
||||
}
|
||||
fi.Error = "Filetype not allowed"
|
||||
return false
|
||||
}
|
||||
|
||||
func (fi *FileInfo) ValidateSize() (valid bool) {
|
||||
if fi.Size < MIN_FILE_SIZE {
|
||||
fi.Error = "File is too small"
|
||||
} else if fi.Size > MAX_FILE_SIZE {
|
||||
fi.Error = "File is too big"
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (fi *FileInfo) CreateUrls(r *http.Request, c context.Context) {
|
||||
u := &url.URL{
|
||||
Scheme: r.URL.Scheme,
|
||||
Host: appengine.DefaultVersionHostname(c),
|
||||
Path: "/",
|
||||
}
|
||||
uString := u.String()
|
||||
fi.Url = uString + fi.Key
|
||||
fi.DeleteUrl = fi.Url
|
||||
fi.DeleteType = "DELETE"
|
||||
if fi.ThumbnailKey != "" {
|
||||
fi.ThumbnailUrl = uString + fi.ThumbnailKey
|
||||
}
|
||||
}
|
||||
|
||||
func (fi *FileInfo) SetKey(checksum uint32) {
|
||||
fi.Key = escape(string(fi.Type)) + "/" +
|
||||
escape(fmt.Sprint(checksum)) + "/" +
|
||||
escape(string(fi.Name))
|
||||
}
|
||||
|
||||
func (fi *FileInfo) createThumb(buffer *bytes.Buffer, c context.Context) {
|
||||
if imageTypes.MatchString(fi.Type) {
|
||||
src, _, err := image.Decode(bytes.NewReader(buffer.Bytes()))
|
||||
check(err)
|
||||
filter := gift.New(gift.ResizeToFit(
|
||||
THUMB_MAX_WIDTH,
|
||||
THUMB_MAX_HEIGHT,
|
||||
gift.LanczosResampling,
|
||||
))
|
||||
dst := image.NewNRGBA(filter.Bounds(src.Bounds()))
|
||||
filter.Draw(dst, src)
|
||||
buffer.Reset()
|
||||
bWriter := bufio.NewWriter(buffer)
|
||||
switch fi.Type {
|
||||
case "image/jpeg", "image/pjpeg":
|
||||
err = jpeg.Encode(bWriter, dst, nil)
|
||||
case "image/gif":
|
||||
err = gif.Encode(bWriter, dst, nil)
|
||||
default:
|
||||
err = png.Encode(bWriter, dst)
|
||||
}
|
||||
check(err)
|
||||
bWriter.Flush()
|
||||
thumbnailKey := fi.Key + thumbSuffix + filepath.Ext(fi.Name)
|
||||
item := &memcache.Item{
|
||||
Key: thumbnailKey,
|
||||
Value: buffer.Bytes(),
|
||||
}
|
||||
err = memcache.Set(c, item)
|
||||
check(err)
|
||||
fi.ThumbnailKey = thumbnailKey
|
||||
}
|
||||
}
|
||||
|
||||
func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) {
|
||||
fi = &FileInfo{
|
||||
Name: p.FileName(),
|
||||
Type: p.Header.Get("Content-Type"),
|
||||
}
|
||||
if !fi.ValidateType() {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if rec := recover(); rec != nil {
|
||||
log.Println(rec)
|
||||
fi.Error = rec.(error).Error()
|
||||
}
|
||||
}()
|
||||
var buffer bytes.Buffer
|
||||
hash := crc32.NewIEEE()
|
||||
mw := io.MultiWriter(&buffer, hash)
|
||||
lr := &io.LimitedReader{R: p, N: MAX_FILE_SIZE + 1}
|
||||
_, err := io.Copy(mw, lr)
|
||||
check(err)
|
||||
fi.Size = MAX_FILE_SIZE + 1 - lr.N
|
||||
if !fi.ValidateSize() {
|
||||
return
|
||||
}
|
||||
fi.SetKey(hash.Sum32())
|
||||
item := &memcache.Item{
|
||||
Key: fi.Key,
|
||||
Value: buffer.Bytes(),
|
||||
}
|
||||
context := appengine.NewContext(r)
|
||||
err = memcache.Set(context, item)
|
||||
check(err)
|
||||
fi.createThumb(&buffer, context)
|
||||
fi.CreateUrls(r, context)
|
||||
return
|
||||
}
|
||||
|
||||
func getFormValue(p *multipart.Part) string {
|
||||
var b bytes.Buffer
|
||||
io.CopyN(&b, p, int64(1<<20)) // Copy max: 1 MiB
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func handleUploads(r *http.Request) (fileInfos []*FileInfo) {
|
||||
fileInfos = make([]*FileInfo, 0)
|
||||
mr, err := r.MultipartReader()
|
||||
check(err)
|
||||
r.Form, err = url.ParseQuery(r.URL.RawQuery)
|
||||
check(err)
|
||||
part, err := mr.NextPart()
|
||||
for err == nil {
|
||||
if name := part.FormName(); name != "" {
|
||||
if part.FileName() != "" {
|
||||
fileInfos = append(fileInfos, handleUpload(r, part))
|
||||
} else {
|
||||
r.Form[name] = append(r.Form[name], getFormValue(part))
|
||||
}
|
||||
}
|
||||
part, err = mr.NextPart()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func validateRedirect(r *http.Request, redirect string) bool {
|
||||
if redirect != "" {
|
||||
var redirectAllowTarget *regexp.Regexp
|
||||
if REDIRECT_ALLOW_TARGET != "" {
|
||||
redirectAllowTarget = regexp.MustCompile(REDIRECT_ALLOW_TARGET)
|
||||
} else {
|
||||
referer := r.Referer()
|
||||
if referer == "" {
|
||||
return false
|
||||
}
|
||||
refererUrl, err := url.Parse(referer)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
redirectAllowTarget = regexp.MustCompile("^" + regexp.QuoteMeta(
|
||||
refererUrl.Scheme+"://"+refererUrl.Host+"/",
|
||||
))
|
||||
}
|
||||
return redirectAllowTarget.MatchString(redirect)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func get(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/" {
|
||||
http.Redirect(w, r, WEBSITE, http.StatusFound)
|
||||
return
|
||||
}
|
||||
// Use RequestURI instead of r.URL.Path, as we need the encoded form:
|
||||
key := extractKey(r)
|
||||
parts := strings.Split(key, "/")
|
||||
if len(parts) == 3 {
|
||||
context := appengine.NewContext(r)
|
||||
item, err := memcache.Get(context, key)
|
||||
if err == nil {
|
||||
w.Header().Add("X-Content-Type-Options", "nosniff")
|
||||
contentType, _ := url.QueryUnescape(parts[0])
|
||||
if !imageTypes.MatchString(contentType) {
|
||||
contentType = "application/octet-stream"
|
||||
}
|
||||
w.Header().Add("Content-Type", contentType)
|
||||
w.Header().Add(
|
||||
"Cache-Control",
|
||||
fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME),
|
||||
)
|
||||
w.Write(item.Value)
|
||||
return
|
||||
}
|
||||
}
|
||||
http.Error(w, "404 Not Found", http.StatusNotFound)
|
||||
}
|
||||
|
||||
func post(w http.ResponseWriter, r *http.Request) {
|
||||
result := make(map[string][]*FileInfo, 1)
|
||||
result["files"] = handleUploads(r)
|
||||
b, err := json.Marshal(result)
|
||||
check(err)
|
||||
if redirect := r.FormValue("redirect"); validateRedirect(r, redirect) {
|
||||
if strings.Contains(redirect, "%s") {
|
||||
redirect = fmt.Sprintf(
|
||||
redirect,
|
||||
escape(string(b)),
|
||||
)
|
||||
}
|
||||
http.Redirect(w, r, redirect, http.StatusFound)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
jsonType := "application/json"
|
||||
if strings.Index(r.Header.Get("Accept"), jsonType) != -1 {
|
||||
w.Header().Set("Content-Type", jsonType)
|
||||
}
|
||||
fmt.Fprintln(w, string(b))
|
||||
}
|
||||
|
||||
func delete(w http.ResponseWriter, r *http.Request) {
|
||||
key := extractKey(r)
|
||||
parts := strings.Split(key, "/")
|
||||
if len(parts) == 3 {
|
||||
result := make(map[string]bool, 1)
|
||||
context := appengine.NewContext(r)
|
||||
err := memcache.Delete(context, key)
|
||||
if err == nil {
|
||||
result[key] = true
|
||||
contentType, _ := url.QueryUnescape(parts[0])
|
||||
if imageTypes.MatchString(contentType) {
|
||||
thumbnailKey := key + thumbSuffix + filepath.Ext(parts[2])
|
||||
err := memcache.Delete(context, thumbnailKey)
|
||||
if err == nil {
|
||||
result[thumbnailKey] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
b, err := json.Marshal(result)
|
||||
check(err)
|
||||
fmt.Fprintln(w, string(b))
|
||||
} else {
|
||||
http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func handle(w http.ResponseWriter, r *http.Request) {
|
||||
params, err := url.ParseQuery(r.URL.RawQuery)
|
||||
check(err)
|
||||
w.Header().Add("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Add(
|
||||
"Access-Control-Allow-Methods",
|
||||
"OPTIONS, HEAD, GET, POST, DELETE",
|
||||
)
|
||||
w.Header().Add(
|
||||
"Access-Control-Allow-Headers",
|
||||
"Content-Type, Content-Range, Content-Disposition",
|
||||
)
|
||||
switch r.Method {
|
||||
case "OPTIONS", "HEAD":
|
||||
return
|
||||
case "GET":
|
||||
get(w, r)
|
||||
case "POST":
|
||||
if len(params["_method"]) > 0 && params["_method"][0] == "DELETE" {
|
||||
delete(w, r)
|
||||
} else {
|
||||
post(w, r)
|
||||
}
|
||||
case "DELETE":
|
||||
delete(w, r)
|
||||
default:
|
||||
http.Error(w, "501 Not Implemented", http.StatusNotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
http.HandleFunc("/", handle)
|
||||
}
|
BIN
public/file_uploader/server/gae-go/static/favicon.ico
Executable file
After Width: | Height: | Size: 1.1 KiB |
2
public/file_uploader/server/gae-go/static/robots.txt
Executable file
|
@ -0,0 +1,2 @@
|
|||
User-agent: *
|
||||
Disallow:
|
17
public/file_uploader/server/gae-python/app.yaml
Executable file
|
@ -0,0 +1,17 @@
|
|||
application: jquery-file-upload
|
||||
version: 1
|
||||
runtime: python27
|
||||
api_version: 1
|
||||
threadsafe: true
|
||||
|
||||
libraries:
|
||||
- name: PIL
|
||||
version: latest
|
||||
|
||||
handlers:
|
||||
- url: /(favicon\.ico|robots\.txt)
|
||||
static_files: static/\1
|
||||
upload: static/(.*)
|
||||
expiration: '1d'
|
||||
- url: /.*
|
||||
script: main.app
|
204
public/file_uploader/server/gae-python/main.py
Executable file
|
@ -0,0 +1,204 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# jQuery File Upload Plugin GAE Python Example
|
||||
# https://github.com/blueimp/jQuery-File-Upload
|
||||
#
|
||||
# Copyright 2011, Sebastian Tschan
|
||||
# https://blueimp.net
|
||||
#
|
||||
# Licensed under the MIT license:
|
||||
# https://opensource.org/licenses/MIT
|
||||
#
|
||||
|
||||
from google.appengine.api import memcache, images
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import urllib
|
||||
import webapp2
|
||||
|
||||
DEBUG=os.environ.get('SERVER_SOFTWARE', '').startswith('Dev')
|
||||
WEBSITE = 'https://blueimp.github.io/jQuery-File-Upload/'
|
||||
MIN_FILE_SIZE = 1 # bytes
|
||||
# Max file size is memcache limit (1MB) minus key size minus overhead:
|
||||
MAX_FILE_SIZE = 999000 # bytes
|
||||
IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)')
|
||||
ACCEPT_FILE_TYPES = IMAGE_TYPES
|
||||
THUMB_MAX_WIDTH = 80
|
||||
THUMB_MAX_HEIGHT = 80
|
||||
THUMB_SUFFIX = '.'+str(THUMB_MAX_WIDTH)+'x'+str(THUMB_MAX_HEIGHT)+'.png'
|
||||
EXPIRATION_TIME = 300 # seconds
|
||||
# If set to None, only allow redirects to the referer protocol+host.
|
||||
# Set to a regexp for custom pattern matching against the redirect value:
|
||||
REDIRECT_ALLOW_TARGET = None
|
||||
|
||||
class CORSHandler(webapp2.RequestHandler):
|
||||
def cors(self):
|
||||
headers = self.response.headers
|
||||
headers['Access-Control-Allow-Origin'] = '*'
|
||||
headers['Access-Control-Allow-Methods'] =\
|
||||
'OPTIONS, HEAD, GET, POST, DELETE'
|
||||
headers['Access-Control-Allow-Headers'] =\
|
||||
'Content-Type, Content-Range, Content-Disposition'
|
||||
|
||||
def initialize(self, request, response):
|
||||
super(CORSHandler, self).initialize(request, response)
|
||||
self.cors()
|
||||
|
||||
def json_stringify(self, obj):
|
||||
return json.dumps(obj, separators=(',', ':'))
|
||||
|
||||
def options(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
class UploadHandler(CORSHandler):
|
||||
def validate(self, file):
|
||||
if file['size'] < MIN_FILE_SIZE:
|
||||
file['error'] = 'File is too small'
|
||||
elif file['size'] > MAX_FILE_SIZE:
|
||||
file['error'] = 'File is too big'
|
||||
elif not ACCEPT_FILE_TYPES.match(file['type']):
|
||||
file['error'] = 'Filetype not allowed'
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
|
||||
def validate_redirect(self, redirect):
|
||||
if redirect:
|
||||
if REDIRECT_ALLOW_TARGET:
|
||||
return REDIRECT_ALLOW_TARGET.match(redirect)
|
||||
referer = self.request.headers['referer']
|
||||
if referer:
|
||||
from urlparse import urlparse
|
||||
parts = urlparse(referer)
|
||||
redirect_allow_target = '^' + re.escape(
|
||||
parts.scheme + '://' + parts.netloc + '/'
|
||||
)
|
||||
return re.match(redirect_allow_target, redirect)
|
||||
return False
|
||||
|
||||
def get_file_size(self, file):
|
||||
file.seek(0, 2) # Seek to the end of the file
|
||||
size = file.tell() # Get the position of EOF
|
||||
file.seek(0) # Reset the file position to the beginning
|
||||
return size
|
||||
|
||||
def write_blob(self, data, info):
|
||||
key = urllib.quote(info['type'].encode('utf-8'), '') +\
|
||||
'/' + str(hash(data)) +\
|
||||
'/' + urllib.quote(info['name'].encode('utf-8'), '')
|
||||
try:
|
||||
memcache.set(key, data, time=EXPIRATION_TIME)
|
||||
except: #Failed to add to memcache
|
||||
return (None, None)
|
||||
thumbnail_key = None
|
||||
if IMAGE_TYPES.match(info['type']):
|
||||
try:
|
||||
img = images.Image(image_data=data)
|
||||
img.resize(
|
||||
width=THUMB_MAX_WIDTH,
|
||||
height=THUMB_MAX_HEIGHT
|
||||
)
|
||||
thumbnail_data = img.execute_transforms()
|
||||
thumbnail_key = key + THUMB_SUFFIX
|
||||
memcache.set(
|
||||
thumbnail_key,
|
||||
thumbnail_data,
|
||||
time=EXPIRATION_TIME
|
||||
)
|
||||
except: #Failed to resize Image or add to memcache
|
||||
thumbnail_key = None
|
||||
return (key, thumbnail_key)
|
||||
|
||||
def handle_upload(self):
|
||||
results = []
|
||||
for name, fieldStorage in self.request.POST.items():
|
||||
if type(fieldStorage) is unicode:
|
||||
continue
|
||||
result = {}
|
||||
result['name'] = urllib.unquote(fieldStorage.filename)
|
||||
result['type'] = fieldStorage.type
|
||||
result['size'] = self.get_file_size(fieldStorage.file)
|
||||
if self.validate(result):
|
||||
key, thumbnail_key = self.write_blob(
|
||||
fieldStorage.value,
|
||||
result
|
||||
)
|
||||
if key is not None:
|
||||
result['url'] = self.request.host_url + '/' + key
|
||||
result['deleteUrl'] = result['url']
|
||||
result['deleteType'] = 'DELETE'
|
||||
if thumbnail_key is not None:
|
||||
result['thumbnailUrl'] = self.request.host_url +\
|
||||
'/' + thumbnail_key
|
||||
else:
|
||||
result['error'] = 'Failed to store uploaded file.'
|
||||
results.append(result)
|
||||
return results
|
||||
|
||||
def head(self):
|
||||
pass
|
||||
|
||||
def get(self):
|
||||
self.redirect(WEBSITE)
|
||||
|
||||
def post(self):
|
||||
if (self.request.get('_method') == 'DELETE'):
|
||||
return self.delete()
|
||||
result = {'files': self.handle_upload()}
|
||||
s = self.json_stringify(result)
|
||||
redirect = self.request.get('redirect')
|
||||
if self.validate_redirect(redirect):
|
||||
return self.redirect(str(
|
||||
redirect.replace('%s', urllib.quote(s, ''), 1)
|
||||
))
|
||||
if 'application/json' in self.request.headers.get('Accept'):
|
||||
self.response.headers['Content-Type'] = 'application/json'
|
||||
self.response.write(s)
|
||||
|
||||
class FileHandler(CORSHandler):
|
||||
def normalize(self, str):
|
||||
return urllib.quote(urllib.unquote(str), '')
|
||||
|
||||
def get(self, content_type, data_hash, file_name):
|
||||
content_type = self.normalize(content_type)
|
||||
file_name = self.normalize(file_name)
|
||||
key = content_type + '/' + data_hash + '/' + file_name
|
||||
data = memcache.get(key)
|
||||
if data is None:
|
||||
return self.error(404)
|
||||
# Prevent browsers from MIME-sniffing the content-type:
|
||||
self.response.headers['X-Content-Type-Options'] = 'nosniff'
|
||||
content_type = urllib.unquote(content_type)
|
||||
if not IMAGE_TYPES.match(content_type):
|
||||
# Force a download dialog for non-image types:
|
||||
content_type = 'application/octet-stream'
|
||||
elif file_name.endswith(THUMB_SUFFIX):
|
||||
content_type = 'image/png'
|
||||
self.response.headers['Content-Type'] = content_type
|
||||
# Cache for the expiration time:
|
||||
self.response.headers['Cache-Control'] = 'public,max-age=%d' \
|
||||
% EXPIRATION_TIME
|
||||
self.response.write(data)
|
||||
|
||||
def delete(self, content_type, data_hash, file_name):
|
||||
content_type = self.normalize(content_type)
|
||||
file_name = self.normalize(file_name)
|
||||
key = content_type + '/' + data_hash + '/' + file_name
|
||||
result = {key: memcache.delete(key)}
|
||||
content_type = urllib.unquote(content_type)
|
||||
if IMAGE_TYPES.match(content_type):
|
||||
thumbnail_key = key + THUMB_SUFFIX
|
||||
result[thumbnail_key] = memcache.delete(thumbnail_key)
|
||||
if 'application/json' in self.request.headers.get('Accept'):
|
||||
self.response.headers['Content-Type'] = 'application/json'
|
||||
s = self.json_stringify(result)
|
||||
self.response.write(s)
|
||||
|
||||
app = webapp2.WSGIApplication(
|
||||
[
|
||||
('/', UploadHandler),
|
||||
('/(.+)/([^/]+)/([^/]+)', FileHandler)
|
||||
],
|
||||
debug=DEBUG
|
||||
)
|
BIN
public/file_uploader/server/gae-python/static/favicon.ico
Executable file
After Width: | Height: | Size: 1.1 KiB |
2
public/file_uploader/server/gae-python/static/robots.txt
Executable file
|
@ -0,0 +1,2 @@
|
|||
User-agent: *
|
||||
Disallow:
|
38
public/file_uploader/server/php/Dockerfile
Executable file
|
@ -0,0 +1,38 @@
|
|||
FROM php:7.0-apache
|
||||
|
||||
# Enable the Apache Headers module:
|
||||
RUN ln -s /etc/apache2/mods-available/headers.load \
|
||||
/etc/apache2/mods-enabled/headers.load
|
||||
|
||||
# Enable the Apache Rewrite module:
|
||||
RUN ln -s /etc/apache2/mods-available/rewrite.load \
|
||||
/etc/apache2/mods-enabled/rewrite.load
|
||||
|
||||
# Install GD, Imagick and ImageMagick as image conversion options:
|
||||
RUN DEBIAN_FRONTEND=noninteractive \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
libpng-dev \
|
||||
libjpeg-dev \
|
||||
libmagickwand-dev \
|
||||
imagemagick \
|
||||
&& pecl install \
|
||||
imagick \
|
||||
&& docker-php-ext-enable \
|
||||
imagick \
|
||||
&& docker-php-ext-configure \
|
||||
gd --with-jpeg-dir=/usr/include/ \
|
||||
&& docker-php-ext-install \
|
||||
gd \
|
||||
# Uninstall obsolete packages:
|
||||
&& apt-get autoremove -y \
|
||||
libpng-dev \
|
||||
libjpeg-dev \
|
||||
libmagickwand-dev \
|
||||
# Remove obsolete files:
|
||||
&& apt-get clean \
|
||||
&& rm -rf \
|
||||
/tmp/* \
|
||||
/usr/share/doc/* \
|
||||
/var/cache/* \
|
||||
/var/lib/apt/lists/* \
|
||||
/var/tmp/*
|
1393
public/file_uploader/server/php/UploadHandler.php
Executable file
6
public/file_uploader/server/php/docker-compose.yml
Executable file
|
@ -0,0 +1,6 @@
|
|||
apache:
|
||||
build: ./
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- "../../:/var/www/html"
|
3
public/file_uploader/server/php/files/.gitignore
vendored
Executable file
|
@ -0,0 +1,3 @@
|
|||
*
|
||||
!.gitignore
|
||||
!.htaccess
|
26
public/file_uploader/server/php/files/.htaccess
Executable file
|
@ -0,0 +1,26 @@
|
|||
# To enable the Headers module, execute the following command and reload Apache:
|
||||
# sudo a2enmod headers
|
||||
|
||||
# The following directives prevent the execution of script files
|
||||
# in the context of the website.
|
||||
# They also force the content-type application/octet-stream and
|
||||
# force browsers to display a download dialog for non-image files.
|
||||
SetHandler default-handler
|
||||
ForceType application/octet-stream
|
||||
Header set Content-Disposition attachment
|
||||
|
||||
# The following unsets the forced type and Content-Disposition headers
|
||||
# for known image files:
|
||||
<FilesMatch "(?i)\.(gif|jpe?g|png)$">
|
||||
ForceType none
|
||||
Header unset Content-Disposition
|
||||
</FilesMatch>
|
||||
|
||||
# The following directive prevents browsers from MIME-sniffing the content-type.
|
||||
# This is an important complement to the ForceType directive above:
|
||||
Header set X-Content-Type-Options nosniff
|
||||
|
||||
# Uncomment the following lines to prevent unauthorized download of files:
|
||||
#AuthName "Authorization required"
|
||||
#AuthType Basic
|
||||
#require valid-user
|
15
public/file_uploader/server/php/index.php
Executable file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
/*
|
||||
* jQuery File Upload Plugin PHP Example
|
||||
* https://github.com/blueimp/jQuery-File-Upload
|
||||
*
|
||||
* Copyright 2010, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
require('UploadHandler.php');
|
||||
$upload_handler = new UploadHandler();
|
172
public/file_uploader/test/index.html
Executable file
|
@ -0,0 +1,172 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
/*
|
||||
* jQuery File Upload Plugin Test
|
||||
* https://github.com/blueimp/jQuery-File-Upload
|
||||
*
|
||||
* Copyright 2010, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Force latest IE rendering engine or ChromeFrame if installed -->
|
||||
<!--[if IE]>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<![endif]-->
|
||||
<meta charset="utf-8">
|
||||
<title>jQuery File Upload Plugin Test</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="//codeorigin.jquery.com/qunit/qunit-1.14.0.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">jQuery File Upload Plugin Test</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<div id="qunit-testrunner-toolbar"></div>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="qunit-fixture">
|
||||
<!-- The file upload form used as target for the file upload widget -->
|
||||
<form id="fileupload" action="../server/php/" method="POST" enctype="multipart/form-data">
|
||||
<!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
|
||||
<div class="row fileupload-buttonbar">
|
||||
<div class="col-lg-7">
|
||||
<!-- The fileinput-button span is used to style the file input field as button -->
|
||||
<span class="btn btn-success fileinput-button">
|
||||
<i class="icon-plus icon-white"></i>
|
||||
<span>Add files...</span>
|
||||
<input type="file" name="files[]" multiple>
|
||||
</span>
|
||||
<button type="submit" class="btn btn-primary start">
|
||||
<i class="icon-upload icon-white"></i>
|
||||
<span>Start upload</span>
|
||||
</button>
|
||||
<button type="reset" class="btn btn-warning cancel">
|
||||
<i class="icon-ban-circle icon-white"></i>
|
||||
<span>Cancel upload</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger delete">
|
||||
<i class="icon-trash icon-white"></i>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
<input type="checkbox" class="toggle">
|
||||
<!-- The global file processing state -->
|
||||
<span class="fileupload-process"></span>
|
||||
</div>
|
||||
<!-- The global progress state -->
|
||||
<div class="col-lg-5 fileupload-progress">
|
||||
<!-- The global progress bar -->
|
||||
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100">
|
||||
<div class="progress-bar progress-bar-success" style="width:0%;"></div>
|
||||
</div>
|
||||
<!-- The extended global progress state -->
|
||||
<div class="progress-extended"> </div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- The table listing the files available for upload/download -->
|
||||
<table role="presentation" class="table table-striped"><tbody class="files"></tbody></table>
|
||||
</form>
|
||||
</div>
|
||||
<!-- The template to display files available for upload -->
|
||||
<script id="template-upload" type="text/x-tmpl">
|
||||
{% for (var i=0, file; file=o.files[i]; i++) { %}
|
||||
<tr class="template-upload">
|
||||
<td>
|
||||
<span class="preview"></span>
|
||||
</td>
|
||||
<td>
|
||||
<p class="name">{%=file.name%}</p>
|
||||
<strong class="error text-danger"></strong>
|
||||
</td>
|
||||
<td>
|
||||
<p class="size">Processing...</p>
|
||||
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="progress-bar progress-bar-success" style="width:0%;"></div></div>
|
||||
</td>
|
||||
<td>
|
||||
{% if (!i && !o.options.autoUpload) { %}
|
||||
<button class="btn btn-primary start" disabled>
|
||||
<i class="glyphicon glyphicon-upload"></i>
|
||||
<span>Start</span>
|
||||
</button>
|
||||
{% } %}
|
||||
{% if (!i) { %}
|
||||
<button class="btn btn-warning cancel">
|
||||
<i class="glyphicon glyphicon-ban-circle"></i>
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
{% } %}
|
||||
</td>
|
||||
</tr>
|
||||
{% } %}
|
||||
</script>
|
||||
<!-- The template to display files available for download -->
|
||||
<script id="template-download" type="text/x-tmpl">
|
||||
{% for (var i=0, file; file=o.files[i]; i++) { %}
|
||||
<tr class="template-download">
|
||||
<td>
|
||||
<span class="preview">
|
||||
{% if (file.thumbnailUrl) { %}
|
||||
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a>
|
||||
{% } %}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<p class="name">
|
||||
{% if (file.url) { %}
|
||||
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a>
|
||||
{% } else { %}
|
||||
<span>{%=file.name%}</span>
|
||||
{% } %}
|
||||
</p>
|
||||
{% if (file.error) { %}
|
||||
<div><span class="label label-danger">Error</span> {%=file.error%}</div>
|
||||
{% } %}
|
||||
</td>
|
||||
<td>
|
||||
<span class="size">{%=o.formatFileSize(file.size)%}</span>
|
||||
</td>
|
||||
<td>
|
||||
{% if (file.deleteUrl) { %}
|
||||
<button class="btn btn-danger delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>
|
||||
<i class="glyphicon glyphicon-trash"></i>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
<input type="checkbox" name="delete" value="1" class="toggle">
|
||||
{% } else { %}
|
||||
<button class="btn btn-warning cancel">
|
||||
<i class="glyphicon glyphicon-ban-circle"></i>
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
{% } %}
|
||||
</td>
|
||||
</tr>
|
||||
{% } %}
|
||||
</script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
|
||||
<script src="../js/vendor/jquery.ui.widget.js"></script>
|
||||
<script src="//blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
|
||||
<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
|
||||
<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
|
||||
<script src="../js/jquery.iframe-transport.js"></script>
|
||||
<script src="../js/jquery.fileupload.js"></script>
|
||||
<script>
|
||||
/* global window, $ */
|
||||
window.testBasicWidget = $.blueimp.fileupload;
|
||||
</script>
|
||||
<script src="../js/jquery.fileupload-process.js"></script>
|
||||
<script src="../js/jquery.fileupload-image.js"></script>
|
||||
<script src="../js/jquery.fileupload-audio.js"></script>
|
||||
<script src="../js/jquery.fileupload-video.js"></script>
|
||||
<script src="../js/jquery.fileupload-validate.js"></script>
|
||||
<script src="../js/jquery.fileupload-ui.js"></script>
|
||||
<script>
|
||||
/* global window, $ */
|
||||
window.testUIWidget = $.blueimp.fileupload;
|
||||
</script>
|
||||
<script src="//code.jquery.com/qunit/qunit-1.15.0.js"></script>
|
||||
<script src="test.js"></script>
|
||||
</body>
|
||||
</html>
|
1292
public/file_uploader/test/test.js
Executable file
Before Width: | Height: | Size: 600 B After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 416 B |
|
@ -2,6 +2,16 @@
|
|||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE images ADD COLUMN original_filename TEXT NOT NULL DEFAULT "Unknown";
|
||||
CREATE TABLE images (
|
||||
file_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
owner_id INTEGER NOT NULL,
|
||||
file_name TEXT NOT NULL,
|
||||
created_time DATETIME NOT NULL
|
||||
DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (
|
||||
owner_id
|
||||
)
|
||||
REFERENCES users (user_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
-- Deploy fotostore:images to sqlite
|
||||
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE images (
|
||||
file_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
owner_id INTEGER NOT NULL,
|
||||
file_name TEXT NOT NULL,
|
||||
created_time DATETIME NOT NULL
|
||||
DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (
|
||||
owner_id
|
||||
)
|
||||
REFERENCES users (user_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
COMMIT;
|
|
@ -1,40 +1,7 @@
|
|||
-- Deploy fotostore:images to sqlite
|
||||
-- Revert fotostore:images from sqlite
|
||||
|
||||
BEGIN;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
CREATE TABLE images_rever_temp_table AS SELECT *
|
||||
FROM images;
|
||||
|
||||
DROP TABLE images;
|
||||
|
||||
CREATE TABLE images (
|
||||
file_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
owner_id INTEGER NOT NULL,
|
||||
file_name TEXT NOT NULL,
|
||||
created_time DATETIME NOT NULL
|
||||
DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (
|
||||
owner_id
|
||||
)
|
||||
REFERENCES users (user_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
INSERT INTO images (
|
||||
file_id,
|
||||
owner_id,
|
||||
file_name,
|
||||
created_time
|
||||
)
|
||||
SELECT file_id,
|
||||
owner_id,
|
||||
file_name,
|
||||
created_time
|
||||
FROM images_rever_temp_table;
|
||||
|
||||
DROP TABLE images_rever_temp_table;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
COMMIT;
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
-- Revert fotostore:images from sqlite
|
||||
|
||||
BEGIN;
|
||||
|
||||
DROP TABLE images;
|
||||
|
||||
COMMIT;
|
|
@ -8,6 +8,3 @@ albums 2017-07-22T08:50:11Z Denis Fedoseev <denis.fedoseev@gmail.com> # Albums d
|
|||
user_images [users images] 2017-07-22T09:16:20Z Denis Fedoseev <denis.fedoseev@gmail.com> # +user_images table
|
||||
album_images [images albums] 2017-07-22T09:21:13Z Denis Fedoseev <denis.fedoseev@gmail.com> # +images to album mapping
|
||||
user_albums [users albums] 2017-07-22T09:47:48Z Denis Fedoseev <denis.fedoseev@gmail.com> # Albums to users mapping
|
||||
@v1.0.0 2017-08-02T03:46:51Z Denis Fedoseev <denis.fedoseev@gmail.com> # Tag v1.0.0.
|
||||
images [images@v1.0.0] 2017-08-02T03:55:08Z Denis Fedoseev <denis.fedoseev@gmail.com> # Adds images.original_filename.
|
||||
@v1.1.0 2017-08-02T04:46:42Z Denis Fedoseev <denis.fedoseev@gmail.com> # Tag v1.1.0.
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
BEGIN;
|
||||
|
||||
select file_id, owner_id, file_name, original_filename, created_time from images where 0;
|
||||
select file_id, owner_id, file_name, created_time from images where 0;
|
||||
|
||||
ROLLBACK;
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
-- Verify fotostore:images on sqlite
|
||||
|
||||
BEGIN;
|
||||
|
||||
select file_id, owner_id, file_name, created_time from images where 0;
|
||||
|
||||
ROLLBACK;
|
|
@ -1,5 +1,5 @@
|
|||
<div class="container upload-form" id="upload-form">
|
||||
|
||||
<div class="container">
|
||||
<div class"upload-form">
|
||||
<input id="fileupload" type="file" name="image" data-url="/upload" multiple>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||
<script src="/file_uploader/js/vendor/jquery.ui.widget.js"></script>
|
||||
|
@ -17,7 +17,7 @@
|
|||
sequentialUploads: true,
|
||||
progressall: function (e, data) {
|
||||
var progress = parseInt(data.loaded / data.total * 100, 10);
|
||||
$('#progress .progress-bar').css(
|
||||
$('#progress .bar').css(
|
||||
'width',
|
||||
progress + '%'
|
||||
);
|
||||
|
@ -26,10 +26,11 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<div id="progress" class="container">
|
||||
<div class="progress-bar" style="width: 0%;"></div>
|
||||
</div>
|
||||
<div id="lastUploadLog" class="container"></div>
|
||||
<div id="progress">
|
||||
<div class="bar" style="width: 0%;"></div>
|
||||
</div>
|
||||
<div id="lastUploadLog"></div>
|
||||
</div>
|
||||
|
||||
<!-- display images from server -->
|
||||
|
@ -37,50 +38,18 @@
|
|||
<div id="images_list">
|
||||
<div class="foto-block row" v-for="image in imagesList">
|
||||
<div class="image col-md-3">
|
||||
<img v-bind:src="image.thumbnail_url">
|
||||
<div class="image_title">
|
||||
{{ image.filename }}
|
||||
</div>
|
||||
<img v-bind:src="image.thumbnail_url">
|
||||
</div>
|
||||
<div class="foto-notes col-md-3">
|
||||
<div class="image-scale image-original">
|
||||
<div class="image-scale-url">
|
||||
<a v-bind:href="image.original_url">Original</a>
|
||||
</div>
|
||||
<div @click="copyText" class="copy-img">
|
||||
<img src={{ hostname+image.original_url }}>
|
||||
</div>
|
||||
<div @click="copyText" class="copy-bb-more">
|
||||
[MORE=<img src={{ hostname+image.thumbnail_url }}>]<img src={{ hostname+image.original_url }}>[/MORE]
|
||||
</div>
|
||||
</div>
|
||||
<div class="image-scale" v-for="scale in image.scales">
|
||||
<div class="image-scale-url">
|
||||
<a v-bind:href="scale.url">{{ scale.size }}</a>
|
||||
</div>
|
||||
<div @click="copyText" class="copy-img">
|
||||
<img src={{ hostname+scale.url }}>
|
||||
</div>
|
||||
<div @click="copyText" class="copy-bb-more">
|
||||
[MORE=<img src={{ hostname+image.thumbnail_url }}>]<img src={{ hostname+scale.url }}>[/MORE]
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container paginator">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default">Prev</button>
|
||||
<button type="button" class="btn btn-default" v-for="pageNumber in pagesCount" v-on:click="fetchData(pageNumber)">{{ pageNumber }}</button>
|
||||
<button type="button" class="btn btn-default">Next</button>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="items-per-page-form">Fotos per page: <input v-model="imagesPerPage">
|
||||
<button type="button" class="btn btn-default" v-on:click="fetchData()">Update</button>
|
||||
</div>
|
||||
<ul>
|
||||
<li><a v-bind:href="image.original_url">Original</a> <div @click="copyText" class="copy-img">{{ hostname+image.original_url }}</div></li>
|
||||
<li v-for="scale in image.scales">
|
||||
<a v-bind:href="scale.url">{{ scale.size }}</a> <div @click="copyText" class="copy-img">{{ hostname+scale.url }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
@ -90,39 +59,34 @@
|
|||
var demo = new Vue({
|
||||
|
||||
el: '#images_list',
|
||||
|
||||
data: {
|
||||
imagesList: null,
|
||||
pageNumber: 1,
|
||||
pagesCount: 5,
|
||||
imagesPerPage: 20,
|
||||
imagesList: null
|
||||
},
|
||||
|
||||
created: function () {
|
||||
this.fetchData(this.pageNumber)
|
||||
this.fetchData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
fetchData: function (pageNumber) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
var self = this
|
||||
xhr.open('GET', apiURL+"?page="+pageNumber+"&per-page="+self.imagesPerPage)
|
||||
xhr.onload = function () {
|
||||
var result = JSON.parse(xhr.responseText);
|
||||
self.imagesList = result.images_list;
|
||||
console.dir(self.imagesList);
|
||||
self.pagesCount = result.pages_count;
|
||||
}
|
||||
xhr.send()
|
||||
fetchData: function () {
|
||||
var xhr = new XMLHttpRequest()
|
||||
var self = this
|
||||
xhr.open('GET', apiURL)
|
||||
xhr.onload = function () {
|
||||
self.imagesList = JSON.parse(xhr.responseText)
|
||||
}
|
||||
xhr.send()
|
||||
},
|
||||
copyText(event) {
|
||||
//TODO: rewrite it to vue or pure JS from jQuery
|
||||
//TODO: rewrite it to vue/JS from jquery
|
||||
var $temp = $("<input>");
|
||||
$("body").append($temp);
|
||||
$temp.val($(event.target).text().trim()).select();
|
||||
$temp.val("<img src="+$(event.target).text()+">").select();
|
||||
document.execCommand("copy");
|
||||
$temp.remove();
|
||||
},
|
||||
}
|
||||
|
||||
});
|
||||
})
|
||||
</script>
|
|
@ -15,6 +15,13 @@
|
|||
<link rel="stylesheet" href="/css/main.css">
|
||||
|
||||
<script src="https://vuejs.org/js/vue.min.js"></script>
|
||||
|
||||
<style>
|
||||
.bar {
|
||||
height: 18px;
|
||||
background: green;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
|
|