Compare commits

...

27 commits

Author SHA1 Message Date
Denis Fedoseev
140a179a8b Merge branch 'master' of github.com:alpha6/fotostore 2018-09-09 16:43:19 +03:00
Denis Fedoseev
156274c109 upload progress and icons were fixed 2018-08-03 23:19:35 +03:00
Denis Fedoseev
7eaa376126 mojo version 2018-08-03 11:00:52 +03:00
Denis Fedoseev
d4a1f99b71 small cleanup 2018-08-01 10:18:24 +03:00
Denis Fedoseev
87ad4111a8 spawn subprocess with promise 2018-08-01 10:11:43 +03:00
Denis Fedoseev
a774698d6e process image in subprocess 2018-08-01 09:14:41 +03:00
Denis Fedoseev
35e03f7bad image processing was moved to sub 2018-07-31 09:17:32 +03:00
Denis Fedoseev
b165b10826 file uploader was updated 2018-07-31 09:16:52 +03:00
Denis Fedoseev
a98302199a Forgot to commit db deployment scripts 2017-08-04 22:52:53 +03:00
Denis Fedoseev
fc97a8cc17 Merge pull request #10 from alpha6/fix_upload_form_style
Style of upload form was fixed
2017-08-04 10:24:50 +03:00
Denis Fedoseev
0e9cbf3b3f Style of upload form was fixed 2017-08-04 10:23:50 +03:00
Denis Fedoseev
b5a554e6a1 Merge pull request #9 from alpha6/pagination
Pagination
2017-08-04 10:01:34 +03:00
Denis Fedoseev
d2d31fd8c3 Merge branch 'master' into pagination 2017-08-04 10:00:22 +03:00
Denis Fedoseev
1205e3539d Pagination mostly works 2017-08-04 09:57:17 +03:00
Denis Fedoseev
d8a2c09ea0 Merge pull request #8 from alpha6/trim_sting_to_copy
trim string in clipboard
2017-08-03 09:11:04 +03:00
Denis Fedoseev
1e8ea69ee1 trim string in clipboard 2017-08-03 09:10:23 +03:00
Denis Fedoseev
ba5a95a165 more icon ico -> png 2017-08-03 09:05:28 +03:00
Denis Fedoseev
d3a30f0c9d Merge pull request #7 from alpha6/more_bb_tag
BB tag more with images
2017-08-03 08:48:49 +03:00
Denis Fedoseev
f71587fa3a BB tag more with images 2017-08-03 08:47:39 +03:00
Denis Fedoseev
5012d8f123 Merge pull request #6 from alpha6/check_scale_exists
Check scale exists
2017-08-02 17:36:43 +03:00
Denis Fedoseev
bac83221aa tidy 2017-08-02 17:30:44 +03:00
Denis Fedoseev
bbe0ff81b0 Image sizes were moved to config.
Skip sizes which more than original image size.
2017-08-02 17:29:04 +03:00
Denis Fedoseev
0aa42552f8 Unused code was removed 2017-08-02 09:28:01 +03:00
Denis Fedoseev
f6e73d1c17 Merge pull request #5 from alpha6/original_fn_field
Original fn field
2017-08-02 07:57:09 +03:00
Denis Fedoseev
066ab0197c Show original filename in web 2017-08-02 07:55:54 +03:00
Denis Fedoseev
5d4a0fd63f Field original_filename was added to database 2017-08-02 07:46:54 +03:00
Denis Fedoseev
8b70364c14 Merge pull request #4 from alpha6/copy_img_tag
Copy img tag
2017-08-01 21:07:10 +03:00
72 changed files with 1068 additions and 5747 deletions

View file

@ -1,4 +1,11 @@
{
db_file => 'sql/fotostore.db',
invite_code => 'very_secure_invite_code',
thumbnails_size => 200,
image_scales => {
640 => 1,
800 => 1,
1024 => 1,
2048 => 1,
},
}

View file

@ -1,4 +1,4 @@
requires 'Mojolicious';
requires 'Mojolicious', '>= 7.88';
requires 'Mojolicious::Plugin::Authentication';
requires 'Imager';
requires 'File::Basename';

View file

@ -4,11 +4,14 @@ use warnings;
use lib 'lib';
use Mojolicious::Lite; # app, get, post is exported.
use Mojo::Promise;
use Mojo::IOLoop;
use File::Basename 'basename';
use File::Basename qw/basename fileparse/;
use File::Path 'mkpath';
use File::Spec 'catfile';
use Cwd;
use POSIX;
use Imager;
use DBI;
@ -17,7 +20,7 @@ use Digest::SHA;
use FotoStore::DB;
use Data::Dumper;
$Data::Dumper::Maxdepth = 3;
$Data::Dumper::Maxdepth = 2;
my $config = plugin 'Config' => { file => 'application.conf' };
@ -27,16 +30,24 @@ my $db = FotoStore::DB->new( $config->{'db_file'} );
my $IMAGE_BASE = 'images';
my $ORIG_DIR = 'orig';
my $thumbs_size = 200;
# set allowed thumbnails scale and image scales
my $thumbs_size = $config->{'thumbnails_size'};
my @scale_width = ( $thumbs_size, 640, 800, 1024 );
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 $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 {
@ -54,7 +65,6 @@ 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;
},
@ -86,39 +96,44 @@ 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');
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'} ) {
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( text => 'Login failed :(' );
$self->render( template => 'error', message => '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 {
@ -131,35 +146,70 @@ 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'};
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 );
#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}
# 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->{'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->{'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 );
my @scaled = ();
for my $scale (@scale_width) {
push(@scaled, {'size' => $scale, 'url' => File::Spec->catfile( '/', $IMAGE_BASE, $current_user->{'user_id'}, $scale, $file )}) ;
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
)
}
);
}
}
$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 => $images );
return $self->render( json => $reply_data );
};
# Upload image file
@ -170,9 +220,8 @@ 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) {
@ -184,7 +233,11 @@ post '/upload' => ( authenticated => 1 ) => sub {
# Check file type
my $image_type = $image->headers->content_type;
my %valid_types = map { $_ => 1 } qw(image/gif image/jpeg image/png);
my %valid_types = (
'image/gif' => 'gif',
'image/jpeg' => 'jpg',
'image/png' => 'png'
);
# Content type is wrong
unless ( $valid_types{$image_type} ) {
@ -194,65 +247,34 @@ post '/upload' => ( authenticated => 1 ) => sub {
);
}
# Extention
my $exts = {
'image/gif' => 'gif',
'image/jpeg' => 'jpg',
'image/png' => 'png'
};
my $ext = $exts->{$image_type};
my $ext = $valid_types{$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 $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 ),
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 ),
}
]
}
]
}
);
# Redirect to top page
# $self->redirect_to('index');
);
})->wait;
} => 'upload';
@ -264,12 +286,76 @@ 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;

View file

@ -1,5 +1,6 @@
package FotoStore::DB;
use v5.20;
use strict;
use warnings;
@ -51,16 +52,25 @@ sub add_user($self, $username, $password, $fullname) {
}
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));
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));
if ($self->{'dbh'}->errstr) {
die $self->{'dbh'}->errstr;
}
return $rows;
}
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 );
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 };
}
1;

View file

@ -1,15 +1,63 @@
.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 {
content:url(/img/copy_icon.png);
.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);
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;
}

View file

@ -1,3 +0,0 @@
.DS_Store
*.pyc
node_modules

View file

@ -1,81 +0,0 @@
{
"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
}

View file

@ -1,20 +0,0 @@
*
!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

View file

@ -1,15 +0,0 @@
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.

View file

@ -1,20 +0,0 @@
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.

View file

@ -1,107 +0,0 @@
# jQuery File Upload Plugin
## Demo
[Demo File Upload](https://blueimp.github.io/jQuery-File-Upload/)
## Description
File Upload widget with multiple file selection, drag&amp;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).

View file

@ -1,211 +0,0 @@
<!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&amp;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">&copy; 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&amp;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">&nbsp;</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 &amp; 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>

View file

@ -1,226 +0,0 @@
<!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&amp;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">&copy; 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&amp;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 &amp; 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>

View file

@ -1,136 +0,0 @@
<!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&amp;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">&copy; 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&amp;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 &amp; 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>

View file

@ -1,16 +0,0 @@
#!/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'
);

View file

@ -1,64 +0,0 @@
{
"name": "blueimp-file-upload",
"version": "9.18.0",
"title": "jQuery File Upload",
"description": "File Upload widget with multiple file selection, drag&amp;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"
]
}

View file

@ -1,75 +0,0 @@
<!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>

View file

@ -1,24 +0,0 @@
<!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>

View file

View file

0
public/file_uploader/css/jquery.fileupload-ui.css Executable file → Normal file
View file

0
public/file_uploader/css/jquery.fileupload.css Executable file → Normal file
View file

0
public/file_uploader/css/style.css Executable file → Normal file
View file

0
public/file_uploader/img/loading.gif Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

0
public/file_uploader/img/progressbar.gif Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -1,255 +0,0 @@
<!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&amp;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">&copy; 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&amp;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">&nbsp;</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 &amp; 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>

View file

@ -1,250 +0,0 @@
<!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&amp;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">&copy; 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&amp;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">&nbsp;</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 &amp; 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 Executable file → Normal file
View file

View file

0
public/file_uploader/js/cors/jquery.xdr-transport.js Executable file → Normal file
View file

0
public/file_uploader/js/jquery.fileupload-angular.js vendored Executable file → Normal file
View file

0
public/file_uploader/js/jquery.fileupload-audio.js vendored Executable file → Normal file
View file

0
public/file_uploader/js/jquery.fileupload-image.js vendored Executable file → Normal file
View file

0
public/file_uploader/js/jquery.fileupload-jquery-ui.js Executable file → Normal file
View file

0
public/file_uploader/js/jquery.fileupload-process.js vendored Executable file → Normal file
View file

1
public/file_uploader/js/jquery.fileupload-ui.js vendored Executable file → Normal file
View file

@ -30,6 +30,7 @@
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 Executable file → Normal file
View file

0
public/file_uploader/js/jquery.fileupload-video.js vendored Executable file → Normal file
View file

16
public/file_uploader/js/jquery.fileupload.js vendored Executable file → Normal file
View 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.name) + '"';
encodeURI(file.uploadName || file.name) + '"';
}
if (!multipart) {
options.contentType = file.type || 'application/octet-stream';
@ -489,7 +489,11 @@
});
}
if (options.blob) {
formData.append(paramName, options.blob, file.name);
formData.append(
paramName,
options.blob,
file.uploadName || file.name
);
} else {
$.each(options.files, function (index, file) {
// This check allows the tests to run with
@ -730,7 +734,7 @@
promise = dfd.promise(),
jqXHR,
upload;
if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) ||
if (!(this._isXHRUpload(options) && slice && (ub || ($.type(mcs) === 'function' ? mcs(options) : mcs) < fs)) ||
options.data) {
return false;
}
@ -753,7 +757,7 @@
o.blob = slice.call(
file,
ub,
ub + mcs,
ub + ($.type(mcs) === 'function' ? mcs(o) : mcs),
file.type
);
// Store the current chunk size, as the blob itself
@ -1126,7 +1130,7 @@
dirReader = entry.createReader();
readEntries();
} else {
// Return an empy list for file system items
// Return an empty list for file system items
// other than files or directories:
dfd.resolve([]);
}

0
public/file_uploader/js/jquery.iframe-transport.js Executable file → Normal file
View file

0
public/file_uploader/js/main.js Executable file → Normal file
View file

1176
public/file_uploader/js/vendor/jquery.ui.widget.js vendored Executable file → Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,55 +0,0 @@
{
"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"
}

View file

@ -1,12 +0,0 @@
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

View file

@ -1,361 +0,0 @@
/*
* 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)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,2 +0,0 @@
User-agent: *
Disallow:

View file

@ -1,17 +0,0 @@
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

View file

@ -1,204 +0,0 @@
# -*- 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
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,2 +0,0 @@
User-agent: *
Disallow:

View file

@ -1,38 +0,0 @@
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/*

File diff suppressed because it is too large Load diff

View file

@ -1,6 +0,0 @@
apache:
build: ./
ports:
- "80:80"
volumes:
- "../../:/var/www/html"

View file

@ -1,3 +0,0 @@
*
!.gitignore
!.htaccess

View file

@ -1,26 +0,0 @@
# 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

View file

@ -1,15 +0,0 @@
<?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();

View file

@ -1,172 +0,0 @@
<!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">&nbsp;</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>

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 600 B

BIN
public/img/more_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

View file

@ -2,16 +2,6 @@
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
);
ALTER TABLE images ADD COLUMN original_filename TEXT NOT NULL DEFAULT "Unknown";
COMMIT;

View file

@ -0,0 +1,17 @@
-- 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;

View file

@ -1,7 +1,40 @@
-- Revert fotostore:images from sqlite
-- Deploy fotostore:images to 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;

View file

@ -0,0 +1,7 @@
-- Revert fotostore:images from sqlite
BEGIN;
DROP TABLE images;
COMMIT;

View file

@ -8,3 +8,6 @@ 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.

View file

@ -2,6 +2,6 @@
BEGIN;
select file_id, owner_id, file_name, created_time from images where 0;
select file_id, owner_id, file_name, original_filename, created_time from images where 0;
ROLLBACK;

View file

@ -0,0 +1,7 @@
-- Verify fotostore:images on sqlite
BEGIN;
select file_id, owner_id, file_name, created_time from images where 0;
ROLLBACK;

View file

@ -1,5 +1,5 @@
<div class="container">
<div class"upload-form">
<div class="container upload-form" id="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 .bar').css(
$('#progress .progress-bar').css(
'width',
progress + '%'
);
@ -26,11 +26,10 @@
});
</script>
<div id="progress" class="container">
<div class="progress-bar" style="width: 0%;"></div>
</div>
<div id="progress">
<div class="bar" style="width: 0%;"></div>
</div>
<div id="lastUploadLog"></div>
<div id="lastUploadLog" class="container"></div>
</div>
<!-- display images from server -->
@ -38,18 +37,50 @@
<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">
<img v-bind:src="image.thumbnail_url">
<div class="image_title">
{{ image.filename }}
</div>
</div>
<div class="foto-notes col-md-3">
<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 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">
&lt;img src={{ hostname+image.original_url }}&gt;
</div>
<div @click="copyText" class="copy-bb-more">
[MORE=&lt;img src={{ hostname+image.thumbnail_url }}&gt;]&lt;img src={{ hostname+image.original_url }}&gt;[/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">
&lt;img src={{ hostname+scale.url }}&gt;
</div>
<div @click="copyText" class="copy-bb-more">
[MORE=&lt;img src={{ hostname+image.thumbnail_url }}&gt;]&lt;img src={{ hostname+scale.url }}&gt;[/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>
</div>
</div>
</div>
</div>
<script>
@ -59,34 +90,39 @@
var demo = new Vue({
el: '#images_list',
data: {
imagesList: null
imagesList: null,
pageNumber: 1,
pagesCount: 5,
imagesPerPage: 20,
},
created: function () {
this.fetchData()
this.fetchData(this.pageNumber)
},
methods: {
fetchData: function () {
var xhr = new XMLHttpRequest()
var self = this
xhr.open('GET', apiURL)
xhr.onload = function () {
self.imagesList = JSON.parse(xhr.responseText)
}
xhr.send()
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()
},
copyText(event) {
//TODO: rewrite it to vue/JS from jquery
//TODO: rewrite it to vue or pure JS from jQuery
var $temp = $("<input>");
$("body").append($temp);
$temp.val("<img src="+$(event.target).text()+">").select();
$temp.val($(event.target).text().trim()).select();
document.execCommand("copy");
$temp.remove();
},
}
})
});
</script>

View file

@ -15,13 +15,6 @@
<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">