From 000d1b000d94876ac653af9e4488ec3642162af1 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Tue, 3 Oct 2017 05:14:53 +0300 Subject: [PATCH] Add tutorial for DropzoneJS. Stay tuned for two-parts article series on https://medium.com/@kataras and https://dev.to/@kataras Former-commit-id: 2aac5c1f5a5b5a7039a7a5fad3312a49e9311ddd --- _examples/http_request/upload-files/main.go | 8 +- .../upload-files/templates/upload_form.html | 2 +- _examples/tutorial/dropzonejs/README.md | 160 ++ _examples/tutorial/dropzonejs/README_NEXT.MD | 303 +++ .../tutorial/dropzonejs/folder_structure.png | Bin 0 -> 10628 bytes _examples/tutorial/dropzonejs/no_files.png | Bin 0 -> 31987 bytes _examples/tutorial/dropzonejs/src/main.go | 171 ++ .../dropzonejs/src/public/css/dropzone.css | 388 ++++ .../dropzonejs/src/public/js/dropzone.js | 2052 +++++++++++++++++ .../tutorial/dropzonejs/src/views/upload.html | 53 + _examples/tutorial/dropzonejs/with_files.png | Bin 0 -> 42036 bytes 11 files changed, 3132 insertions(+), 5 deletions(-) create mode 100644 _examples/tutorial/dropzonejs/README.md create mode 100644 _examples/tutorial/dropzonejs/README_NEXT.MD create mode 100644 _examples/tutorial/dropzonejs/folder_structure.png create mode 100644 _examples/tutorial/dropzonejs/no_files.png create mode 100644 _examples/tutorial/dropzonejs/src/main.go create mode 100644 _examples/tutorial/dropzonejs/src/public/css/dropzone.css create mode 100644 _examples/tutorial/dropzonejs/src/public/js/dropzone.js create mode 100644 _examples/tutorial/dropzonejs/src/views/upload.html create mode 100644 _examples/tutorial/dropzonejs/with_files.png diff --git a/_examples/http_request/upload-files/main.go b/_examples/http_request/upload-files/main.go index a9d574e0..77968e1f 100644 --- a/_examples/http_request/upload-files/main.go +++ b/_examples/http_request/upload-files/main.go @@ -16,16 +16,16 @@ func main() { app.RegisterView(iris.HTML("./templates", ".html")) - // Serve the form.html to the user + // Serve the upload_form.html to the client. app.Get("/upload", func(ctx iris.Context) { - //create a token (optionally) + // create a token (optionally). now := time.Now().Unix() h := md5.New() io.WriteString(h, strconv.FormatInt(now, 10)) token := fmt.Sprintf("%x", h.Sum(nil)) - // render the form with the token for any use you like + // render the form with the token for any use you'd like. ctx.ViewData("", token) ctx.View("upload_form.html") }) @@ -34,7 +34,7 @@ func main() { app.Post("/upload", iris.LimitRequestBodySize(10<<20), func(ctx iris.Context) { // or use ctx.SetMaxRequestBodySize(10 << 20) - //to limit the uploaded file(s) size. + // to limit the uploaded file(s) size. // Get the file from the request file, info, err := ctx.FormFile("uploadfile") diff --git a/_examples/http_request/upload-files/templates/upload_form.html b/_examples/http_request/upload-files/templates/upload_form.html index 55350ff8..9782eadf 100644 --- a/_examples/http_request/upload-files/templates/upload_form.html +++ b/_examples/http_request/upload-files/templates/upload_form.html @@ -4,7 +4,7 @@
+ action="http://127.0.0.1:8080/upload" method="POST">
diff --git a/_examples/tutorial/dropzonejs/README.md b/_examples/tutorial/dropzonejs/README.md new file mode 100644 index 00000000..b296a3b8 --- /dev/null +++ b/_examples/tutorial/dropzonejs/README.md @@ -0,0 +1,160 @@ +This is the part 1 of 2 in DropzoneJS + Go series. + +- [Part 1: How to build a file upload form](README.md) +- [Part 2: How to display existing files on server](README_NEXT.md) + +# DropzoneJS + Go: How to build a file upload form + +[DropzoneJS](https://github.com/enyo/dropzone) is an open source library that provides drag'n'drop file uploads with image previews. It is a great JavaScript library which actually does not even rely on JQuery. +In this tutorial, we are building a multiple file upload form using DropzoneJS, and the backend will be handled by Go and [Iris](https://iris-go.com). + +## Table Of Content + +- [Preparation](#preparation) +- [Work with DropzoneJS](#work-with-dropzonejs) +- [Work with Go](#work-with-go) + +## Preparation + +1. Download [Go(Golang)](https://golang.org/dl), setup your computer as shown there and continue to 2. +2. Install [Iris](https://github.com/kataras/iris); open a terminal and execute `go get -u github.com/kataras/iris` +3. Download DropzoneJS from [this URL](https://raw.githubusercontent.com/enyo/dropzone/master/dist/dropzone.js). DropzoneJS does not rely on JQuery, you will not have to worry that, upgrading JQuery version breaks your application. +4. Download dropzone.css from [this URL](https://raw.githubusercontent.com/enyo/dropzone/master/dist/dropzone.css), if you want some already made css. +5. Create a folder "./public/uploads", this is for storing uploaded files. +6. Create a file "./views/upload.html", this is for the front form page. +7. Create a file "./main.go", this is for handling backend file upload process. + +Your folder&file structure should look like this after the preparation: + +![folder&file structure](folder_structure.png) + +## Work with DropzoneJS + +Open file "./views/upload.html" and let us create a DropzoneJs form. + +Copy the content below to "./views/upload.html" and we will go through each line of code individually. + +```html + + + + + DropzoneJS Uploader + + + + + + + + + + + +
+
+ + +
+
+ + + +``` + +1. Include the CSS Stylesheet. +2. Include DropzoneJS JavaScript library. +3. Create an upload form with css class "dropzone" and "action" is the route path "/upload". Note that we did create an input filed for fallback mode. This is all handled by DropzoneJS library itself. All we need to do is assign css class "dropzone" to the form. By default, DropzoneJS will find all forms with class "dropzone" and automatically attach itself to it. + +## Work with Go + +Now you have come to Last part of the tutorial. In this section, we will store files sent from DropzoneJS to the "./public/uploads" folder. + +Open "main.go" and copy the code below: + +```go +// main.go + +package main + +import ( + "os" + "io" + "strings" + + "github.com/kataras/iris" +) + +const uploadsDir = "./public/uploads/" + +func main() { + app := iris.New() + + // Register templates + app.RegisterView(iris.HTML("./views", ".html")) + + // Make the /public route path to statically serve the ./public/... contents + app.StaticWeb("/public", "./public") + + // Render the actual form + // GET: http://localhost:8080 + app.Get("/", func(ctx iris.Context) { + ctx.View("upload.html") + }) + + // Upload the file to the server + // POST: http://localhost:8080/upload + app.Post("/upload", iris.LimitRequestBodySize(10<<20), func(ctx iris.Context) { + // Get the file from the dropzone request + file, info, err := ctx.FormFile("file") + if err != nil { + ctx.StatusCode(iris.StatusInternalServerError) + ctx.Application().Logger().Warnf("Error while uploading: %v", err.Error()) + return + } + + defer file.Close() + fname := info.Filename + + // Create a file with the same name + // assuming that you have a folder named 'uploads' + out, err := os.OpenFile(uploadsDir+fname, + os.O_WRONLY|os.O_CREATE, 0666) + + if err != nil { + ctx.StatusCode(iris.StatusInternalServerError) + ctx.Application().Logger().Warnf("Error while preparing the new file: %v", err.Error()) + return + } + defer out.Close() + + io.Copy(out, file) + }) + + // Start the server at http://localhost:8080 + app.Run(iris.Addr(":8080")) +} +``` + +1. Create a new Iris app. +2. Register and load templates from the "views" folder. +3. Make the "/public" route path to statically serve the ./public/... folder's contents +4. Create a route to serve the upload form. +5. Create a route to handle the POST form data from the DropzoneJS' form +6. Declare a variable for destination folder. +7. If file is sent to the page, store the file object to a temporary "file" variable. +8. Move uploaded file to destination based on the uploadsDir+uploaded file's name. + +**Run the server** +Open the terminal at the current project's folder and execute: + +```bash +$ go run main.go +Now listening on: http://localhost:8080 +Application started. Press CTRL+C to shut down. +``` + +Now go to browser, and navigate to http://localhost:8080, you should be able to see a page as below: + +![no files screenshot](no_files.png) +![with uploaded files screenshot](with_files.png) \ No newline at end of file diff --git a/_examples/tutorial/dropzonejs/README_NEXT.MD b/_examples/tutorial/dropzonejs/README_NEXT.MD new file mode 100644 index 00000000..a28eb823 --- /dev/null +++ b/_examples/tutorial/dropzonejs/README_NEXT.MD @@ -0,0 +1,303 @@ +This is the part 2 of 2 in DropzoneJS + Go series. + +- [Part 1: How to build a file upload form](README.md) +- [Part 2: How to display existing files on server](README_NEXT.md) + +# DropzoneJS + Go: How to display existing files on server + +In this tutorial, we will show you how to display existing files on the server when using DropzoneJs and Go. This tutorial is based on [How to build a file upload form using DropzoneJs and Go](README.md). Make sure you have read it before proceeding to content in this tutorial. + +## Table Of Content + +- [Preparation](#preparation) +- [Modify the Server side](#modify-the-server-side) +- [Modify the Client side](#modify-the-client-side) +- [References](#references) +- [The End](#the-end) + +## Preparation + +Install the go package "nfnt/resize" with `go get github.com/nfnt/resize`, we need it to create thumbnails. + +In previous [tutorial](README.md). We have already set up a proper working DropzoneJs upload form. There is no additional file needed for this tutorial. What we need to do is to make some modifications to file below: + +1. main.go +2. views/upload.html + +Let us get started! + +## Modify the Server side + +In previous tutorial. All "/upload" does is to store uploaded files to the server directory "./public/uploads". So we need to add a piece of code to retrieve stored files' information (name and size), and return it in JSON format. + +Copy the content below to "main.go". Read comments for details. + +```go +// main.go + +package main + +import ( + "image/jpeg" + "image/png" + "io" + "os" + "path" + "path/filepath" + "strings" + "sync" + + "github.com/kataras/iris" + + "github.com/nfnt/resize" // $ go get -u github.com/nfnt/resize +) + +const uploadsDir = "./public/uploads/" + +type uploadedFile struct { + // {name: "", size: } are the dropzone's only requirements. + Name string `json:"name"` + Size int64 `json:"size"` +} + +type uploadedFiles struct { + dir string + items []uploadedFile + mu sync.RWMutex // slices are safe but RWMutex is a good practise for you. +} + +// scan the ./public/uploads folder for any files +// add them to a new uploadedFiles list. +func scanUploads(dir string) *uploadedFiles { + f := new(uploadedFiles) + + lindex := dir[len(dir)-1] + if lindex != os.PathSeparator && lindex != '/' { + dir += string(os.PathSeparator) + } + + // create directories if necessary + // and if, then return empty uploaded files; skipping the scan. + if err := os.MkdirAll(dir, os.FileMode(0666)); err != nil { + return f + } + + // otherwise scan the given "dir" for files. + f.scan(dir) + return f +} + +func (f *uploadedFiles) scan(dir string) { + f.dir = dir + filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + + // if it's directory or a thumbnail we saved ealier, skip it. + if info.IsDir() || strings.HasPrefix(info.Name(), "thumbnail_") { + return nil + } + + f.add(info.Name(), info.Size()) + return nil + }) +} + +// add the file's Name and Size to the uploadedFiles memory list +func (f *uploadedFiles) add(name string, size int64) uploadedFile { + f.mu.Lock() + uf := uploadedFile{ + Name: name, + Size: size, + } + f.items = append(f.items, uf) + f.mu.Unlock() + + return uf +} + +// create thumbnail 100x100 +// and save that to the ./public/uploads/thumbnail_$FILENAME +func (f *uploadedFiles) createThumbnail(uf uploadedFile) { + file, err := os.Open(path.Join(f.dir, uf.Name)) + if err != nil { + return + } + defer file.Close() + + name := strings.ToLower(uf.Name) + + out, err := os.OpenFile(f.dir+"thumbnail_"+uf.Name, + os.O_WRONLY|os.O_CREATE, 0666) + if err != nil { + return + } + defer out.Close() + + if strings.HasSuffix(name, ".jpg") { + // decode jpeg into image.Image + img, err := jpeg.Decode(file) + if err != nil { + return + } + + // write new image to file + resized := resize.Thumbnail(180, 180, img, resize.Lanczos3) + jpeg.Encode(out, resized, + &jpeg.Options{Quality: jpeg.DefaultQuality}) + + } else if strings.HasSuffix(name, ".png") { + img, err := png.Decode(file) + if err != nil { + return + } + + // write new image to file + resized := resize.Thumbnail(180, 180, img, resize.Lanczos3) // slower but better res + png.Encode(out, resized) + } + // and so on... you got the point, this code can be simplify, as a practise. +} + +func main() { + app := iris.New() + app.RegisterView(iris.HTML("./views", ".html")) + + app.StaticWeb("/public", "./public") + + app.Get("/", func(ctx iris.Context) { + ctx.View("upload.html") + }) + + files := scanUploads(uploadsDir) + + app.Get("/uploads", func(ctx iris.Context) { + ctx.JSON(files.items) + }) + + app.Post("/upload", iris.LimitRequestBodySize(10<<20), func(ctx iris.Context) { + // Get the file from the dropzone request + file, info, err := ctx.FormFile("file") + if err != nil { + ctx.StatusCode(iris.StatusInternalServerError) + ctx.Application().Logger().Warnf("Error while uploading: %v", err.Error()) + return + } + + defer file.Close() + fname := info.Filename + + // Create a file with the same name + // assuming that you have a folder named 'uploads' + out, err := os.OpenFile(uploadsDir+fname, + os.O_WRONLY|os.O_CREATE, 0666) + + if err != nil { + ctx.StatusCode(iris.StatusInternalServerError) + ctx.Application().Logger().Warnf("Error while preparing the new file: %v", err.Error()) + return + } + defer out.Close() + + io.Copy(out, file) + + // optionally, add that file to the list in order to be visible when refresh. + uploadedFile := files.add(fname, info.Size) + go files.createThumbnail(uploadedFile) + }) + + // start the server at http://localhost:8080 + app.Run(iris.Addr(":8080")) +} +``` + +## Modify the Client side + +Copy content below to "./views/upload.html". We will go through modifications individually. + +```html + + + + + DropzoneJS Uploader + + + + + + + + + + + + + + + +
+
+ + +
+
+ + + +``` + +1. We added Jquery library into our page. This actually not for DropzoneJs directly. We are using Jquery's ajax function **$.get** only. You will see below +2. We added an ID element (my-dropzone) to the form. This is needed because we need to pass configuration values to Dropzone. And to do it, we must have an ID reference of it. So that we can configure it by assigning values to Dropzone.options.myDropzone. A lot of people face confusion when configuring Dropzone. To put it in a simple way. Do not take Dropzone as a Jquery plugin, it has its own syntax and you need to follow it. +3. This starts the main part of modification. What we did here is to pass a function to listen to Dropzone's init event. This event is called when Dropzone is initialized. +4. Retrieve files details from the new "/uploads" via ajax. +5. Create mockFile using values from server. mockFile is simply JavaScript objects with properties of name and size. Then we call Dropzone's **addedfile** and **thumbnail** functions explicitly to put existing files to Dropzone upload area and generate its thumbnail. + + +**Run the server** +Open the terminal at the current project's folder and execute: + +```bash +$ go run main.go +Now listening on: http://localhost:8080 +Application started. Press CTRL+C to shut down. +``` + +If you have done it successfully. Now go and upload some images and reload the upload page. Already uploaded files should auto display in Dropzone area. + +![with uploaded files screenshot](with_files.png) + +## References + +- http://www.dropzonejs.com/#server-side-implementation +- https://www.startutorial.com/articles/view/how-to-build-a-file-upload-form-using-dropzonejs-and-php +- https://docs.iris-go.com +- https://github.com/kataras/iris/tree/master/_examples/tutorial/dropzonejs + +## The end + +Hopefully this simple tutorial helped you with your development. +If you like my post, please follow me on [Twitter](https://twitter.com/makismaropoulos) and help spread the word. I need your support to continue. \ No newline at end of file diff --git a/_examples/tutorial/dropzonejs/folder_structure.png b/_examples/tutorial/dropzonejs/folder_structure.png new file mode 100644 index 0000000000000000000000000000000000000000..2c81637c3411c4d3f5bf2069dc000715917703e0 GIT binary patch literal 10628 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 S5A2*IP<{IRNwuQ&>;DCtU)Hh! literal 0 HcmV?d00001 diff --git a/_examples/tutorial/dropzonejs/no_files.png b/_examples/tutorial/dropzonejs/no_files.png new file mode 100644 index 0000000000000000000000000000000000000000..6e4afacb52e81714cc0ea27e2f349d0c264f0e28 GIT binary patch literal 31987 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 + */ +@-webkit-keyframes passing-through { + 0% { + opacity: 0; + -webkit-transform: translateY(40px); + -moz-transform: translateY(40px); + -ms-transform: translateY(40px); + -o-transform: translateY(40px); + transform: translateY(40px); } + 30%, 70% { + opacity: 1; + -webkit-transform: translateY(0px); + -moz-transform: translateY(0px); + -ms-transform: translateY(0px); + -o-transform: translateY(0px); + transform: translateY(0px); } + 100% { + opacity: 0; + -webkit-transform: translateY(-40px); + -moz-transform: translateY(-40px); + -ms-transform: translateY(-40px); + -o-transform: translateY(-40px); + transform: translateY(-40px); } } +@-moz-keyframes passing-through { + 0% { + opacity: 0; + -webkit-transform: translateY(40px); + -moz-transform: translateY(40px); + -ms-transform: translateY(40px); + -o-transform: translateY(40px); + transform: translateY(40px); } + 30%, 70% { + opacity: 1; + -webkit-transform: translateY(0px); + -moz-transform: translateY(0px); + -ms-transform: translateY(0px); + -o-transform: translateY(0px); + transform: translateY(0px); } + 100% { + opacity: 0; + -webkit-transform: translateY(-40px); + -moz-transform: translateY(-40px); + -ms-transform: translateY(-40px); + -o-transform: translateY(-40px); + transform: translateY(-40px); } } +@keyframes passing-through { + 0% { + opacity: 0; + -webkit-transform: translateY(40px); + -moz-transform: translateY(40px); + -ms-transform: translateY(40px); + -o-transform: translateY(40px); + transform: translateY(40px); } + 30%, 70% { + opacity: 1; + -webkit-transform: translateY(0px); + -moz-transform: translateY(0px); + -ms-transform: translateY(0px); + -o-transform: translateY(0px); + transform: translateY(0px); } + 100% { + opacity: 0; + -webkit-transform: translateY(-40px); + -moz-transform: translateY(-40px); + -ms-transform: translateY(-40px); + -o-transform: translateY(-40px); + transform: translateY(-40px); } } +@-webkit-keyframes slide-in { + 0% { + opacity: 0; + -webkit-transform: translateY(40px); + -moz-transform: translateY(40px); + -ms-transform: translateY(40px); + -o-transform: translateY(40px); + transform: translateY(40px); } + 30% { + opacity: 1; + -webkit-transform: translateY(0px); + -moz-transform: translateY(0px); + -ms-transform: translateY(0px); + -o-transform: translateY(0px); + transform: translateY(0px); } } +@-moz-keyframes slide-in { + 0% { + opacity: 0; + -webkit-transform: translateY(40px); + -moz-transform: translateY(40px); + -ms-transform: translateY(40px); + -o-transform: translateY(40px); + transform: translateY(40px); } + 30% { + opacity: 1; + -webkit-transform: translateY(0px); + -moz-transform: translateY(0px); + -ms-transform: translateY(0px); + -o-transform: translateY(0px); + transform: translateY(0px); } } +@keyframes slide-in { + 0% { + opacity: 0; + -webkit-transform: translateY(40px); + -moz-transform: translateY(40px); + -ms-transform: translateY(40px); + -o-transform: translateY(40px); + transform: translateY(40px); } + 30% { + opacity: 1; + -webkit-transform: translateY(0px); + -moz-transform: translateY(0px); + -ms-transform: translateY(0px); + -o-transform: translateY(0px); + transform: translateY(0px); } } +@-webkit-keyframes pulse { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); } + 10% { + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -ms-transform: scale(1.1); + -o-transform: scale(1.1); + transform: scale(1.1); } + 20% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); } } +@-moz-keyframes pulse { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); } + 10% { + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -ms-transform: scale(1.1); + -o-transform: scale(1.1); + transform: scale(1.1); } + 20% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); } } +@keyframes pulse { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); } + 10% { + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -ms-transform: scale(1.1); + -o-transform: scale(1.1); + transform: scale(1.1); } + 20% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); } } +.dropzone, .dropzone * { + box-sizing: border-box; } + +.dropzone { + min-height: 150px; + border: 2px solid rgba(0, 0, 0, 0.3); + background: white; + padding: 20px 20px; } + .dropzone.dz-clickable { + cursor: pointer; } + .dropzone.dz-clickable * { + cursor: default; } + .dropzone.dz-clickable .dz-message, .dropzone.dz-clickable .dz-message * { + cursor: pointer; } + .dropzone.dz-started .dz-message { + display: none; } + .dropzone.dz-drag-hover { + border-style: solid; } + .dropzone.dz-drag-hover .dz-message { + opacity: 0.5; } + .dropzone .dz-message { + text-align: center; + margin: 2em 0; } + .dropzone .dz-preview { + position: relative; + display: inline-block; + vertical-align: top; + margin: 16px; + min-height: 100px; } + .dropzone .dz-preview:hover { + z-index: 1000; } + .dropzone .dz-preview:hover .dz-details { + opacity: 1; } + .dropzone .dz-preview.dz-file-preview .dz-image { + border-radius: 20px; + background: #999; + background: linear-gradient(to bottom, #eee, #ddd); } + .dropzone .dz-preview.dz-file-preview .dz-details { + opacity: 1; } + .dropzone .dz-preview.dz-image-preview { + background: white; } + .dropzone .dz-preview.dz-image-preview .dz-details { + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + -ms-transition: opacity 0.2s linear; + -o-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; } + .dropzone .dz-preview .dz-remove { + font-size: 14px; + text-align: center; + display: block; + cursor: pointer; + border: none; } + .dropzone .dz-preview .dz-remove:hover { + text-decoration: underline; } + .dropzone .dz-preview:hover .dz-details { + opacity: 1; } + .dropzone .dz-preview .dz-details { + z-index: 20; + position: absolute; + top: 0; + left: 0; + opacity: 0; + font-size: 13px; + min-width: 100%; + max-width: 100%; + padding: 2em 1em; + text-align: center; + color: rgba(0, 0, 0, 0.9); + line-height: 150%; } + .dropzone .dz-preview .dz-details .dz-size { + margin-bottom: 1em; + font-size: 16px; } + .dropzone .dz-preview .dz-details .dz-filename { + white-space: nowrap; } + .dropzone .dz-preview .dz-details .dz-filename:hover span { + border: 1px solid rgba(200, 200, 200, 0.8); + background-color: rgba(255, 255, 255, 0.8); } + .dropzone .dz-preview .dz-details .dz-filename:not(:hover) { + overflow: hidden; + text-overflow: ellipsis; } + .dropzone .dz-preview .dz-details .dz-filename:not(:hover) span { + border: 1px solid transparent; } + .dropzone .dz-preview .dz-details .dz-filename span, .dropzone .dz-preview .dz-details .dz-size span { + background-color: rgba(255, 255, 255, 0.4); + padding: 0 0.4em; + border-radius: 3px; } + .dropzone .dz-preview:hover .dz-image img { + -webkit-transform: scale(1.05, 1.05); + -moz-transform: scale(1.05, 1.05); + -ms-transform: scale(1.05, 1.05); + -o-transform: scale(1.05, 1.05); + transform: scale(1.05, 1.05); + -webkit-filter: blur(8px); + filter: blur(8px); } + .dropzone .dz-preview .dz-image { + border-radius: 20px; + overflow: hidden; + width: 120px; + height: 120px; + position: relative; + display: block; + z-index: 10; } + .dropzone .dz-preview .dz-image img { + display: block; } + .dropzone .dz-preview.dz-success .dz-success-mark { + -webkit-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); + -moz-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); + -ms-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); + -o-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); + animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); } + .dropzone .dz-preview.dz-error .dz-error-mark { + opacity: 1; + -webkit-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); + -moz-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); + -ms-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); + -o-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); + animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); } + .dropzone .dz-preview .dz-success-mark, .dropzone .dz-preview .dz-error-mark { + pointer-events: none; + opacity: 0; + z-index: 500; + position: absolute; + display: block; + top: 50%; + left: 50%; + margin-left: -27px; + margin-top: -27px; } + .dropzone .dz-preview .dz-success-mark svg, .dropzone .dz-preview .dz-error-mark svg { + display: block; + width: 54px; + height: 54px; } + .dropzone .dz-preview.dz-processing .dz-progress { + opacity: 1; + -webkit-transition: all 0.2s linear; + -moz-transition: all 0.2s linear; + -ms-transition: all 0.2s linear; + -o-transition: all 0.2s linear; + transition: all 0.2s linear; } + .dropzone .dz-preview.dz-complete .dz-progress { + opacity: 0; + -webkit-transition: opacity 0.4s ease-in; + -moz-transition: opacity 0.4s ease-in; + -ms-transition: opacity 0.4s ease-in; + -o-transition: opacity 0.4s ease-in; + transition: opacity 0.4s ease-in; } + .dropzone .dz-preview:not(.dz-processing) .dz-progress { + -webkit-animation: pulse 6s ease infinite; + -moz-animation: pulse 6s ease infinite; + -ms-animation: pulse 6s ease infinite; + -o-animation: pulse 6s ease infinite; + animation: pulse 6s ease infinite; } + .dropzone .dz-preview .dz-progress { + opacity: 1; + z-index: 1000; + pointer-events: none; + position: absolute; + height: 16px; + left: 50%; + top: 50%; + margin-top: -8px; + width: 80px; + margin-left: -40px; + background: rgba(255, 255, 255, 0.9); + -webkit-transform: scale(1); + border-radius: 8px; + overflow: hidden; } + .dropzone .dz-preview .dz-progress .dz-upload { + background: #333; + background: linear-gradient(to bottom, #666, #444); + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 0; + -webkit-transition: width 300ms ease-in-out; + -moz-transition: width 300ms ease-in-out; + -ms-transition: width 300ms ease-in-out; + -o-transition: width 300ms ease-in-out; + transition: width 300ms ease-in-out; } + .dropzone .dz-preview.dz-error .dz-error-message { + display: block; } + .dropzone .dz-preview.dz-error:hover .dz-error-message { + opacity: 1; + pointer-events: auto; } + .dropzone .dz-preview .dz-error-message { + pointer-events: none; + z-index: 1000; + position: absolute; + display: block; + display: none; + opacity: 0; + -webkit-transition: opacity 0.3s ease; + -moz-transition: opacity 0.3s ease; + -ms-transition: opacity 0.3s ease; + -o-transition: opacity 0.3s ease; + transition: opacity 0.3s ease; + border-radius: 8px; + font-size: 13px; + top: 130px; + left: -10px; + width: 140px; + background: #be2626; + background: linear-gradient(to bottom, #be2626, #a92222); + padding: 0.5em 1.2em; + color: white; } + .dropzone .dz-preview .dz-error-message:after { + content: ''; + position: absolute; + top: -6px; + left: 64px; + width: 0; + height: 0; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #be2626; } diff --git a/_examples/tutorial/dropzonejs/src/public/js/dropzone.js b/_examples/tutorial/dropzonejs/src/public/js/dropzone.js new file mode 100644 index 00000000..1bf9a7fe --- /dev/null +++ b/_examples/tutorial/dropzonejs/src/public/js/dropzone.js @@ -0,0 +1,2052 @@ + +/* + * + * More info at [www.dropzonejs.com](http://www.dropzonejs.com) + * + * Copyright (c) 2012, Matias Meno + * + * 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. + * + */ + +(function() { + var Dropzone, Emitter, ExifRestore, camelize, contentLoaded, detectVerticalSquash, drawImageIOSFix, noop, without, + slice = [].slice, + extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + noop = function() {}; + + Emitter = (function() { + function Emitter() {} + + Emitter.prototype.addEventListener = Emitter.prototype.on; + + Emitter.prototype.on = function(event, fn) { + this._callbacks = this._callbacks || {}; + if (!this._callbacks[event]) { + this._callbacks[event] = []; + } + this._callbacks[event].push(fn); + return this; + }; + + Emitter.prototype.emit = function() { + var args, callback, callbacks, event, j, len; + event = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + this._callbacks = this._callbacks || {}; + callbacks = this._callbacks[event]; + if (callbacks) { + for (j = 0, len = callbacks.length; j < len; j++) { + callback = callbacks[j]; + callback.apply(this, args); + } + } + return this; + }; + + Emitter.prototype.removeListener = Emitter.prototype.off; + + Emitter.prototype.removeAllListeners = Emitter.prototype.off; + + Emitter.prototype.removeEventListener = Emitter.prototype.off; + + Emitter.prototype.off = function(event, fn) { + var callback, callbacks, i, j, len; + if (!this._callbacks || arguments.length === 0) { + this._callbacks = {}; + return this; + } + callbacks = this._callbacks[event]; + if (!callbacks) { + return this; + } + if (arguments.length === 1) { + delete this._callbacks[event]; + return this; + } + for (i = j = 0, len = callbacks.length; j < len; i = ++j) { + callback = callbacks[i]; + if (callback === fn) { + callbacks.splice(i, 1); + break; + } + } + return this; + }; + + return Emitter; + + })(); + + Dropzone = (function(superClass) { + var extend, resolveOption; + + extend1(Dropzone, superClass); + + Dropzone.prototype.Emitter = Emitter; + + + /* + This is a list of all available events you can register on a dropzone object. + + You can register an event handler like this: + + dropzone.on("dragEnter", function() { }); + */ + + Dropzone.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "addedfiles", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"]; + + Dropzone.prototype.defaultOptions = { + url: null, + method: "post", + withCredentials: false, + timeout: 30000, + parallelUploads: 2, + uploadMultiple: false, + maxFilesize: 256, + paramName: "file", + createImageThumbnails: true, + maxThumbnailFilesize: 10, + thumbnailWidth: 120, + thumbnailHeight: 120, + thumbnailMethod: 'crop', + resizeWidth: null, + resizeHeight: null, + resizeMimeType: null, + resizeQuality: 0.8, + resizeMethod: 'contain', + filesizeBase: 1000, + maxFiles: null, + params: {}, + headers: null, + clickable: true, + ignoreHiddenFiles: true, + acceptedFiles: null, + acceptedMimeTypes: null, + autoProcessQueue: true, + autoQueue: true, + addRemoveLinks: false, + previewsContainer: null, + hiddenInputContainer: "body", + capture: null, + renameFilename: null, + renameFile: null, + forceFallback: false, + dictDefaultMessage: "Drop files here to upload", + dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.", + dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.", + dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.", + dictInvalidFileType: "You can't upload files of this type.", + dictResponseError: "Server responded with {{statusCode}} code.", + dictCancelUpload: "Cancel upload", + dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?", + dictRemoveFile: "Remove file", + dictRemoveFileConfirmation: null, + dictMaxFilesExceeded: "You can not upload any more files.", + dictFileSizeUnits: { + tb: "TB", + gb: "GB", + mb: "MB", + kb: "KB", + b: "b" + }, + init: function() { + return noop; + }, + accept: function(file, done) { + return done(); + }, + fallback: function() { + var child, j, len, messageElement, ref, span; + this.element.className = this.element.className + " dz-browser-not-supported"; + ref = this.element.getElementsByTagName("div"); + for (j = 0, len = ref.length; j < len; j++) { + child = ref[j]; + if (/(^| )dz-message($| )/.test(child.className)) { + messageElement = child; + child.className = "dz-message"; + continue; + } + } + if (!messageElement) { + messageElement = Dropzone.createElement("
"); + this.element.appendChild(messageElement); + } + span = messageElement.getElementsByTagName("span")[0]; + if (span) { + if (span.textContent != null) { + span.textContent = this.options.dictFallbackMessage; + } else if (span.innerText != null) { + span.innerText = this.options.dictFallbackMessage; + } + } + return this.element.appendChild(this.getFallbackForm()); + }, + resize: function(file, width, height, resizeMethod) { + var info, srcRatio, trgRatio; + info = { + srcX: 0, + srcY: 0, + srcWidth: file.width, + srcHeight: file.height + }; + srcRatio = file.width / file.height; + if ((width == null) && (height == null)) { + width = info.srcWidth; + height = info.srcHeight; + } else if (width == null) { + width = height * srcRatio; + } else if (height == null) { + height = width / srcRatio; + } + width = Math.min(width, info.srcWidth); + height = Math.min(height, info.srcHeight); + trgRatio = width / height; + if (info.srcWidth > width || info.srcHeight > height) { + if (resizeMethod === 'crop') { + if (srcRatio > trgRatio) { + info.srcHeight = file.height; + info.srcWidth = info.srcHeight * trgRatio; + } else { + info.srcWidth = file.width; + info.srcHeight = info.srcWidth / trgRatio; + } + } else if (resizeMethod === 'contain') { + if (srcRatio > trgRatio) { + height = width / srcRatio; + } else { + width = height * srcRatio; + } + } else { + throw new Error("Unknown resizeMethod '" + resizeMethod + "'"); + } + } + info.srcX = (file.width - info.srcWidth) / 2; + info.srcY = (file.height - info.srcHeight) / 2; + info.trgWidth = width; + info.trgHeight = height; + return info; + }, + transformFile: function(file, done) { + if ((this.options.resizeWidth || this.options.resizeHeight) && file.type.match(/image.*/)) { + return this.resizeImage(file, this.options.resizeWidth, this.options.resizeHeight, this.options.resizeMethod, done); + } else { + return done(file); + } + }, + previewTemplate: "
\n
\n
\n
\n
\n
\n
\n
\n
\n \n Check\n \n \n \n \n \n
\n
\n \n Error\n \n \n \n \n \n \n \n
\n
", + + /* + Those functions register themselves to the events on init and handle all + the user interface specific stuff. Overwriting them won't break the upload + but can break the way it's displayed. + You can overwrite them if you don't like the default behavior. If you just + want to add an additional event handler, register it on the dropzone object + and don't overwrite those options. + */ + drop: function(e) { + return this.element.classList.remove("dz-drag-hover"); + }, + dragstart: noop, + dragend: function(e) { + return this.element.classList.remove("dz-drag-hover"); + }, + dragenter: function(e) { + return this.element.classList.add("dz-drag-hover"); + }, + dragover: function(e) { + return this.element.classList.add("dz-drag-hover"); + }, + dragleave: function(e) { + return this.element.classList.remove("dz-drag-hover"); + }, + paste: noop, + reset: function() { + return this.element.classList.remove("dz-started"); + }, + addedfile: function(file) { + var j, k, l, len, len1, len2, node, ref, ref1, ref2, removeFileEvent, removeLink, results; + if (this.element === this.previewsContainer) { + this.element.classList.add("dz-started"); + } + if (this.previewsContainer) { + file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim()); + file.previewTemplate = file.previewElement; + this.previewsContainer.appendChild(file.previewElement); + ref = file.previewElement.querySelectorAll("[data-dz-name]"); + for (j = 0, len = ref.length; j < len; j++) { + node = ref[j]; + node.textContent = file.name; + } + ref1 = file.previewElement.querySelectorAll("[data-dz-size]"); + for (k = 0, len1 = ref1.length; k < len1; k++) { + node = ref1[k]; + node.innerHTML = this.filesize(file.size); + } + if (this.options.addRemoveLinks) { + file._removeLink = Dropzone.createElement("" + this.options.dictRemoveFile + ""); + file.previewElement.appendChild(file._removeLink); + } + removeFileEvent = (function(_this) { + return function(e) { + e.preventDefault(); + e.stopPropagation(); + if (file.status === Dropzone.UPLOADING) { + return Dropzone.confirm(_this.options.dictCancelUploadConfirmation, function() { + return _this.removeFile(file); + }); + } else { + if (_this.options.dictRemoveFileConfirmation) { + return Dropzone.confirm(_this.options.dictRemoveFileConfirmation, function() { + return _this.removeFile(file); + }); + } else { + return _this.removeFile(file); + } + } + }; + })(this); + ref2 = file.previewElement.querySelectorAll("[data-dz-remove]"); + results = []; + for (l = 0, len2 = ref2.length; l < len2; l++) { + removeLink = ref2[l]; + results.push(removeLink.addEventListener("click", removeFileEvent)); + } + return results; + } + }, + removedfile: function(file) { + var ref; + if (file.previewElement) { + if ((ref = file.previewElement) != null) { + ref.parentNode.removeChild(file.previewElement); + } + } + return this._updateMaxFilesReachedClass(); + }, + thumbnail: function(file, dataUrl) { + var j, len, ref, thumbnailElement; + if (file.previewElement) { + file.previewElement.classList.remove("dz-file-preview"); + ref = file.previewElement.querySelectorAll("[data-dz-thumbnail]"); + for (j = 0, len = ref.length; j < len; j++) { + thumbnailElement = ref[j]; + thumbnailElement.alt = file.name; + thumbnailElement.src = dataUrl; + } + return setTimeout(((function(_this) { + return function() { + return file.previewElement.classList.add("dz-image-preview"); + }; + })(this)), 1); + } + }, + error: function(file, message) { + var j, len, node, ref, results; + if (file.previewElement) { + file.previewElement.classList.add("dz-error"); + if (typeof message !== "String" && message.error) { + message = message.error; + } + ref = file.previewElement.querySelectorAll("[data-dz-errormessage]"); + results = []; + for (j = 0, len = ref.length; j < len; j++) { + node = ref[j]; + results.push(node.textContent = message); + } + return results; + } + }, + errormultiple: noop, + processing: function(file) { + if (file.previewElement) { + file.previewElement.classList.add("dz-processing"); + if (file._removeLink) { + return file._removeLink.textContent = this.options.dictCancelUpload; + } + } + }, + processingmultiple: noop, + uploadprogress: function(file, progress, bytesSent) { + var j, len, node, ref, results; + if (file.previewElement) { + ref = file.previewElement.querySelectorAll("[data-dz-uploadprogress]"); + results = []; + for (j = 0, len = ref.length; j < len; j++) { + node = ref[j]; + if (node.nodeName === 'PROGRESS') { + results.push(node.value = progress); + } else { + results.push(node.style.width = progress + "%"); + } + } + return results; + } + }, + totaluploadprogress: noop, + sending: noop, + sendingmultiple: noop, + success: function(file) { + if (file.previewElement) { + return file.previewElement.classList.add("dz-success"); + } + }, + successmultiple: noop, + canceled: function(file) { + return this.emit("error", file, "Upload canceled."); + }, + canceledmultiple: noop, + complete: function(file) { + if (file._removeLink) { + file._removeLink.textContent = this.options.dictRemoveFile; + } + if (file.previewElement) { + return file.previewElement.classList.add("dz-complete"); + } + }, + completemultiple: noop, + maxfilesexceeded: noop, + maxfilesreached: noop, + queuecomplete: noop, + addedfiles: noop + }; + + extend = function() { + var j, key, len, object, objects, target, val; + target = arguments[0], objects = 2 <= arguments.length ? slice.call(arguments, 1) : []; + for (j = 0, len = objects.length; j < len; j++) { + object = objects[j]; + for (key in object) { + val = object[key]; + target[key] = val; + } + } + return target; + }; + + function Dropzone(element1, options) { + var elementOptions, fallback, ref; + this.element = element1; + this.version = Dropzone.version; + this.defaultOptions.previewTemplate = this.defaultOptions.previewTemplate.replace(/\n*/g, ""); + this.clickableElements = []; + this.listeners = []; + this.files = []; + if (typeof this.element === "string") { + this.element = document.querySelector(this.element); + } + if (!(this.element && (this.element.nodeType != null))) { + throw new Error("Invalid dropzone element."); + } + if (this.element.dropzone) { + throw new Error("Dropzone already attached."); + } + Dropzone.instances.push(this); + this.element.dropzone = this; + elementOptions = (ref = Dropzone.optionsForElement(this.element)) != null ? ref : {}; + this.options = extend({}, this.defaultOptions, elementOptions, options != null ? options : {}); + if (this.options.forceFallback || !Dropzone.isBrowserSupported()) { + return this.options.fallback.call(this); + } + if (this.options.url == null) { + this.options.url = this.element.getAttribute("action"); + } + if (!this.options.url) { + throw new Error("No URL provided."); + } + if (this.options.acceptedFiles && this.options.acceptedMimeTypes) { + throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated."); + } + if (this.options.acceptedMimeTypes) { + this.options.acceptedFiles = this.options.acceptedMimeTypes; + delete this.options.acceptedMimeTypes; + } + if (this.options.renameFilename != null) { + this.options.renameFile = (function(_this) { + return function(file) { + return _this.options.renameFilename.call(_this, file.name, file); + }; + })(this); + } + this.options.method = this.options.method.toUpperCase(); + if ((fallback = this.getExistingFallback()) && fallback.parentNode) { + fallback.parentNode.removeChild(fallback); + } + if (this.options.previewsContainer !== false) { + if (this.options.previewsContainer) { + this.previewsContainer = Dropzone.getElement(this.options.previewsContainer, "previewsContainer"); + } else { + this.previewsContainer = this.element; + } + } + if (this.options.clickable) { + if (this.options.clickable === true) { + this.clickableElements = [this.element]; + } else { + this.clickableElements = Dropzone.getElements(this.options.clickable, "clickable"); + } + } + this.init(); + } + + Dropzone.prototype.getAcceptedFiles = function() { + var file, j, len, ref, results; + ref = this.files; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + file = ref[j]; + if (file.accepted) { + results.push(file); + } + } + return results; + }; + + Dropzone.prototype.getRejectedFiles = function() { + var file, j, len, ref, results; + ref = this.files; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + file = ref[j]; + if (!file.accepted) { + results.push(file); + } + } + return results; + }; + + Dropzone.prototype.getFilesWithStatus = function(status) { + var file, j, len, ref, results; + ref = this.files; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + file = ref[j]; + if (file.status === status) { + results.push(file); + } + } + return results; + }; + + Dropzone.prototype.getQueuedFiles = function() { + return this.getFilesWithStatus(Dropzone.QUEUED); + }; + + Dropzone.prototype.getUploadingFiles = function() { + return this.getFilesWithStatus(Dropzone.UPLOADING); + }; + + Dropzone.prototype.getAddedFiles = function() { + return this.getFilesWithStatus(Dropzone.ADDED); + }; + + Dropzone.prototype.getActiveFiles = function() { + var file, j, len, ref, results; + ref = this.files; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + file = ref[j]; + if (file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED) { + results.push(file); + } + } + return results; + }; + + Dropzone.prototype.init = function() { + var eventName, j, len, noPropagation, ref, ref1, setupHiddenFileInput; + if (this.element.tagName === "form") { + this.element.setAttribute("enctype", "multipart/form-data"); + } + if (this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message")) { + this.element.appendChild(Dropzone.createElement("
" + this.options.dictDefaultMessage + "
")); + } + if (this.clickableElements.length) { + setupHiddenFileInput = (function(_this) { + return function() { + if (_this.hiddenFileInput) { + _this.hiddenFileInput.parentNode.removeChild(_this.hiddenFileInput); + } + _this.hiddenFileInput = document.createElement("input"); + _this.hiddenFileInput.setAttribute("type", "file"); + if ((_this.options.maxFiles == null) || _this.options.maxFiles > 1) { + _this.hiddenFileInput.setAttribute("multiple", "multiple"); + } + _this.hiddenFileInput.className = "dz-hidden-input"; + if (_this.options.acceptedFiles != null) { + _this.hiddenFileInput.setAttribute("accept", _this.options.acceptedFiles); + } + if (_this.options.capture != null) { + _this.hiddenFileInput.setAttribute("capture", _this.options.capture); + } + _this.hiddenFileInput.style.visibility = "hidden"; + _this.hiddenFileInput.style.position = "absolute"; + _this.hiddenFileInput.style.top = "0"; + _this.hiddenFileInput.style.left = "0"; + _this.hiddenFileInput.style.height = "0"; + _this.hiddenFileInput.style.width = "0"; + document.querySelector(_this.options.hiddenInputContainer).appendChild(_this.hiddenFileInput); + return _this.hiddenFileInput.addEventListener("change", function() { + var file, files, j, len; + files = _this.hiddenFileInput.files; + if (files.length) { + for (j = 0, len = files.length; j < len; j++) { + file = files[j]; + _this.addFile(file); + } + } + _this.emit("addedfiles", files); + return setupHiddenFileInput(); + }); + }; + })(this); + setupHiddenFileInput(); + } + this.URL = (ref = window.URL) != null ? ref : window.webkitURL; + ref1 = this.events; + for (j = 0, len = ref1.length; j < len; j++) { + eventName = ref1[j]; + this.on(eventName, this.options[eventName]); + } + this.on("uploadprogress", (function(_this) { + return function() { + return _this.updateTotalUploadProgress(); + }; + })(this)); + this.on("removedfile", (function(_this) { + return function() { + return _this.updateTotalUploadProgress(); + }; + })(this)); + this.on("canceled", (function(_this) { + return function(file) { + return _this.emit("complete", file); + }; + })(this)); + this.on("complete", (function(_this) { + return function(file) { + if (_this.getAddedFiles().length === 0 && _this.getUploadingFiles().length === 0 && _this.getQueuedFiles().length === 0) { + return setTimeout((function() { + return _this.emit("queuecomplete"); + }), 0); + } + }; + })(this)); + noPropagation = function(e) { + e.stopPropagation(); + if (e.preventDefault) { + return e.preventDefault(); + } else { + return e.returnValue = false; + } + }; + this.listeners = [ + { + element: this.element, + events: { + "dragstart": (function(_this) { + return function(e) { + return _this.emit("dragstart", e); + }; + })(this), + "dragenter": (function(_this) { + return function(e) { + noPropagation(e); + return _this.emit("dragenter", e); + }; + })(this), + "dragover": (function(_this) { + return function(e) { + var efct; + try { + efct = e.dataTransfer.effectAllowed; + } catch (undefined) {} + e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy'; + noPropagation(e); + return _this.emit("dragover", e); + }; + })(this), + "dragleave": (function(_this) { + return function(e) { + return _this.emit("dragleave", e); + }; + })(this), + "drop": (function(_this) { + return function(e) { + noPropagation(e); + return _this.drop(e); + }; + })(this), + "dragend": (function(_this) { + return function(e) { + return _this.emit("dragend", e); + }; + })(this) + } + } + ]; + this.clickableElements.forEach((function(_this) { + return function(clickableElement) { + return _this.listeners.push({ + element: clickableElement, + events: { + "click": function(evt) { + if ((clickableElement !== _this.element) || (evt.target === _this.element || Dropzone.elementInside(evt.target, _this.element.querySelector(".dz-message")))) { + _this.hiddenFileInput.click(); + } + return true; + } + } + }); + }; + })(this)); + this.enable(); + return this.options.init.call(this); + }; + + Dropzone.prototype.destroy = function() { + var ref; + this.disable(); + this.removeAllFiles(true); + if ((ref = this.hiddenFileInput) != null ? ref.parentNode : void 0) { + this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput); + this.hiddenFileInput = null; + } + delete this.element.dropzone; + return Dropzone.instances.splice(Dropzone.instances.indexOf(this), 1); + }; + + Dropzone.prototype.updateTotalUploadProgress = function() { + var activeFiles, file, j, len, ref, totalBytes, totalBytesSent, totalUploadProgress; + totalBytesSent = 0; + totalBytes = 0; + activeFiles = this.getActiveFiles(); + if (activeFiles.length) { + ref = this.getActiveFiles(); + for (j = 0, len = ref.length; j < len; j++) { + file = ref[j]; + totalBytesSent += file.upload.bytesSent; + totalBytes += file.upload.total; + } + totalUploadProgress = 100 * totalBytesSent / totalBytes; + } else { + totalUploadProgress = 100; + } + return this.emit("totaluploadprogress", totalUploadProgress, totalBytes, totalBytesSent); + }; + + Dropzone.prototype._getParamName = function(n) { + if (typeof this.options.paramName === "function") { + return this.options.paramName(n); + } else { + return "" + this.options.paramName + (this.options.uploadMultiple ? "[" + n + "]" : ""); + } + }; + + Dropzone.prototype._renameFile = function(file) { + if (typeof this.options.renameFile !== "function") { + return file.name; + } + return this.options.renameFile(file); + }; + + Dropzone.prototype.getFallbackForm = function() { + var existingFallback, fields, fieldsString, form; + if (existingFallback = this.getExistingFallback()) { + return existingFallback; + } + fieldsString = "
"; + if (this.options.dictFallbackText) { + fieldsString += "

" + this.options.dictFallbackText + "

"; + } + fieldsString += "
"; + fields = Dropzone.createElement(fieldsString); + if (this.element.tagName !== "FORM") { + form = Dropzone.createElement("
"); + form.appendChild(fields); + } else { + this.element.setAttribute("enctype", "multipart/form-data"); + this.element.setAttribute("method", this.options.method); + } + return form != null ? form : fields; + }; + + Dropzone.prototype.getExistingFallback = function() { + var fallback, getFallback, j, len, ref, tagName; + getFallback = function(elements) { + var el, j, len; + for (j = 0, len = elements.length; j < len; j++) { + el = elements[j]; + if (/(^| )fallback($| )/.test(el.className)) { + return el; + } + } + }; + ref = ["div", "form"]; + for (j = 0, len = ref.length; j < len; j++) { + tagName = ref[j]; + if (fallback = getFallback(this.element.getElementsByTagName(tagName))) { + return fallback; + } + } + }; + + Dropzone.prototype.setupEventListeners = function() { + var elementListeners, event, j, len, listener, ref, results; + ref = this.listeners; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + elementListeners = ref[j]; + results.push((function() { + var ref1, results1; + ref1 = elementListeners.events; + results1 = []; + for (event in ref1) { + listener = ref1[event]; + results1.push(elementListeners.element.addEventListener(event, listener, false)); + } + return results1; + })()); + } + return results; + }; + + Dropzone.prototype.removeEventListeners = function() { + var elementListeners, event, j, len, listener, ref, results; + ref = this.listeners; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + elementListeners = ref[j]; + results.push((function() { + var ref1, results1; + ref1 = elementListeners.events; + results1 = []; + for (event in ref1) { + listener = ref1[event]; + results1.push(elementListeners.element.removeEventListener(event, listener, false)); + } + return results1; + })()); + } + return results; + }; + + Dropzone.prototype.disable = function() { + var file, j, len, ref, results; + this.clickableElements.forEach(function(element) { + return element.classList.remove("dz-clickable"); + }); + this.removeEventListeners(); + ref = this.files; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + file = ref[j]; + results.push(this.cancelUpload(file)); + } + return results; + }; + + Dropzone.prototype.enable = function() { + this.clickableElements.forEach(function(element) { + return element.classList.add("dz-clickable"); + }); + return this.setupEventListeners(); + }; + + Dropzone.prototype.filesize = function(size) { + var cutoff, i, j, len, selectedSize, selectedUnit, unit, units; + selectedSize = 0; + selectedUnit = "b"; + if (size > 0) { + units = ['tb', 'gb', 'mb', 'kb', 'b']; + for (i = j = 0, len = units.length; j < len; i = ++j) { + unit = units[i]; + cutoff = Math.pow(this.options.filesizeBase, 4 - i) / 10; + if (size >= cutoff) { + selectedSize = size / Math.pow(this.options.filesizeBase, 4 - i); + selectedUnit = unit; + break; + } + } + selectedSize = Math.round(10 * selectedSize) / 10; + } + return "" + selectedSize + " " + this.options.dictFileSizeUnits[selectedUnit]; + }; + + Dropzone.prototype._updateMaxFilesReachedClass = function() { + if ((this.options.maxFiles != null) && this.getAcceptedFiles().length >= this.options.maxFiles) { + if (this.getAcceptedFiles().length === this.options.maxFiles) { + this.emit('maxfilesreached', this.files); + } + return this.element.classList.add("dz-max-files-reached"); + } else { + return this.element.classList.remove("dz-max-files-reached"); + } + }; + + Dropzone.prototype.drop = function(e) { + var files, items; + if (!e.dataTransfer) { + return; + } + this.emit("drop", e); + files = e.dataTransfer.files; + this.emit("addedfiles", files); + if (files.length) { + items = e.dataTransfer.items; + if (items && items.length && (items[0].webkitGetAsEntry != null)) { + this._addFilesFromItems(items); + } else { + this.handleFiles(files); + } + } + }; + + Dropzone.prototype.paste = function(e) { + var items, ref; + if ((e != null ? (ref = e.clipboardData) != null ? ref.items : void 0 : void 0) == null) { + return; + } + this.emit("paste", e); + items = e.clipboardData.items; + if (items.length) { + return this._addFilesFromItems(items); + } + }; + + Dropzone.prototype.handleFiles = function(files) { + var file, j, len, results; + results = []; + for (j = 0, len = files.length; j < len; j++) { + file = files[j]; + results.push(this.addFile(file)); + } + return results; + }; + + Dropzone.prototype._addFilesFromItems = function(items) { + var entry, item, j, len, results; + results = []; + for (j = 0, len = items.length; j < len; j++) { + item = items[j]; + if ((item.webkitGetAsEntry != null) && (entry = item.webkitGetAsEntry())) { + if (entry.isFile) { + results.push(this.addFile(item.getAsFile())); + } else if (entry.isDirectory) { + results.push(this._addFilesFromDirectory(entry, entry.name)); + } else { + results.push(void 0); + } + } else if (item.getAsFile != null) { + if ((item.kind == null) || item.kind === "file") { + results.push(this.addFile(item.getAsFile())); + } else { + results.push(void 0); + } + } else { + results.push(void 0); + } + } + return results; + }; + + Dropzone.prototype._addFilesFromDirectory = function(directory, path) { + var dirReader, errorHandler, readEntries; + dirReader = directory.createReader(); + errorHandler = function(error) { + return typeof console !== "undefined" && console !== null ? typeof console.log === "function" ? console.log(error) : void 0 : void 0; + }; + readEntries = (function(_this) { + return function() { + return dirReader.readEntries(function(entries) { + var entry, j, len; + if (entries.length > 0) { + for (j = 0, len = entries.length; j < len; j++) { + entry = entries[j]; + if (entry.isFile) { + entry.file(function(file) { + if (_this.options.ignoreHiddenFiles && file.name.substring(0, 1) === '.') { + return; + } + file.fullPath = path + "/" + file.name; + return _this.addFile(file); + }); + } else if (entry.isDirectory) { + _this._addFilesFromDirectory(entry, path + "/" + entry.name); + } + } + readEntries(); + } + return null; + }, errorHandler); + }; + })(this); + return readEntries(); + }; + + Dropzone.prototype.accept = function(file, done) { + if (file.size > this.options.maxFilesize * 1024 * 1024) { + return done(this.options.dictFileTooBig.replace("{{filesize}}", Math.round(file.size / 1024 / 10.24) / 100).replace("{{maxFilesize}}", this.options.maxFilesize)); + } else if (!Dropzone.isValidFile(file, this.options.acceptedFiles)) { + return done(this.options.dictInvalidFileType); + } else if ((this.options.maxFiles != null) && this.getAcceptedFiles().length >= this.options.maxFiles) { + done(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}", this.options.maxFiles)); + return this.emit("maxfilesexceeded", file); + } else { + return this.options.accept.call(this, file, done); + } + }; + + Dropzone.prototype.addFile = function(file) { + file.upload = { + progress: 0, + total: file.size, + bytesSent: 0, + filename: this._renameFile(file) + }; + this.files.push(file); + file.status = Dropzone.ADDED; + this.emit("addedfile", file); + this._enqueueThumbnail(file); + return this.accept(file, (function(_this) { + return function(error) { + if (error) { + file.accepted = false; + _this._errorProcessing([file], error); + } else { + file.accepted = true; + if (_this.options.autoQueue) { + _this.enqueueFile(file); + } + } + return _this._updateMaxFilesReachedClass(); + }; + })(this)); + }; + + Dropzone.prototype.enqueueFiles = function(files) { + var file, j, len; + for (j = 0, len = files.length; j < len; j++) { + file = files[j]; + this.enqueueFile(file); + } + return null; + }; + + Dropzone.prototype.enqueueFile = function(file) { + if (file.status === Dropzone.ADDED && file.accepted === true) { + file.status = Dropzone.QUEUED; + if (this.options.autoProcessQueue) { + return setTimeout(((function(_this) { + return function() { + return _this.processQueue(); + }; + })(this)), 0); + } + } else { + throw new Error("This file can't be queued because it has already been processed or was rejected."); + } + }; + + Dropzone.prototype._thumbnailQueue = []; + + Dropzone.prototype._processingThumbnail = false; + + Dropzone.prototype._enqueueThumbnail = function(file) { + if (this.options.createImageThumbnails && file.type.match(/image.*/) && file.size <= this.options.maxThumbnailFilesize * 1024 * 1024) { + this._thumbnailQueue.push(file); + return setTimeout(((function(_this) { + return function() { + return _this._processThumbnailQueue(); + }; + })(this)), 0); + } + }; + + Dropzone.prototype._processThumbnailQueue = function() { + var file; + if (this._processingThumbnail || this._thumbnailQueue.length === 0) { + return; + } + this._processingThumbnail = true; + file = this._thumbnailQueue.shift(); + return this.createThumbnail(file, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, true, (function(_this) { + return function(dataUrl) { + _this.emit("thumbnail", file, dataUrl); + _this._processingThumbnail = false; + return _this._processThumbnailQueue(); + }; + })(this)); + }; + + Dropzone.prototype.removeFile = function(file) { + if (file.status === Dropzone.UPLOADING) { + this.cancelUpload(file); + } + this.files = without(this.files, file); + this.emit("removedfile", file); + if (this.files.length === 0) { + return this.emit("reset"); + } + }; + + Dropzone.prototype.removeAllFiles = function(cancelIfNecessary) { + var file, j, len, ref; + if (cancelIfNecessary == null) { + cancelIfNecessary = false; + } + ref = this.files.slice(); + for (j = 0, len = ref.length; j < len; j++) { + file = ref[j]; + if (file.status !== Dropzone.UPLOADING || cancelIfNecessary) { + this.removeFile(file); + } + } + return null; + }; + + Dropzone.prototype.resizeImage = function(file, width, height, resizeMethod, callback) { + return this.createThumbnail(file, width, height, resizeMethod, false, (function(_this) { + return function(dataUrl, canvas) { + var resizeMimeType, resizedDataURL; + if (canvas === null) { + return callback(file); + } else { + resizeMimeType = _this.options.resizeMimeType; + if (resizeMimeType == null) { + resizeMimeType = file.type; + } + resizedDataURL = canvas.toDataURL(resizeMimeType, _this.options.resizeQuality); + if (resizeMimeType === 'image/jpeg' || resizeMimeType === 'image/jpg') { + resizedDataURL = ExifRestore.restore(file.dataURL, resizedDataURL); + } + return callback(Dropzone.dataURItoBlob(resizedDataURL)); + } + }; + })(this)); + }; + + Dropzone.prototype.createThumbnail = function(file, width, height, resizeMethod, fixOrientation, callback) { + var fileReader; + fileReader = new FileReader; + fileReader.onload = (function(_this) { + return function() { + file.dataURL = fileReader.result; + if (file.type === "image/svg+xml") { + if (callback != null) { + callback(fileReader.result); + } + return; + } + return _this.createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback); + }; + })(this); + return fileReader.readAsDataURL(file); + }; + + Dropzone.prototype.createThumbnailFromUrl = function(file, width, height, resizeMethod, fixOrientation, callback, crossOrigin) { + var img; + img = document.createElement("img"); + if (crossOrigin) { + img.crossOrigin = crossOrigin; + } + img.onload = (function(_this) { + return function() { + var loadExif; + loadExif = function(callback) { + return callback(1); + }; + if ((typeof EXIF !== "undefined" && EXIF !== null) && fixOrientation) { + loadExif = function(callback) { + return EXIF.getData(img, function() { + return callback(EXIF.getTag(this, 'Orientation')); + }); + }; + } + return loadExif(function(orientation) { + var canvas, ctx, ref, ref1, ref2, ref3, resizeInfo, thumbnail; + file.width = img.width; + file.height = img.height; + resizeInfo = _this.options.resize.call(_this, file, width, height, resizeMethod); + canvas = document.createElement("canvas"); + ctx = canvas.getContext("2d"); + canvas.width = resizeInfo.trgWidth; + canvas.height = resizeInfo.trgHeight; + if (orientation > 4) { + canvas.width = resizeInfo.trgHeight; + canvas.height = resizeInfo.trgWidth; + } + switch (orientation) { + case 2: + ctx.translate(canvas.width, 0); + ctx.scale(-1, 1); + break; + case 3: + ctx.translate(canvas.width, canvas.height); + ctx.rotate(Math.PI); + break; + case 4: + ctx.translate(0, canvas.height); + ctx.scale(1, -1); + break; + case 5: + ctx.rotate(0.5 * Math.PI); + ctx.scale(1, -1); + break; + case 6: + ctx.rotate(0.5 * Math.PI); + ctx.translate(0, -canvas.height); + break; + case 7: + ctx.rotate(0.5 * Math.PI); + ctx.translate(canvas.width, -canvas.height); + ctx.scale(-1, 1); + break; + case 8: + ctx.rotate(-0.5 * Math.PI); + ctx.translate(-canvas.width, 0); + } + drawImageIOSFix(ctx, img, (ref = resizeInfo.srcX) != null ? ref : 0, (ref1 = resizeInfo.srcY) != null ? ref1 : 0, resizeInfo.srcWidth, resizeInfo.srcHeight, (ref2 = resizeInfo.trgX) != null ? ref2 : 0, (ref3 = resizeInfo.trgY) != null ? ref3 : 0, resizeInfo.trgWidth, resizeInfo.trgHeight); + thumbnail = canvas.toDataURL("image/png"); + if (callback != null) { + return callback(thumbnail, canvas); + } + }); + }; + })(this); + if (callback != null) { + img.onerror = callback; + } + return img.src = file.dataURL; + }; + + Dropzone.prototype.processQueue = function() { + var i, parallelUploads, processingLength, queuedFiles; + parallelUploads = this.options.parallelUploads; + processingLength = this.getUploadingFiles().length; + i = processingLength; + if (processingLength >= parallelUploads) { + return; + } + queuedFiles = this.getQueuedFiles(); + if (!(queuedFiles.length > 0)) { + return; + } + if (this.options.uploadMultiple) { + return this.processFiles(queuedFiles.slice(0, parallelUploads - processingLength)); + } else { + while (i < parallelUploads) { + if (!queuedFiles.length) { + return; + } + this.processFile(queuedFiles.shift()); + i++; + } + } + }; + + Dropzone.prototype.processFile = function(file) { + return this.processFiles([file]); + }; + + Dropzone.prototype.processFiles = function(files) { + var file, j, len; + for (j = 0, len = files.length; j < len; j++) { + file = files[j]; + file.processing = true; + file.status = Dropzone.UPLOADING; + this.emit("processing", file); + } + if (this.options.uploadMultiple) { + this.emit("processingmultiple", files); + } + return this.uploadFiles(files); + }; + + Dropzone.prototype._getFilesWithXhr = function(xhr) { + var file, files; + return files = (function() { + var j, len, ref, results; + ref = this.files; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + file = ref[j]; + if (file.xhr === xhr) { + results.push(file); + } + } + return results; + }).call(this); + }; + + Dropzone.prototype.cancelUpload = function(file) { + var groupedFile, groupedFiles, j, k, len, len1, ref; + if (file.status === Dropzone.UPLOADING) { + groupedFiles = this._getFilesWithXhr(file.xhr); + for (j = 0, len = groupedFiles.length; j < len; j++) { + groupedFile = groupedFiles[j]; + groupedFile.status = Dropzone.CANCELED; + } + file.xhr.abort(); + for (k = 0, len1 = groupedFiles.length; k < len1; k++) { + groupedFile = groupedFiles[k]; + this.emit("canceled", groupedFile); + } + if (this.options.uploadMultiple) { + this.emit("canceledmultiple", groupedFiles); + } + } else if ((ref = file.status) === Dropzone.ADDED || ref === Dropzone.QUEUED) { + file.status = Dropzone.CANCELED; + this.emit("canceled", file); + if (this.options.uploadMultiple) { + this.emit("canceledmultiple", [file]); + } + } + if (this.options.autoProcessQueue) { + return this.processQueue(); + } + }; + + resolveOption = function() { + var args, option; + option = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + if (typeof option === 'function') { + return option.apply(this, args); + } + return option; + }; + + Dropzone.prototype.uploadFile = function(file) { + return this.uploadFiles([file]); + }; + + Dropzone.prototype.uploadFiles = function(files) { + var doneCounter, doneFunction, file, formData, handleError, headerName, headerValue, headers, i, input, inputName, inputType, j, k, key, l, len, len1, len2, len3, m, method, o, option, progressObj, ref, ref1, ref2, ref3, ref4, ref5, response, results, updateProgress, url, value, xhr; + xhr = new XMLHttpRequest(); + for (j = 0, len = files.length; j < len; j++) { + file = files[j]; + file.xhr = xhr; + } + method = resolveOption(this.options.method, files); + url = resolveOption(this.options.url, files); + xhr.open(method, url, true); + xhr.timeout = resolveOption(this.options.timeout, files); + xhr.withCredentials = !!this.options.withCredentials; + response = null; + handleError = (function(_this) { + return function() { + var k, len1, results; + results = []; + for (k = 0, len1 = files.length; k < len1; k++) { + file = files[k]; + results.push(_this._errorProcessing(files, response || _this.options.dictResponseError.replace("{{statusCode}}", xhr.status), xhr)); + } + return results; + }; + })(this); + updateProgress = (function(_this) { + return function(e) { + var allFilesFinished, k, l, len1, len2, len3, m, progress, results; + if (e != null) { + progress = 100 * e.loaded / e.total; + for (k = 0, len1 = files.length; k < len1; k++) { + file = files[k]; + file.upload.progress = progress; + file.upload.total = e.total; + file.upload.bytesSent = e.loaded; + } + } else { + allFilesFinished = true; + progress = 100; + for (l = 0, len2 = files.length; l < len2; l++) { + file = files[l]; + if (!(file.upload.progress === 100 && file.upload.bytesSent === file.upload.total)) { + allFilesFinished = false; + } + file.upload.progress = progress; + file.upload.bytesSent = file.upload.total; + } + if (allFilesFinished) { + return; + } + } + results = []; + for (m = 0, len3 = files.length; m < len3; m++) { + file = files[m]; + results.push(_this.emit("uploadprogress", file, progress, file.upload.bytesSent)); + } + return results; + }; + })(this); + xhr.onload = (function(_this) { + return function(e) { + var error1, ref; + if (files[0].status === Dropzone.CANCELED) { + return; + } + if (xhr.readyState !== 4) { + return; + } + if (xhr.responseType !== 'arraybuffer' && xhr.responseType !== 'blob') { + response = xhr.responseText; + if (xhr.getResponseHeader("content-type") && ~xhr.getResponseHeader("content-type").indexOf("application/json")) { + try { + response = JSON.parse(response); + } catch (error1) { + e = error1; + response = "Invalid JSON response from server."; + } + } + } + updateProgress(); + if (!((200 <= (ref = xhr.status) && ref < 300))) { + return handleError(); + } else { + return _this._finished(files, response, e); + } + }; + })(this); + xhr.onerror = (function(_this) { + return function() { + if (files[0].status === Dropzone.CANCELED) { + return; + } + return handleError(); + }; + })(this); + progressObj = (ref = xhr.upload) != null ? ref : xhr; + progressObj.onprogress = updateProgress; + headers = { + "Accept": "application/json", + "Cache-Control": "no-cache", + "X-Requested-With": "XMLHttpRequest" + }; + if (this.options.headers) { + extend(headers, this.options.headers); + } + for (headerName in headers) { + headerValue = headers[headerName]; + if (headerValue) { + xhr.setRequestHeader(headerName, headerValue); + } + } + formData = new FormData(); + if (this.options.params) { + ref1 = this.options.params; + for (key in ref1) { + value = ref1[key]; + formData.append(key, value); + } + } + for (k = 0, len1 = files.length; k < len1; k++) { + file = files[k]; + this.emit("sending", file, xhr, formData); + } + if (this.options.uploadMultiple) { + this.emit("sendingmultiple", files, xhr, formData); + } + if (this.element.tagName === "FORM") { + ref2 = this.element.querySelectorAll("input, textarea, select, button"); + for (l = 0, len2 = ref2.length; l < len2; l++) { + input = ref2[l]; + inputName = input.getAttribute("name"); + inputType = input.getAttribute("type"); + if (input.tagName === "SELECT" && input.hasAttribute("multiple")) { + ref3 = input.options; + for (m = 0, len3 = ref3.length; m < len3; m++) { + option = ref3[m]; + if (option.selected) { + formData.append(inputName, option.value); + } + } + } else if (!inputType || ((ref4 = inputType.toLowerCase()) !== "checkbox" && ref4 !== "radio") || input.checked) { + formData.append(inputName, input.value); + } + } + } + doneCounter = 0; + results = []; + for (i = o = 0, ref5 = files.length - 1; 0 <= ref5 ? o <= ref5 : o >= ref5; i = 0 <= ref5 ? ++o : --o) { + doneFunction = (function(_this) { + return function(file, paramName, fileName) { + return function(transformedFile) { + formData.append(paramName, transformedFile, fileName); + if (++doneCounter === files.length) { + return _this.submitRequest(xhr, formData, files); + } + }; + }; + })(this); + results.push(this.options.transformFile.call(this, files[i], doneFunction(files[i], this._getParamName(i), files[i].upload.filename))); + } + return results; + }; + + Dropzone.prototype.submitRequest = function(xhr, formData, files) { + return xhr.send(formData); + }; + + Dropzone.prototype._finished = function(files, responseText, e) { + var file, j, len; + for (j = 0, len = files.length; j < len; j++) { + file = files[j]; + file.status = Dropzone.SUCCESS; + this.emit("success", file, responseText, e); + this.emit("complete", file); + } + if (this.options.uploadMultiple) { + this.emit("successmultiple", files, responseText, e); + this.emit("completemultiple", files); + } + if (this.options.autoProcessQueue) { + return this.processQueue(); + } + }; + + Dropzone.prototype._errorProcessing = function(files, message, xhr) { + var file, j, len; + for (j = 0, len = files.length; j < len; j++) { + file = files[j]; + file.status = Dropzone.ERROR; + this.emit("error", file, message, xhr); + this.emit("complete", file); + } + if (this.options.uploadMultiple) { + this.emit("errormultiple", files, message, xhr); + this.emit("completemultiple", files); + } + if (this.options.autoProcessQueue) { + return this.processQueue(); + } + }; + + return Dropzone; + + })(Emitter); + + Dropzone.version = "5.1.1"; + + Dropzone.options = {}; + + Dropzone.optionsForElement = function(element) { + if (element.getAttribute("id")) { + return Dropzone.options[camelize(element.getAttribute("id"))]; + } else { + return void 0; + } + }; + + Dropzone.instances = []; + + Dropzone.forElement = function(element) { + if (typeof element === "string") { + element = document.querySelector(element); + } + if ((element != null ? element.dropzone : void 0) == null) { + throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone."); + } + return element.dropzone; + }; + + Dropzone.autoDiscover = true; + + Dropzone.discover = function() { + var checkElements, dropzone, dropzones, j, len, results; + if (document.querySelectorAll) { + dropzones = document.querySelectorAll(".dropzone"); + } else { + dropzones = []; + checkElements = function(elements) { + var el, j, len, results; + results = []; + for (j = 0, len = elements.length; j < len; j++) { + el = elements[j]; + if (/(^| )dropzone($| )/.test(el.className)) { + results.push(dropzones.push(el)); + } else { + results.push(void 0); + } + } + return results; + }; + checkElements(document.getElementsByTagName("div")); + checkElements(document.getElementsByTagName("form")); + } + results = []; + for (j = 0, len = dropzones.length; j < len; j++) { + dropzone = dropzones[j]; + if (Dropzone.optionsForElement(dropzone) !== false) { + results.push(new Dropzone(dropzone)); + } else { + results.push(void 0); + } + } + return results; + }; + + Dropzone.blacklistedBrowsers = [/opera.*Macintosh.*version\/12/i]; + + Dropzone.isBrowserSupported = function() { + var capableBrowser, j, len, ref, regex; + capableBrowser = true; + if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) { + if (!("classList" in document.createElement("a"))) { + capableBrowser = false; + } else { + ref = Dropzone.blacklistedBrowsers; + for (j = 0, len = ref.length; j < len; j++) { + regex = ref[j]; + if (regex.test(navigator.userAgent)) { + capableBrowser = false; + continue; + } + } + } + } else { + capableBrowser = false; + } + return capableBrowser; + }; + + Dropzone.dataURItoBlob = function(dataURI) { + var ab, byteString, i, ia, j, mimeString, ref; + byteString = atob(dataURI.split(',')[1]); + mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; + ab = new ArrayBuffer(byteString.length); + ia = new Uint8Array(ab); + for (i = j = 0, ref = byteString.length; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) { + ia[i] = byteString.charCodeAt(i); + } + return new Blob([ab], { + type: mimeString + }); + }; + + without = function(list, rejectedItem) { + var item, j, len, results; + results = []; + for (j = 0, len = list.length; j < len; j++) { + item = list[j]; + if (item !== rejectedItem) { + results.push(item); + } + } + return results; + }; + + camelize = function(str) { + return str.replace(/[\-_](\w)/g, function(match) { + return match.charAt(1).toUpperCase(); + }); + }; + + Dropzone.createElement = function(string) { + var div; + div = document.createElement("div"); + div.innerHTML = string; + return div.childNodes[0]; + }; + + Dropzone.elementInside = function(element, container) { + if (element === container) { + return true; + } + while (element = element.parentNode) { + if (element === container) { + return true; + } + } + return false; + }; + + Dropzone.getElement = function(el, name) { + var element; + if (typeof el === "string") { + element = document.querySelector(el); + } else if (el.nodeType != null) { + element = el; + } + if (element == null) { + throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector or a plain HTML element."); + } + return element; + }; + + Dropzone.getElements = function(els, name) { + var e, el, elements, error1, j, k, len, len1, ref; + if (els instanceof Array) { + elements = []; + try { + for (j = 0, len = els.length; j < len; j++) { + el = els[j]; + elements.push(this.getElement(el, name)); + } + } catch (error1) { + e = error1; + elements = null; + } + } else if (typeof els === "string") { + elements = []; + ref = document.querySelectorAll(els); + for (k = 0, len1 = ref.length; k < len1; k++) { + el = ref[k]; + elements.push(el); + } + } else if (els.nodeType != null) { + elements = [els]; + } + if (!((elements != null) && elements.length)) { + throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector, a plain HTML element or a list of those."); + } + return elements; + }; + + Dropzone.confirm = function(question, accepted, rejected) { + if (window.confirm(question)) { + return accepted(); + } else if (rejected != null) { + return rejected(); + } + }; + + Dropzone.isValidFile = function(file, acceptedFiles) { + var baseMimeType, j, len, mimeType, validType; + if (!acceptedFiles) { + return true; + } + acceptedFiles = acceptedFiles.split(","); + mimeType = file.type; + baseMimeType = mimeType.replace(/\/.*$/, ""); + for (j = 0, len = acceptedFiles.length; j < len; j++) { + validType = acceptedFiles[j]; + validType = validType.trim(); + if (validType.charAt(0) === ".") { + if (file.name.toLowerCase().indexOf(validType.toLowerCase(), file.name.length - validType.length) !== -1) { + return true; + } + } else if (/\/\*$/.test(validType)) { + if (baseMimeType === validType.replace(/\/.*$/, "")) { + return true; + } + } else { + if (mimeType === validType) { + return true; + } + } + } + return false; + }; + + if (typeof jQuery !== "undefined" && jQuery !== null) { + jQuery.fn.dropzone = function(options) { + return this.each(function() { + return new Dropzone(this, options); + }); + }; + } + + if (typeof module !== "undefined" && module !== null) { + module.exports = Dropzone; + } else { + window.Dropzone = Dropzone; + } + + Dropzone.ADDED = "added"; + + Dropzone.QUEUED = "queued"; + + Dropzone.ACCEPTED = Dropzone.QUEUED; + + Dropzone.UPLOADING = "uploading"; + + Dropzone.PROCESSING = Dropzone.UPLOADING; + + Dropzone.CANCELED = "canceled"; + + Dropzone.ERROR = "error"; + + Dropzone.SUCCESS = "success"; + + + /* + + Bugfix for iOS 6 and 7 + Source: http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios + based on the work of https://github.com/stomita/ios-imagefile-megapixel + */ + + detectVerticalSquash = function(img) { + var alpha, canvas, ctx, data, ey, ih, iw, py, ratio, sy; + iw = img.naturalWidth; + ih = img.naturalHeight; + canvas = document.createElement("canvas"); + canvas.width = 1; + canvas.height = ih; + ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0); + data = ctx.getImageData(1, 0, 1, ih).data; + sy = 0; + ey = ih; + py = ih; + while (py > sy) { + alpha = data[(py - 1) * 4 + 3]; + if (alpha === 0) { + ey = py; + } else { + sy = py; + } + py = (ey + sy) >> 1; + } + ratio = py / ih; + if (ratio === 0) { + return 1; + } else { + return ratio; + } + }; + + drawImageIOSFix = function(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { + var vertSquashRatio; + vertSquashRatio = detectVerticalSquash(img); + return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio); + }; + + ExifRestore = (function() { + function ExifRestore() {} + + ExifRestore.KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + + ExifRestore.encode64 = function(input) { + var chr1, chr2, chr3, enc1, enc2, enc3, enc4, i, output; + output = ''; + chr1 = void 0; + chr2 = void 0; + chr3 = ''; + enc1 = void 0; + enc2 = void 0; + enc3 = void 0; + enc4 = ''; + i = 0; + while (true) { + chr1 = input[i++]; + chr2 = input[i++]; + chr3 = input[i++]; + enc1 = chr1 >> 2; + enc2 = (chr1 & 3) << 4 | chr2 >> 4; + enc3 = (chr2 & 15) << 2 | chr3 >> 6; + enc4 = chr3 & 63; + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4); + chr1 = chr2 = chr3 = ''; + enc1 = enc2 = enc3 = enc4 = ''; + if (!(i < input.length)) { + break; + } + } + return output; + }; + + ExifRestore.restore = function(origFileBase64, resizedFileBase64) { + var image, rawImage, segments; + if (!origFileBase64.match('data:image/jpeg;base64,')) { + return resizedFileBase64; + } + rawImage = this.decode64(origFileBase64.replace('data:image/jpeg;base64,', '')); + segments = this.slice2Segments(rawImage); + image = this.exifManipulation(resizedFileBase64, segments); + return 'data:image/jpeg;base64,' + this.encode64(image); + }; + + ExifRestore.exifManipulation = function(resizedFileBase64, segments) { + var aBuffer, exifArray, newImageArray; + exifArray = this.getExifArray(segments); + newImageArray = this.insertExif(resizedFileBase64, exifArray); + aBuffer = new Uint8Array(newImageArray); + return aBuffer; + }; + + ExifRestore.getExifArray = function(segments) { + var seg, x; + seg = void 0; + x = 0; + while (x < segments.length) { + seg = segments[x]; + if (seg[0] === 255 & seg[1] === 225) { + return seg; + } + x++; + } + return []; + }; + + ExifRestore.insertExif = function(resizedFileBase64, exifArray) { + var array, ato, buf, imageData, mae, separatePoint; + imageData = resizedFileBase64.replace('data:image/jpeg;base64,', ''); + buf = this.decode64(imageData); + separatePoint = buf.indexOf(255, 3); + mae = buf.slice(0, separatePoint); + ato = buf.slice(separatePoint); + array = mae; + array = array.concat(exifArray); + array = array.concat(ato); + return array; + }; + + ExifRestore.slice2Segments = function(rawImageArray) { + var endPoint, head, length, seg, segments; + head = 0; + segments = []; + while (true) { + if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 218) { + break; + } + if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 216) { + head += 2; + } else { + length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3]; + endPoint = head + length + 2; + seg = rawImageArray.slice(head, endPoint); + segments.push(seg); + head = endPoint; + } + if (head > rawImageArray.length) { + break; + } + } + return segments; + }; + + ExifRestore.decode64 = function(input) { + var base64test, buf, chr1, chr2, chr3, enc1, enc2, enc3, enc4, i, output; + output = ''; + chr1 = void 0; + chr2 = void 0; + chr3 = ''; + enc1 = void 0; + enc2 = void 0; + enc3 = void 0; + enc4 = ''; + i = 0; + buf = []; + base64test = /[^A-Za-z0-9\+\/\=]/g; + if (base64test.exec(input)) { + console.warning('There were invalid base64 characters in the input text.\n' + 'Valid base64 characters are A-Z, a-z, 0-9, \'+\', \'/\',and \'=\'\n' + 'Expect errors in decoding.'); + } + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); + while (true) { + enc1 = this.KEY_STR.indexOf(input.charAt(i++)); + enc2 = this.KEY_STR.indexOf(input.charAt(i++)); + enc3 = this.KEY_STR.indexOf(input.charAt(i++)); + enc4 = this.KEY_STR.indexOf(input.charAt(i++)); + chr1 = enc1 << 2 | enc2 >> 4; + chr2 = (enc2 & 15) << 4 | enc3 >> 2; + chr3 = (enc3 & 3) << 6 | enc4; + buf.push(chr1); + if (enc3 !== 64) { + buf.push(chr2); + } + if (enc4 !== 64) { + buf.push(chr3); + } + chr1 = chr2 = chr3 = ''; + enc1 = enc2 = enc3 = enc4 = ''; + if (!(i < input.length)) { + break; + } + } + return buf; + }; + + return ExifRestore; + + })(); + + + /* + * contentloaded.js + * + * Author: Diego Perini (diego.perini at gmail.com) + * Summary: cross-browser wrapper for DOMContentLoaded + * Updated: 20101020 + * License: MIT + * Version: 1.2 + * + * URL: + * http://javascript.nwbox.com/ContentLoaded/ + * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE + */ + + contentLoaded = function(win, fn) { + var add, doc, done, init, poll, pre, rem, root, top; + done = false; + top = true; + doc = win.document; + root = doc.documentElement; + add = (doc.addEventListener ? "addEventListener" : "attachEvent"); + rem = (doc.addEventListener ? "removeEventListener" : "detachEvent"); + pre = (doc.addEventListener ? "" : "on"); + init = function(e) { + if (e.type === "readystatechange" && doc.readyState !== "complete") { + return; + } + (e.type === "load" ? win : doc)[rem](pre + e.type, init, false); + if (!done && (done = true)) { + return fn.call(win, e.type || e); + } + }; + poll = function() { + var e, error1; + try { + root.doScroll("left"); + } catch (error1) { + e = error1; + setTimeout(poll, 50); + return; + } + return init("poll"); + }; + if (doc.readyState !== "complete") { + if (doc.createEventObject && root.doScroll) { + try { + top = !win.frameElement; + } catch (undefined) {} + if (top) { + poll(); + } + } + doc[add](pre + "DOMContentLoaded", init, false); + doc[add](pre + "readystatechange", init, false); + return win[add](pre + "load", init, false); + } + }; + + Dropzone._autoDiscoverFunction = function() { + if (Dropzone.autoDiscover) { + return Dropzone.discover(); + } + }; + + contentLoaded(window, Dropzone._autoDiscoverFunction); + +}).call(this); diff --git a/_examples/tutorial/dropzonejs/src/views/upload.html b/_examples/tutorial/dropzonejs/src/views/upload.html new file mode 100644 index 00000000..d7f00987 --- /dev/null +++ b/_examples/tutorial/dropzonejs/src/views/upload.html @@ -0,0 +1,53 @@ + + + + DropzoneJS Uploader + + + + + + + + + + + + + + + +
+
+ + +
+
+ + + \ No newline at end of file diff --git a/_examples/tutorial/dropzonejs/with_files.png b/_examples/tutorial/dropzonejs/with_files.png new file mode 100644 index 0000000000000000000000000000000000000000..2b6f3cdc7b9b4c24b6675d7f50433d4954c9e3c8 GIT binary patch literal 42036 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