Permalink
Browse files

Initial commit to multiuploader.

  • Loading branch information...
0 parents commit 6f07287001c5891e5b6f0bcc5c6cc81293c5bce2 @RISCfuture committed with Apr 21, 2012
5 .document
@@ -0,0 +1,5 @@
+lib/**/*.rb
+bin/*
+-
+features/**/*.feature
+LICENSE.txt
49 .gitignore
@@ -0,0 +1,49 @@
+# rcov generated
+coverage
+coverage.data
+
+# rdoc generated
+rdoc
+
+# yard generated
+doc
+.yardoc
+
+# bundler
+.bundle
+
+# jeweler generated
+pkg
+
+# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
+#
+# * Create a file at ~/.gitignore
+# * Include files you want ignored
+# * Run: git config --global core.excludesfile ~/.gitignore
+#
+# After doing this, these files will be ignored in all your git projects,
+# saving you from having to 'pollute' every project you touch with them
+#
+# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
+#
+# For MacOS:
+#
+#.DS_Store
+
+# For TextMate
+#*.tmproj
+#tmtags
+
+# For emacs:
+#*~
+#\#*
+#.\#*
+
+# For vim:
+#*.swp
+
+# For redcar:
+#.redcar
+
+# For rubinius:
+#*.rbc
1 .rvmrc
@@ -0,0 +1 @@
+rvm 1.9.3@multiuploader --create
15 Gemfile
@@ -0,0 +1,15 @@
+source :rubygems
+
+gem 'rails'
+gem 'compass'
+gem 'jquery-rails'
+
+group :development do
+ # DOCS
+ gem 'yard'
+ gem 'redcarpet'
+
+ # DEVELOPMENT
+ gem 'bundler'
+ gem 'jeweler'
+end
109 Gemfile.lock
@@ -0,0 +1,109 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ actionmailer (3.2.3)
+ actionpack (= 3.2.3)
+ mail (~> 2.4.4)
+ actionpack (3.2.3)
+ activemodel (= 3.2.3)
+ activesupport (= 3.2.3)
+ builder (~> 3.0.0)
+ erubis (~> 2.7.0)
+ journey (~> 1.0.1)
+ rack (~> 1.4.0)
+ rack-cache (~> 1.2)
+ rack-test (~> 0.6.1)
+ sprockets (~> 2.1.2)
+ activemodel (3.2.3)
+ activesupport (= 3.2.3)
+ builder (~> 3.0.0)
+ activerecord (3.2.3)
+ activemodel (= 3.2.3)
+ activesupport (= 3.2.3)
+ arel (~> 3.0.2)
+ tzinfo (~> 0.3.29)
+ activeresource (3.2.3)
+ activemodel (= 3.2.3)
+ activesupport (= 3.2.3)
+ activesupport (3.2.3)
+ i18n (~> 0.6)
+ multi_json (~> 1.0)
+ arel (3.0.2)
+ builder (3.0.0)
+ chunky_png (1.2.5)
+ compass (0.12.1)
+ chunky_png (~> 1.2)
+ fssm (>= 0.2.7)
+ sass (~> 3.1)
+ erubis (2.7.0)
+ fssm (0.2.9)
+ git (1.2.5)
+ hike (1.2.1)
+ i18n (0.6.0)
+ jeweler (1.8.3)
+ bundler (~> 1.0)
+ git (>= 1.2.5)
+ rake
+ rdoc
+ journey (1.0.3)
+ jquery-rails (2.0.2)
+ railties (>= 3.2.0, < 5.0)
+ thor (~> 0.14)
+ json (1.6.6)
+ mail (2.4.4)
+ i18n (>= 0.4.0)
+ mime-types (~> 1.16)
+ treetop (~> 1.4.8)
+ mime-types (1.18)
+ multi_json (1.3.2)
+ polyglot (0.3.3)
+ rack (1.4.1)
+ rack-cache (1.2)
+ rack (>= 0.4)
+ rack-ssl (1.3.2)
+ rack
+ rack-test (0.6.1)
+ rack (>= 1.0)
+ rails (3.2.3)
+ actionmailer (= 3.2.3)
+ actionpack (= 3.2.3)
+ activerecord (= 3.2.3)
+ activeresource (= 3.2.3)
+ activesupport (= 3.2.3)
+ bundler (~> 1.0)
+ railties (= 3.2.3)
+ railties (3.2.3)
+ actionpack (= 3.2.3)
+ activesupport (= 3.2.3)
+ rack-ssl (~> 1.3.2)
+ rake (>= 0.8.7)
+ rdoc (~> 3.4)
+ thor (~> 0.14.6)
+ rake (0.9.2.2)
+ rdoc (3.12)
+ json (~> 1.4)
+ redcarpet (2.1.1)
+ sass (3.1.16)
+ sprockets (2.1.2)
+ hike (~> 1.2)
+ rack (~> 1.0)
+ tilt (~> 1.1, != 1.3.0)
+ thor (0.14.6)
+ tilt (1.3.3)
+ treetop (1.4.10)
+ polyglot
+ polyglot (>= 0.3.1)
+ tzinfo (0.3.33)
+ yard (0.7.5)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ bundler
+ compass
+ jeweler
+ jquery-rails
+ rails
+ redcarpet
+ yard
20 LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2012 Tim Morgan
+
+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.
164 README.md
@@ -0,0 +1,164 @@
+MultiUploader
+=============
+
+A Ruby on Rails engine that adds drag-and-drop streaming multi-file uploader
+that uses strictly modern standard Web technologies.
+
+| | |
+|:------------|:--------------------------------|
+| **Author** | Tim Morgan |
+| **Version** | 1.0 (Apr 20, 2012) |
+| **License** | Released under the MIT license. |
+
+About
+-----
+
+This gem adds a JavaScript library that draws a drag-and-drop target. When a
+file is dragged to this target, it is queued for upload. Files are uploaded to
+an endpoint with a configured amount of maximum parallel uploads. JavaScript
+callbacks are used to track file progress.
+
+In addition to the uploader itself, a higher-level abstraction, called
+"EasyUploader", is also included. EasyUploader is powered by MultiUploader, but
+also includes a quick-'n'-ugly™ user interface. You can use EasyUploader to
+quickly start testing MultiUploader in your app, or you can even use it in
+production if you really hate rolling your own designs. It also makes for
+excellent example code for learning MultiUploader!
+
+### Requirements
+
+* **Rails 3.1**: This gem uses Rails engines.
+* **jQuery**: The carousel and lightbox is rendered and managed using jQuery.
+* **Sass**: The carousel layout is written using SCSS.
+
+#### Client Requirements
+
+For people to use this gem, they will need support for XmlHttpRequest level 2
+and the JavaScript drag-and-drop API. If you use the theme that ships with this
+gem, your clients will also need CSS level 3. All of these are supported on
+recent versions of Safari and Google Chrome.
+
+Installation
+------------
+
+To use this gem, add to your Gemfile:
+
+```` ruby
+gem 'multiuploader'
+````
+
+To your `application.js` file (or some other JavaScript manifest file), add:
+
+```` javascript
+//= require multiuploader
+````
+
+You may also need to add the following if it is not already there:
+
+```` javascript
+ //= require jquery
+ ````
+
+### EasyUploader
+
+If you wish to additionally use EasyUploader, you must add the following to
+your `application.css` file (or some other CSS manifest file);
+
+ ```` css
+ /*
+ *= require multiuploader
+ *= require easyuploader
+ */
+````
+
+To your `application.js` file (or some other JavaScript manifest file), add:
+
+```` javascript
+//= require easyuploader
+````
+
+Usage
+-----
+
+We'll get started with EasyUploader first, since that's the ... easiest. If you
+want to skip the baby stuff and get right into hot hot adult uploading, flip to
+the next subsection.
+
+### EasyUploader
+
+All you need to do to start using EasyUploader is create a DIV element and call
+the `easyUploader` jQuery method on it:
+
+```` javascript
+$('#easyuploader').easyUploader("http://some/endpoint", 'file');
+````
+
+The first parameter is the URL to upload the files to, and the second is the
+name of the form field to associate the file data with. The encoding will always
+be `application/x-www-form-urlencoded`.
+
+If you use the `easyuploader` ID, the styles in the `easyuploader.css.scss.erb`
+file will kick in and you should get an instant drag-and-drop target. Drag one
+or more files in there and you should start seeing the magic happen on your
+server.
+
+There is a third parameter, not used above, that allows you to pass in
+additional options to the underlying MultiUploader:
+
+```` javascript
+$('#easyuploader').easyUploader("http://some/endpoint", 'file', {
+ maxSimultaneousUploads: 4
+});
+````
+
+Read the MultiUploader documentation for a full list of options.
+
+### MultiUploader
+
+For more low-level control of the upload process, you'll need to use
+MultiUploader directly. The signature is the same as EasyUploader:
+
+```` javascript
+$('#easyuploader').multiUploader("http://some/endpoint", 'file');
+````
+
+The only difference is, this time you need to implement the callbacks yourself.
+There are four: `startHandler`, `progressHandler`, `loadHandler`, and
+`errorHandler`. Their method signatures are as follows:
+
+```` javascript
+$('#easyuploader').multiUploader("http://some/endpoint", 'file', {
+ startHandler: function(file_unique_id, file) {
+ // called when a file begins uploading
+ },
+ progressHandler: function(file_unique_id, state, position, total) {
+ // called periodically as a file is uploaded
+ // (position/total)*100 gives the percent complete
+ },
+ loadHandler: function(file_unique_id, xhr) {
+ // called when the upload is complete and the response has been received
+ // use the xhr (an XmlHttpRequest instance) to get response data
+ },
+ errorHandler: function(file_unique_id, xhr) {
+ // called when the upload fails or an error response is received
+ // same arguments as loadHandler
+ }
+});
+````
+
+Notice that each callback receives a unique ID for the file. These are randomly
+generated and have no meaningful information. They're just used to keep track of
+your files. You should associate each upload's unique ID with the page element
+that displays its progress.
+
+Also note that the `startHandler` will not necessarily be called the moment the
+user releases his mouse button. If the `maxSimultaneousUploads` option is set,
+additional uploads beyond this number will be queued and put into a pending
+state until an "upload slot" is vacated.
+
+The `progressHandler` method receives a state parameter. The value will be
+"upload" when the file is uploading, and "download" when the upload has
+completed and the client is downloading the server's response.
+
+For more information, and a list of additional options, see the MultiUploader
+class documentation.
38 Rakefile
@@ -0,0 +1,38 @@
+# encoding: utf-8
+
+require 'rubygems'
+require 'bundler'
+begin
+ Bundler.setup(:default, :development)
+rescue Bundler::BundlerError => e
+ $stderr.puts e.message
+ $stderr.puts "Run `bundle install` to install missing gems"
+ exit e.status_code
+end
+require 'rake'
+
+require 'jeweler'
+Jeweler::Tasks.new do |gem|
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
+ gem.name = "multiuploader"
+ gem.homepage = "http://github.com/RISCfuture/multiuploader"
+ gem.license = "MIT"
+ gem.summary = %Q{Multi-file drag-and-drop file uploader using strictly HTML5}
+ gem.description = %Q{A drag-and-drop multi-streaming uploader that uses XHR level 2 and the drag-drop JS API (and no Flash!).}
+ gem.email = "github@timothymorgan.info"
+ gem.authors = ["Tim Morgan"]
+ gem.files = %w( lib/**/* vendor/**/* multiuploader.gemspec LICENSE.txt README.md )
+ # dependencies defined in Gemfile
+end
+Jeweler::RubygemsDotOrgTasks.new
+
+require 'yard'
+YARD::Rake::YardocTask.new('doc') do |doc|
+ doc.options << '-m' << 'markdown' << '-M' << 'redcarpet'
+ doc.options << '--protected' << '--no-private'
+ doc.options << '-r' << 'README.md'
+ doc.options << '-o' << 'doc'
+ doc.options << '--title' << 'MultiUploader Documentation'
+
+ doc.files = %w( lib/**/* README.md )
+end
1 VERSION
@@ -0,0 +1 @@
+1.0.0
4 lib/multiuploader.rb
@@ -0,0 +1,4 @@
+# The Rails engine for MultiUploader.
+
+class MultiUploader < Rails::Engine
+end
63 multiuploader.gemspec
@@ -0,0 +1,63 @@
+# Generated by jeweler
+# DO NOT EDIT THIS FILE DIRECTLY
+# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = "multiuploader"
+ s.version = "1.0.0"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Tim Morgan"]
+ s.date = "2012-04-21"
+ s.description = "A drag-and-drop multi-streaming uploader that uses XHR level 2 and the drag-drop JS API (and no Flash!)."
+ s.email = "github@timothymorgan.info"
+ s.extra_rdoc_files = [
+ "LICENSE.txt",
+ "README.md"
+ ]
+ s.files = [
+ "LICENSE.txt",
+ "README.md",
+ "lib/multiuploader.rb",
+ "multiuploader.gemspec",
+ "vendor/assets/images/easyuploader/empty.png",
+ "vendor/assets/images/easyuploader/filled.png",
+ "vendor/assets/javascripts/easyuploader.js.coffee.erb",
+ "vendor/assets/javascripts/multiuploader.js.coffee",
+ "vendor/assets/stylesheets/easyuploader.css.scss.erb"
+ ]
+ s.homepage = "http://github.com/RISCfuture/multiuploader"
+ s.licenses = ["MIT"]
+ s.require_paths = ["lib"]
+ s.rubygems_version = "1.8.23"
+ s.summary = "Multi-file drag-and-drop file uploader using strictly HTML5"
+
+ if s.respond_to? :specification_version then
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+ s.add_runtime_dependency(%q<rails>, [">= 0"])
+ s.add_runtime_dependency(%q<compass>, [">= 0"])
+ s.add_runtime_dependency(%q<jquery-rails>, [">= 0"])
+ s.add_development_dependency(%q<yard>, [">= 0"])
+ s.add_development_dependency(%q<bundler>, [">= 0"])
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
+ else
+ s.add_dependency(%q<rails>, [">= 0"])
+ s.add_dependency(%q<compass>, [">= 0"])
+ s.add_dependency(%q<jquery-rails>, [">= 0"])
+ s.add_dependency(%q<yard>, [">= 0"])
+ s.add_dependency(%q<bundler>, [">= 0"])
+ s.add_dependency(%q<jeweler>, [">= 0"])
+ end
+ else
+ s.add_dependency(%q<rails>, [">= 0"])
+ s.add_dependency(%q<compass>, [">= 0"])
+ s.add_dependency(%q<jquery-rails>, [">= 0"])
+ s.add_dependency(%q<yard>, [">= 0"])
+ s.add_dependency(%q<bundler>, [">= 0"])
+ s.add_dependency(%q<jeweler>, [">= 0"])
+ end
+end
+
BIN vendor/assets/images/easyuploader/empty.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN vendor/assets/images/easyuploader/filled.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 vendor/assets/javascripts/easyuploader.js.coffee.erb
@@ -0,0 +1,74 @@
+root = exports ? this
+
+# A basic implementation of the {MultiUploader} class. Use this class in
+# conjunction with the "easyuploader" assets in `vendor/assets` for a
+# quick-and-dirty file uploader.
+#
+# Use the `$(...).easyUploader(...)` method for a more jQuery-like syntax.
+#
+# In order to take advantage of the included quick-'n'-ugly theme, your target
+# div needs to have an ID of `#easyuploader`.
+#
+class EasyUploader
+
+ # Creates a new upload manager.
+ #
+ # @param [jQuery element array] element The element to render the uploader in.
+ # @param [String] url The URL endpoint to post files to.
+ # @param [String] name The name of the file field.
+ # @param [Object] options Additional options to pass to {MultiUploader}.
+ #
+ constructor: (element, url, name, options) ->
+ options = $.extend({}, options,
+ startHandler: (uid, file) =>
+ if !@currentRow || @currentRow.find('>div.file').length == 5
+ @currentRow = $('<div/>').addClass('file-row').appendTo(element)
+
+ # preload images
+ (new Image()).src = "<%= image_path('easyuploader/empty.png') %>"
+ (new Image()).src = "<%= image_path('easyuploader/filled.png') %>"
+
+ fileDiv = $('<div/>').addClass('file').attr('id', "file_#{uid}").appendTo(@currentRow)
+ empty = $('<div/>').addClass('empty').appendTo(fileDiv)
+ $('<div/>').addClass('filled').appendTo empty
+ filename = $('<p/>').text(file.fileName).appendTo(fileDiv)
+ progressHandler: (uid, phase, position, total) =>
+ if (phase == 'upload')
+ amount = Math.round((position/total)*44)
+ $("#file_#{uid} .filled").css 'width', "#{amount}px"
+ loadHandler: (uid, xhr) =>
+ if Math.round(xhr.status/100) == 2
+ $("#file_#{uid}").addClass 'finished'
+ else
+ $("#file_#{uid}").addClass 'error'
+ if (xhr.status == 422)
+ errors = JSON.parse(xhr.responseText)
+ errorList = []
+
+ for fieldErrors in errors
+ do (fieldErrors) -> errorList = errorList.concat(fieldErrors)
+ $('<p/>').addClass('message').text(errorList.join(', ')).appendTo $("#file_#{uid}")
+ else
+ $('<p/>').addClass('message').text(xhr.statusText).appendTo $("#file_#{uid}")
+
+ if uploader.isFinished() && !uploader.isFailed() then window.location.reload()
+ errorHandler: (uid, xhr) =>
+ $("#file_#{uid}").addClass 'error'
+ if uploader.isFinished() && !uploader.isFailed() then window.location.reload()
+
+ )
+ uploader = element.multiUploader url, name, options
+ element.text "Drag files here to upload"
+
+
+$.fn.extend
+
+ # Creates an EasyUploader in the target element.
+ #
+ # @param [String] url The URL endpoint to post files to.
+ # @param [String] name The name of the file field.
+ # @param [Object] options Additional options to pass to {MultiUploader}.
+ # @return [EasyUploader] The new upload manager.
+ #
+ easyUploader: (url, name, options={}) ->
+ new EasyUploader(this, url, name, options)
121 vendor/assets/javascripts/multiuploader.js.coffee
@@ -0,0 +1,121 @@
+# A drag-and-drop multi-file uploader using strictly modern standard Web
+# technologies.
+#
+# Use the `$(...).multiUploader(...)` method for a more jQuery-like syntax.
+
+class MultiUploader
+
+ # Creates a new upload manager. Files dropped into `elem` will be uploaded (or
+ # queued for upload). The callbacks will be invoked at each phase of each
+ # file's upload.
+ #
+ # @param [jQuery element array] elem The drop target.
+ # @param [String] url The URL endpoint to post files to.
+ # @param [String] name The name of the file field.
+ # @param [Object] options Additional options.
+ # @option options [Integer] maxSimultaneousUploads The maximum number of
+ # parallel uploads. If not set, unlimited.
+ # @option options [String] method ("POST") The request method.
+ # @option options [Object] data Additional key-value pairs to include in the
+ # request form body.
+ # @option options [Function] startHandler Called when a file begins uploading.
+ # @option options [Function] progressHandler Called when some file data is
+ # uploaded.
+ # @option options [Function] loadHandler Called when a file finishes
+ # uploading.
+ # @option options [Function] errorHandler Called when a file upload fails or a
+ # bad response is received.
+ #
+ constructor: (elem, @url, @name, @options={}) ->
+ @method = @options.method || 'POST'
+ @element = $(elem)
+
+ @activeUploads = 0
+ @successfulUploads = 0
+ @failedUploads = 0
+ @pendingUploads = []
+
+ @element.bind 'dragenter', (event) ->
+ event.stopPropagation()
+ event.preventDefault()
+ false
+ @element.bind 'dragover', (event) ->
+ event.stopPropagation()
+ event.preventDefault()
+ false
+ @element.bind 'drop', this.drop
+
+ # @private
+ drop: (event) =>
+ event.stopPropagation()
+ event.preventDefault()
+
+ @element.text ''
+
+ $.each event.originalEvent.dataTransfer.files, (_, file) =>
+ this.upload file
+
+ # @private
+ isFinished: =>
+ @activeUploads == 0 && @pendingUploads.length == 0
+
+ # @private
+ isFailed: =>
+ @failedUploads > 0
+
+ # Uploads a file, or enqueues it for uploading.
+ #
+ # @param [File] file The file to upload.
+ #
+ upload: (file) =>
+ if @options.maxSimultaneousUploads && @activeUploads > @options.maxSimultaneousUploads
+ @pendingUploads.push file
+ return
+
+ @activeUploads++
+ uid = Math.round(Math.random()*0x1000000).toString(16); # so that the listeners can keep their files apart
+ @options.startHandler(uid, file) if @options.startHandler
+
+ xhr = new XMLHttpRequest()
+
+ data = new FormData()
+ data.append @name, file
+ if @options.data
+ for key, value of @options.data
+ do (key, value) -> data.append key, value
+
+ xhr.addEventListener 'load', (event) =>
+ @activeUploads--
+ if xhr.status >= 400 then @failedUploads++ else @successfulUploads++
+ this.upload @pendingUploads.pop() if @pendingUploads.length > 0
+ xhr.addEventListener 'error', (event) =>
+ @activeUploads--
+ @failedUploads++
+ this.upload @pendingUploads.pop() if @pendingUploads.length > 0
+
+ if @options.progressHandler
+ xhr.upload.addEventListener 'progress', (event) =>
+ @options.progressHandler uid, 'upload', event.position, event.total
+ xhr.addEventListener 'progress', (event) =>
+ @options.progressHandler uid, 'download', event.position, event.total
+ if @options.errorHandler
+ xhr.addEventListener 'error', (event) =>
+ @options.errorHandler uid, xhr
+ if @options.loadHandler
+ xhr.addEventListener 'load', (event) =>
+ @options.loadHandler uid, xhr
+
+ xhr.open @method, @url, true
+ xhr.send data
+
+$.fn.extend
+
+ # Creates a new file uploader using the target element as the drop zone.
+ #
+ # @param [String] url The URL endpoint to post files to.
+ # @param [String] name The name of the file field.
+ # @param [Object] options Additional options to pass to {MultiUploader}.
+ # @return [MultiUploader] The new upload manager.
+ #
+ multiUploader: (url, name, options={}) ->
+ new MultiUploader(this, url, name, options)
51 vendor/assets/stylesheets/easyuploader.css.scss.erb
@@ -0,0 +1,51 @@
+@import "compass/css3/box";
+$theme-color: gray;
+
+#easyuploader {
+ color: $theme-color;
+ font-size: 14pt;
+ font-weight: bold;
+ text-align: center;
+ padding: 20px 10px;
+ background-color: lighten($theme-color, 40%);
+ border: 5px dashed lighten($theme-color, 25%);
+
+ .file-row {
+ @include display-box;
+ @include box-orient(horizontal);
+ @include box-pack(center);
+ }
+
+ .file {
+ margin: 20px;
+ width: 100px;
+
+ .empty {
+ background: url("<%= image_path 'easyuploader/empty.png' %>") no-repeat left top;
+ width: 44px;
+ height: 56px;
+ margin-left: 28px;
+ }
+
+ .filled {
+ background: url("<%= image_path 'easyuploader/filled.png' %>") no-repeat left top;
+ width: 0;
+ height: 56px;
+ }
+
+ p {
+ text-align: center;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ &.finished p { color: black; }
+ &.error p { color: #900; }
+
+ p.message {
+ font-size: 10pt;
+ font-style: italic;
+ font-weight: normal;
+ }
+ }
+}

0 comments on commit 6f07287

Please sign in to comment.