├── .gitignore ├── Gemfile ├── Gemfile.lock ├── README.textile ├── Rakefile ├── app ├── assets │ ├── images │ │ └── spinner.gif │ ├── javascripts │ │ ├── application.js │ │ └── pictures │ │ │ ├── customupload.js │ │ │ └── form.js │ └── stylesheets │ │ └── application.css ├── controllers │ ├── application_controller.rb │ └── pictures_controller.rb ├── helpers │ ├── application_helper.rb │ ├── error_messages_helper.rb │ ├── layout_helper.rb │ └── pictures_helper.rb ├── mailers │ └── .gitkeep ├── models │ ├── .gitkeep │ └── picture.rb ├── uploaders │ └── image_uploader.rb └── views │ ├── layouts │ └── application.html.erb │ └── pictures │ ├── _form.html.erb │ ├── _template-download.html.erb │ ├── _template-upload.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb ├── config.ru ├── config ├── application.rb ├── boot.rb ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── backtrace_silencers.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── secret_token.rb │ ├── session_store.rb │ └── wrap_parameters.rb ├── locales │ └── en.yml └── routes.rb ├── db ├── migrate │ └── 20111021151343_create_pictures.rb ├── schema.rb └── seeds.rb ├── doc └── README_FOR_APP ├── lib ├── assets │ └── .gitkeep └── tasks │ └── .gitkeep ├── log └── .gitkeep ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico └── robots.txt ├── script └── rails └── vendor ├── assets ├── images │ ├── close.png │ ├── loading.gif │ ├── next.png │ ├── pause.png │ ├── pbar-ani.gif │ ├── play.png │ ├── previous.png │ └── red_pen.png ├── javascripts │ ├── jquery.fileupload-ui.js │ ├── jquery.fileupload.js │ ├── jquery.iframe-transport.js │ └── shadowbox.js └── stylesheets │ ├── .gitkeep │ ├── best_in_place.css │ ├── jquery.fileupload-ui.css │ ├── nifty-layout.css │ └── shadowbox.css └── plugins └── .gitkeep /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | db/*.sqlite3 3 | log/*.log 4 | tmp/ 5 | .sass-cache/ 6 | config/initializers/carrierwave.rb 7 | public/uploads 8 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gem 'rails', '3.1.1' 4 | gem 'mysql2' 5 | gem 'jquery-rails' 6 | gem 'nifty-generators' 7 | gem 'carrierwave' 8 | gem 'fog' 9 | gem 'mini_magick' 10 | gem "best_in_place", :git => 'git://github.com/proton/best_in_place.git' 11 | 12 | group :assets do 13 | gem 'sass-rails', '~> 3.1.4' 14 | gem 'coffee-rails', '~> 3.1.1' 15 | gem 'uglifier', '>= 1.0.3' 16 | end 17 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: git://github.com/proton/best_in_place.git 3 | revision: f101f00e20230c72ee681232b6440144d1ca2448 4 | specs: 5 | best_in_place (0.1.9) 6 | rails (~> 3.0) 7 | 8 | GEM 9 | remote: http://rubygems.org/ 10 | specs: 11 | actionmailer (3.1.1) 12 | actionpack (= 3.1.1) 13 | mail (~> 2.3.0) 14 | actionpack (3.1.1) 15 | activemodel (= 3.1.1) 16 | activesupport (= 3.1.1) 17 | builder (~> 3.0.0) 18 | erubis (~> 2.7.0) 19 | i18n (~> 0.6) 20 | rack (~> 1.3.2) 21 | rack-cache (~> 1.1) 22 | rack-mount (~> 0.8.2) 23 | rack-test (~> 0.6.1) 24 | sprockets (~> 2.0.2) 25 | activemodel (3.1.1) 26 | activesupport (= 3.1.1) 27 | builder (~> 3.0.0) 28 | i18n (~> 0.6) 29 | activerecord (3.1.1) 30 | activemodel (= 3.1.1) 31 | activesupport (= 3.1.1) 32 | arel (~> 2.2.1) 33 | tzinfo (~> 0.3.29) 34 | activeresource (3.1.1) 35 | activemodel (= 3.1.1) 36 | activesupport (= 3.1.1) 37 | activesupport (3.1.1) 38 | multi_json (~> 1.0) 39 | arel (2.2.1) 40 | builder (3.0.0) 41 | carrierwave (0.5.7) 42 | activesupport (~> 3.0) 43 | coffee-rails (3.1.1) 44 | coffee-script (>= 2.2.0) 45 | railties (~> 3.1.0) 46 | coffee-script (2.2.0) 47 | coffee-script-source 48 | execjs 49 | coffee-script-source (1.1.2) 50 | erubis (2.7.0) 51 | excon (0.7.6) 52 | execjs (1.2.9) 53 | multi_json (~> 1.0) 54 | fog (1.0.0) 55 | builder 56 | excon (~> 0.7.3) 57 | formatador (~> 0.2.0) 58 | mime-types 59 | multi_json (~> 1.0.3) 60 | net-scp (~> 1.0.4) 61 | net-ssh (~> 2.1.4) 62 | nokogiri (~> 1.5.0) 63 | ruby-hmac 64 | formatador (0.2.1) 65 | hike (1.2.1) 66 | i18n (0.6.0) 67 | jquery-rails (1.0.16) 68 | railties (~> 3.0) 69 | thor (~> 0.14) 70 | json (1.6.1) 71 | mail (2.3.0) 72 | i18n (>= 0.4.0) 73 | mime-types (~> 1.16) 74 | treetop (~> 1.4.8) 75 | mime-types (1.16) 76 | mini_magick (3.3) 77 | subexec (~> 0.1.0) 78 | multi_json (1.0.3) 79 | mysql2 (0.3.7) 80 | net-scp (1.0.4) 81 | net-ssh (>= 1.99.1) 82 | net-ssh (2.1.4) 83 | nifty-generators (0.4.6) 84 | nokogiri (1.5.0) 85 | polyglot (0.3.2) 86 | rack (1.3.5) 87 | rack-cache (1.1) 88 | rack (>= 0.4) 89 | rack-mount (0.8.3) 90 | rack (>= 1.0.0) 91 | rack-ssl (1.3.2) 92 | rack 93 | rack-test (0.6.1) 94 | rack (>= 1.0) 95 | rails (3.1.1) 96 | actionmailer (= 3.1.1) 97 | actionpack (= 3.1.1) 98 | activerecord (= 3.1.1) 99 | activeresource (= 3.1.1) 100 | activesupport (= 3.1.1) 101 | bundler (~> 1.0) 102 | railties (= 3.1.1) 103 | railties (3.1.1) 104 | actionpack (= 3.1.1) 105 | activesupport (= 3.1.1) 106 | rack-ssl (~> 1.3.2) 107 | rake (>= 0.8.7) 108 | rdoc (~> 3.4) 109 | thor (~> 0.14.6) 110 | rake (0.9.2) 111 | rdoc (3.11) 112 | json (~> 1.4) 113 | ruby-hmac (0.4.0) 114 | sass (3.1.10) 115 | sass-rails (3.1.4) 116 | actionpack (~> 3.1.0) 117 | railties (~> 3.1.0) 118 | sass (>= 3.1.4) 119 | sprockets (~> 2.0.0) 120 | tilt (~> 1.3.2) 121 | sprockets (2.0.3) 122 | hike (~> 1.2) 123 | rack (~> 1.0) 124 | tilt (~> 1.1, != 1.3.0) 125 | subexec (0.1.0) 126 | thor (0.14.6) 127 | tilt (1.3.3) 128 | treetop (1.4.10) 129 | polyglot 130 | polyglot (>= 0.3.1) 131 | tzinfo (0.3.30) 132 | uglifier (1.0.4) 133 | execjs (>= 0.3.0) 134 | multi_json (>= 1.0.2) 135 | 136 | PLATFORMS 137 | ruby 138 | 139 | DEPENDENCIES 140 | best_in_place! 141 | carrierwave 142 | coffee-rails (~> 3.1.1) 143 | fog 144 | jquery-rails 145 | mini_magick 146 | mysql2 147 | nifty-generators 148 | rails (= 3.1.1) 149 | sass-rails (~> 3.1.4) 150 | uglifier (>= 1.0.3) 151 | -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1. Description: 2 | 3 | h2. V5: 4 | 5 | Sample app using Rails 3.1, "carrierwave":https://github.com/jnicklas/carrierwave and V5 of "jquery-file-upload":https://github.com/blueimp/jQuery-File-Upload to upload and store files on Amazon S3. 6 | 7 | h2. V4: 8 | 9 | The old version of the app using Rails 3 and V4 of "jquery-file-upload":https://github.com/blueimp/jQuery-File-Upload can be found "here":https://github.com/yortz/carrierwave_jquery_file_upload/tree/v4 10 | 11 | The "backgrounder":https://github.com/yortz/carrierwave_jquery_file_upload/tree/backgrounder branch delays the entire upload process to S3 thanks to "carrierwave backgrounder":https://github.com/lardawge/carrierwave_backgrounder and "delayed job":https://github.com/collectiveidea/delayed_job 12 | 13 | h1. Install: 14 | 15 | * Clone or fork the github repo 16 | * cd into app directory 17 | 18 |
19 |   
20 |     $: bundle install       #install required gems
21 |     $: rake db:create:all   #create dbs
22 |     $: rake db:migrate      #migrate db
23 |     $: rails s              #start app
24 |   
25 | 
26 | 27 | h1. S3: 28 | 29 | Since this app stores files to amazon S3 you will need an "Amazon S3":http://aws.amazon.com/s3/ account, otherwise you can choose to store images on your local filesystem by editing the uploader: 30 | 31 |
32 |   
33 |     #app/uploaders/image_uploader.rb
34 |     # Choose what kind of storage to use for this uploader:
35 |       storage :file     #stores files locally
36 |     # storage :fog      #stores files on S3
37 |   
38 | 
39 | 40 | Amazon S3 support is made possibile by "Fog":https://github.com/geemus/fog 41 | 42 | You will need to tell carrierwave to use Amazons S3 by creating an initializer and providing your Amazon S3 authentication details: 43 | 44 |
45 |   
46 |     #config/initializers/carrierwave.rb
47 |     
48 |     CarrierWave.configure do |config|
49 |       config.fog_credentials = {
50 |         :provider               => 'AWS',                                      # required
51 |         :aws_access_key_id      => 'amazon s3 access key',                     # required
52 |         :aws_secret_access_key  => 'amazon s3 secret access key',              # required
53 |         :region                 => 'us-west-1'                                 # optional, defaults to 'us-east-1'
54 |       }
55 |       config.fog_directory  = 'yourbucketname'                                 # required
56 |       config.fog_host       = 'http://yourbucketname.s3.amazonaws.com/'        # optional, defaults to nil
57 |       config.fog_public     = false                                            # optional, defaults to true
58 |       config.fog_attributes = {'Cache-Control'=>'max-age=315576000'}           # optional, defaults to {}
59 |     end
60 |   
61 | 
62 | 63 | h1. Image Processing: 64 | 65 | MiniMagick is app default for processing images; if you want to use another library, just edit the Gemfile and modify the uploader to reflect your choice: 66 | 67 |
68 |   
69 |     #app/uploaders/image_uploader.rb
70 |     # Include RMagick or ImageScience support:
71 |     # include CarrierWave::RMagick
72 |       include CarrierWave::ImageScience
73 |     # include CarrierWave::MiniMagick
74 |   
75 | 
76 | 77 | h1. References: 78 | 79 | * "carrierwave":https://github.com/jnicklas/carrierwave 80 | 81 | * "Jquery-File-Upload":https://github.com/blueimp/jQuery-File-Upload 82 | 83 | h1. TODO: 84 | 85 | * testing 86 | 87 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | CarrierwaveJqueryFileUpload::Application.load_tasks 8 | -------------------------------------------------------------------------------- /app/assets/images/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/app/assets/images/spinner.gif -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into including all the files listed below. 2 | // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically 3 | // be included in the compiled file accessible from http://example.com/assets/application.js 4 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 5 | // the compiled file. 6 | // 7 | //= require jquery 8 | //= require jquery-ui 9 | //= require best_in_place 10 | //= require jquery.iframe-transport 11 | //= require jquery.fileupload 12 | //= require jquery.fileupload-ui 13 | //= require shadowbox 14 | //= require pictures/customupload 15 | //= require pictures/form 16 | //= require_tree . -------------------------------------------------------------------------------- /app/assets/javascripts/pictures/customupload.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | 'use strict'; 3 | 4 | $.widget('blueimpUIX.fileupload', $.blueimpUI.fileupload, { 5 | 6 | options: { 7 | errorMessages: { 8 | maxFileSize: 'File is too big', 9 | minFileSize: 'File is too small', 10 | acceptFileTypes: 'Filetype not allowed', 11 | maxNumberOfFiles: 'Max number of files exceeded' 12 | } 13 | }, 14 | 15 | _initFileUploadButtonBar: function () { 16 | var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'), 17 | filesList = this.element.find('.files'), 18 | ns = this.options.namespace; 19 | fileUploadButtonBar 20 | .addClass('ui-widget-header ui-corner-top'); 21 | this.element.find('.fileinput-button').each(function () { 22 | var fileInput = $(this).find('input:file').detach(); 23 | $(this).button({icons: {primary: 'ui-icon-plusthick'}}) 24 | .append(fileInput); 25 | }); 26 | fileUploadButtonBar.find('.start') 27 | .button({icons: {primary: 'ui-icon-circle-arrow-e'}}) 28 | .bind('click.' + ns, function (e) { 29 | e.preventDefault(); 30 | filesList.find('.start button').click(); 31 | }); 32 | fileUploadButtonBar.find('.cancel') 33 | .button({icons: {primary: 'ui-icon-cancel'}}) 34 | .bind('click.' + ns, function (e) { 35 | e.preventDefault(); 36 | filesList.find('.cancel button').click(); 37 | }); 38 | fileUploadButtonBar.find('.delete') 39 | .button({icons: {primary: 'ui-icon-trash'}}) 40 | .bind('click.' + ns, function (e) { 41 | e.preventDefault(); 42 | if (confirm("Are you sure you want to delete all files?")) { 43 | filesList.find('.delete').addClass("all"); 44 | filesList.find('.all button').click(); 45 | } 46 | else { 47 | return false; 48 | } 49 | }); 50 | }, 51 | 52 | _deleteHandler: function (e) { 53 | e.preventDefault(); 54 | var button = $(this); 55 | if ($(this).parent().hasClass("all")) { 56 | e.data.fileupload._trigger('destroy', e, { 57 | context: button.closest('.template-download'), 58 | url: button.attr('data-url'), 59 | type: button.attr('data-type'), 60 | dataType: e.data.fileupload.options.dataType 61 | }); 62 | } 63 | else { 64 | if ( confirm("Are you sure you want to delete this file ?") == true) { 65 | e.data.fileupload._trigger('destroy', e, { 66 | context: button.closest('.template-download'), 67 | url: button.attr('data-url'), 68 | type: button.attr('data-type'), 69 | dataType: e.data.fileupload.options.dataType 70 | }); 71 | console.info($(this).parent()); 72 | } 73 | else { 74 | return false; 75 | } 76 | } 77 | }, 78 | 79 | _renderUploadTemplate: function (files) { 80 | var that = this, 81 | rows = $(); 82 | $.each(files, function (index, file) { 83 | file = that._uploadTemplateHelper(file); 84 | var row = $('' + 85 | '' + 86 | '' + 87 | '' + 88 | (file.error ? 89 | '' 90 | : 91 | '
' + 92 | '' 93 | ) + 94 | '' + 95 | ''); 96 | row.find('.name').text(file.name); 97 | row.find('.size').text(file.sizef); 98 | if (file.error) { 99 | row.addClass('ui-state-error'); 100 | row.find('.error').text( 101 | that.options.errorMessages[file.error] || file.error 102 | ); 103 | } 104 | rows = rows.add(row); 105 | }); 106 | return rows; 107 | } 108 | 109 | }); 110 | 111 | }(jQuery)); -------------------------------------------------------------------------------- /app/assets/javascripts/pictures/form.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | 3 | $('.fileupload-content').append('
'); 4 | 5 | var inputs = $('#new_picture :input[type=text]'); 6 | 7 | clearFields(inputs); 8 | 9 | function clearFields (inputs) { 10 | $('.ui-state-error-text').remove(); 11 | $.each(inputs, function(index, field){ 12 | $(field).focus(function(){ 13 | $(field).removeClass("ui-state-error"); 14 | $(field).next().remove(); 15 | }); 16 | }); 17 | }; 18 | 19 | // Initialize the jQuery File Upload widget: 20 | $('#fileupload').fileupload({ 21 | maxNumberOfFiles: 10, 22 | acceptFileTypes: /\.(jpg|jpeg|gif|png|JPG|JPEG|GIF|PNG)$/ 23 | }); 24 | 25 | // 26 | // Load existing files: 27 | $.getJSON($('#fileupload form').prop('action'), function (files) { 28 | var fu = $('#fileupload').data('fileupload'); 29 | //fu._adjustMaxNumberOfFiles(-files.length); 30 | fu._renderDownload(files) 31 | .appendTo($('#fileupload .files')) 32 | .fadeIn(function () { 33 | // Fix for IE7 and lower: 34 | $(this).show(); 35 | }); 36 | 37 | $(".best_in_place").best_in_place(); 38 | Shadowbox.init(); 39 | $('#loading').hide(); 40 | }); 41 | 42 | // Open download dialogs via iframes, 43 | // to prevent aborting current uploads: 44 | $('#fileupload .files a:not([target^=_blank])').live('click', function (e) { 45 | e.preventDefault(); 46 | $('') 47 | .prop('src', this.href) 48 | .appendTo('body'); 49 | }); 50 | 51 | 52 | $('#fileupload').bind('fileuploadsend', function (e, data) { 53 | 54 | var values = {}; 55 | 56 | $.each($('#new_picture').serializeArray(), function(i, field) { 57 | values[field.name] = field.value; 58 | }); 59 | 60 | var title = values["picture[title]"] 61 | var description = values["picture[description]"] 62 | 63 | $.each( values, function(k, v){ 64 | if (v == 0) { 65 | $('input[name="' + k + '"]').addClass("ui-state-error"); 66 | $('input[name="' + k + '"]').after(" can't be blank!"); 67 | } 68 | }); 69 | 70 | }); 71 | 72 | $('#fileupload').bind('fileuploadprogressall', function (e,data) { 73 | var progress = parseInt(data.loaded / data.total * 100, 10); 74 | //$('.progress-bar').find('div').css('width', progress + '%').find('span').html(progress + '%'); 75 | console.info(progress); 76 | }); 77 | 78 | }); -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll automatically include all the stylesheets available in this directory 3 | * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at 4 | * the top of the compiled file, but it's generally better to create a new file per style scope. 5 | *= require_self 6 | *= require_tree . 7 | //= require jquery.fileupload-ui 8 | //= require nifty-layout 9 | //= require best_in_place 10 | //= require shadowbox 11 | */ 12 | 13 | #loading { 14 | top: 50%; 15 | margin-bottom: 25px; 16 | margin-left: 45%; 17 | margin-right: 45%; 18 | width:128px; 19 | height:128px; 20 | background-image: url(../assets/spinner.gif); 21 | } -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | end 4 | -------------------------------------------------------------------------------- /app/controllers/pictures_controller.rb: -------------------------------------------------------------------------------- 1 | class PicturesController < ApplicationController 2 | # GET /pictures 3 | # GET /pictures.json 4 | def index 5 | @pictures = Picture.all 6 | 7 | respond_to do |format| 8 | format.html # index.html.erb 9 | format.json { render :json => @pictures.collect { |p| p.to_jq_upload }.to_json } 10 | end 11 | end 12 | 13 | # GET /pictures/1 14 | # GET /pictures/1.json 15 | def show 16 | @picture = Picture.find(params[:id]) 17 | 18 | respond_to do |format| 19 | format.html # show.html.erb 20 | format.json { render json: @picture } 21 | end 22 | end 23 | 24 | # GET /pictures/new 25 | # GET /pictures/new.json 26 | def new 27 | @picture = Picture.new 28 | 29 | respond_to do |format| 30 | format.html # new.html.erb 31 | format.json { render json: @picture } 32 | end 33 | end 34 | 35 | # GET /pictures/1/edit 36 | def edit 37 | @picture = Picture.find(params[:id]) 38 | end 39 | 40 | # POST /pictures 41 | # POST /pictures.json 42 | def create 43 | @picture = Picture.new(params[:picture]) 44 | 45 | respond_to do |format| 46 | if @picture.save 47 | format.json { render :json => [ @picture.to_jq_upload ].to_json } 48 | else 49 | format.json { render :json => [ @picture.to_jq_upload.merge({ :error => "custom_failure" }) ].to_json } 50 | end 51 | end 52 | end 53 | 54 | # PUT /pictures/1 55 | # PUT /pictures/1.json 56 | def update 57 | @picture = Picture.find(params[:id]) 58 | 59 | respond_to do |format| 60 | if @picture.update_attributes(params[:picture]) 61 | format.html { redirect_to @picture, notice: 'Picture was successfully updated.' } 62 | format.json { head :ok } 63 | else 64 | format.html { render action: "edit" } 65 | format.json { render json: @picture.errors, status: :unprocessable_entity } 66 | end 67 | end 68 | end 69 | 70 | # DELETE /pictures/1 71 | # DELETE /pictures/1.json 72 | def destroy 73 | @picture = Picture.find(params[:id]) 74 | @picture.destroy 75 | 76 | respond_to do |format| 77 | format.html { redirect_to pictures_url } 78 | format.json { render :json => true } 79 | end 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/error_messages_helper.rb: -------------------------------------------------------------------------------- 1 | module ErrorMessagesHelper 2 | # Render error messages for the given objects. The :message and :header_message options are allowed. 3 | def error_messages_for(*objects) 4 | options = objects.extract_options! 5 | options[:header_message] ||= I18n.t(:"activerecord.errors.header", :default => "Invalid Fields") 6 | options[:message] ||= I18n.t(:"activerecord.errors.message", :default => "Correct the following errors and try again.") 7 | messages = objects.compact.map { |o| o.errors.full_messages }.flatten 8 | unless messages.empty? 9 | content_tag(:div, :class => "error_messages") do 10 | list_items = messages.map { |msg| content_tag(:li, msg) } 11 | content_tag(:h2, options[:header_message]) + content_tag(:p, options[:message]) + content_tag(:ul, list_items.join.html_safe) 12 | end 13 | end 14 | end 15 | 16 | module FormBuilderAdditions 17 | def error_messages(options = {}) 18 | @template.error_messages_for(@object, options) 19 | end 20 | end 21 | end 22 | 23 | ActionView::Helpers::FormBuilder.send(:include, ErrorMessagesHelper::FormBuilderAdditions) 24 | -------------------------------------------------------------------------------- /app/helpers/layout_helper.rb: -------------------------------------------------------------------------------- 1 | # These helper methods can be called in your template to set variables to be used in the layout 2 | # This module should be included in all views globally, 3 | # to do so you may need to add this line to your ApplicationController 4 | # helper :layout 5 | module LayoutHelper 6 | def title(page_title, show_title = true) 7 | content_for(:title) { h(page_title.to_s) } 8 | @show_title = show_title 9 | end 10 | 11 | def show_title? 12 | @show_title 13 | end 14 | 15 | def stylesheet(*args) 16 | content_for(:head) { stylesheet_link_tag(*args) } 17 | end 18 | 19 | def javascript(*args) 20 | content_for(:head) { javascript_include_tag(*args) } 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/helpers/pictures_helper.rb: -------------------------------------------------------------------------------- 1 | module PicturesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/app/mailers/.gitkeep -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/app/models/.gitkeep -------------------------------------------------------------------------------- /app/models/picture.rb: -------------------------------------------------------------------------------- 1 | class Picture < ActiveRecord::Base 2 | include Rails.application.routes.url_helpers 3 | validates_presence_of :title, :description, :file 4 | mount_uploader :file, ImageUploader 5 | 6 | #one convenient method to pass jq_upload the necessary information 7 | def to_jq_upload 8 | { 9 | "id" => read_attribute(:id), 10 | "title" => read_attribute(:title), 11 | "description" => read_attribute(:description), 12 | "name" => read_attribute(:file), 13 | "size" => file.size, 14 | "url" => file.url, 15 | "thumbnail_url" => file.thumb.url, 16 | "delete_url" => picture_path(:id => id), 17 | "delete_type" => "DELETE" 18 | } 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /app/uploaders/image_uploader.rb: -------------------------------------------------------------------------------- 1 | class ImageUploader < CarrierWave::Uploader::Base 2 | 3 | # Include RMagick or ImageScience support: 4 | # include CarrierWave::RMagick 5 | # include CarrierWave::ImageScience 6 | include CarrierWave::MiniMagick 7 | 8 | # Choose what kind of storage to use for this uploader: 9 | # storage :file 10 | storage :fog 11 | 12 | # Override the directory where uploaded files will be stored. 13 | # This is a sensible default for uploaders that are meant to be mounted: 14 | def store_dir 15 | "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" 16 | end 17 | 18 | # Provide a default URL as a default if there hasn't been a file uploaded: 19 | # def default_url 20 | # "/images/fallback/" + [version_name, "default.png"].compact.join('_') 21 | # end 22 | 23 | # Process files as they are uploaded: 24 | # process :scale => [200, 300] 25 | # 26 | # def scale(width, height) 27 | # # do something 28 | # end 29 | 30 | # Create different versions of your uploaded files: 31 | process :resize_to_fit => [800, 600] 32 | 33 | version :thumb do 34 | process :resize_to_fit => [80, 80] 35 | end 36 | 37 | version :medium do 38 | process :resize_to_fit => [200, 200] 39 | end 40 | 41 | # Add a white list of extensions which are allowed to be uploaded. 42 | # For images you might use something like this: 43 | def extension_white_list 44 | %w(jpg jpeg gif png) 45 | end 46 | 47 | # Override the filename of the uploaded files: 48 | # def filename 49 | # "something.jpg" if original_filename 50 | # end 51 | 52 | end 53 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= content_for?(:title) ? yield(:title) : "jQuery-File-Upload" %> 5 | <%= stylesheet_link_tag "application" %> 6 | <%= javascript_include_tag :application %> 7 | <%= csrf_meta_tag %> 8 | <%= yield(:head) %> 9 | 10 | 11 |
12 | <%= content_tag :h1, yield(:title) if show_title? %> 13 | <%= yield %> 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /app/views/pictures/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= content_for :head do %> 2 | <%= stylesheet_link_tag "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/base/jquery-ui.css", :id => "theme" %> 3 | <%= javascript_include_tag "http://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js" %> 4 | <% end %> 5 | 6 |
7 | <%= form_for @picture, :html => { :multipart => true } do |f| %> 8 |
9 | <%= f.label :title %>
10 | <%= f.text_field :title %> 11 |
12 |
13 |
14 | <%= f.label :description %>
15 | <%= f.text_field :description %> 16 |
17 |
18 |
19 | 23 | 24 | 25 | 26 |
27 | <% end %> 28 |
29 |
30 |
31 |
32 |
33 | 34 | <%= render :partial => "template-upload" %> 35 | <%= render :partial => "template-download" %> -------------------------------------------------------------------------------- /app/views/pictures/_template-download.html.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/pictures/_template-upload.html.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/pictures/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Editing picture

2 | 3 | <%= render 'form' %> 4 | 5 | <%= link_to 'Show', @picture %> | 6 | <%= link_to 'Back', pictures_path %> 7 | -------------------------------------------------------------------------------- /app/views/pictures/index.html.erb: -------------------------------------------------------------------------------- 1 |

Listing pictures

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | <% @pictures.each do |picture| %> 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | <% end %> 23 |
TitleDescriptionFile
<%= picture.title %><%= picture.description %><%= image_tag(picture.file_url(:thumb)) if picture.file.present? %><%= link_to 'Show', picture %><%= link_to 'Edit', edit_picture_path(picture) %><%= link_to 'Destroy', picture, confirm: 'Are you sure?', method: :delete %>
24 | 25 |
26 | 27 | <%= link_to 'New Picture', new_picture_path %> 28 | -------------------------------------------------------------------------------- /app/views/pictures/new.html.erb: -------------------------------------------------------------------------------- 1 |

New picture

2 | 3 | <%= render 'form' %> 4 | 5 | <%= link_to 'Back', pictures_path %> 6 | -------------------------------------------------------------------------------- /app/views/pictures/show.html.erb: -------------------------------------------------------------------------------- 1 |

<%= notice %>

2 | 3 |

4 | Title: 5 | <%= @picture.title %> 6 |

7 | 8 |

9 | Description: 10 | <%= @picture.description %> 11 |

12 | 13 |

14 | File: 15 | <%= image_tag(@picture.file_url(:medium)) %> 16 |

17 | 18 | 19 | <%= link_to 'Edit', edit_picture_path(@picture) %> | 20 | <%= link_to 'Back', pictures_path %> 21 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run CarrierwaveJqueryFileUpload::Application 5 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | # Pick the frameworks you want: 4 | require "active_record/railtie" 5 | require "action_controller/railtie" 6 | require "action_mailer/railtie" 7 | require "active_resource/railtie" 8 | require "sprockets/railtie" 9 | # require "rails/test_unit/railtie" 10 | 11 | if defined?(Bundler) 12 | # If you precompile assets before deploying to production, use this line 13 | Bundler.require(*Rails.groups(:assets => %w(development test))) 14 | # If you want your assets lazily compiled in production, use this line 15 | # Bundler.require(:default, :assets, Rails.env) 16 | end 17 | 18 | module CarrierwaveJqueryFileUpload 19 | class Application < Rails::Application 20 | # Settings in config/environments/* take precedence over those specified here. 21 | # Application configuration should go into files in config/initializers 22 | # -- all .rb files in that directory are automatically loaded. 23 | 24 | # Custom directories with classes and modules you want to be autoloadable. 25 | # config.autoload_paths += %W(#{config.root}/extras) 26 | 27 | # Only load the plugins named here, in the order given (default is alphabetical). 28 | # :all can be used as a placeholder for all plugins not explicitly named. 29 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 30 | 31 | # Activate observers that should always be running. 32 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 33 | 34 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 35 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 36 | # config.time_zone = 'Central Time (US & Canada)' 37 | 38 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 39 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 40 | # config.i18n.default_locale = :de 41 | 42 | # Configure the default encoding used in templates for Ruby 1.9. 43 | config.encoding = "utf-8" 44 | 45 | # Configure sensitive parameters which will be filtered from the log file. 46 | config.filter_parameters += [:password] 47 | 48 | # Enable the asset pipeline 49 | config.assets.enabled = true 50 | 51 | # Version of your assets, change this if you want to expire all your assets 52 | config.assets.version = '1.0' 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | # MySQL. Versions 4.1 and 5.0 are recommended. 2 | # 3 | # Install the MYSQL driver 4 | # gem install mysql2 5 | # 6 | # Ensure the MySQL gem is defined in your Gemfile 7 | # gem 'mysql2' 8 | # 9 | # And be sure to use new-style password hashing: 10 | # http://dev.mysql.com/doc/refman/5.0/en/old-client.html 11 | development: 12 | adapter: mysql2 13 | encoding: utf8 14 | reconnect: false 15 | database: cjfu_development 16 | pool: 5 17 | username: root 18 | password: 19 | socket: /tmp/mysql.sock 20 | 21 | # Warning: The database defined as "test" will be erased and 22 | # re-generated from your development database when you run "rake". 23 | # Do not set this db to the same as development or production. 24 | test: 25 | adapter: mysql2 26 | encoding: utf8 27 | reconnect: false 28 | database: cjfu_test 29 | pool: 5 30 | username: root 31 | password: 32 | socket: /tmp/mysql.sock 33 | 34 | production: 35 | adapter: mysql2 36 | encoding: utf8 37 | reconnect: false 38 | database: cjfu_production 39 | pool: 5 40 | username: root 41 | password: 42 | socket: /tmp/mysql.sock 43 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | CarrierwaveJqueryFileUpload::Application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | CarrierwaveJqueryFileUpload::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Log error messages when you accidentally call methods on nil. 10 | config.whiny_nils = true 11 | 12 | # Show full error reports and disable caching 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger 20 | config.active_support.deprecation = :log 21 | 22 | # Only use best-standards-support built into browsers 23 | config.action_dispatch.best_standards_support = :builtin 24 | 25 | # Do not compress assets 26 | config.assets.compress = false 27 | 28 | # Expands the lines which load the assets 29 | config.assets.debug = true 30 | end 31 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | CarrierwaveJqueryFileUpload::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = false 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = false 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to Rails.root.join("public/assets") 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | # config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Use a different logger for distributed setups 37 | # config.logger = SyslogLogger.new 38 | 39 | # Use a different cache store in production 40 | # config.cache_store = :mem_cache_store 41 | 42 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 43 | # config.action_controller.asset_host = "http://assets.example.com" 44 | 45 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 46 | # config.assets.precompile += %w( search.js ) 47 | 48 | # Disable delivery errors, bad email addresses will be ignored 49 | # config.action_mailer.raise_delivery_errors = false 50 | 51 | # Enable threaded mode 52 | # config.threadsafe! 53 | 54 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 55 | # the I18n.default_locale when a translation can not be found) 56 | config.i18n.fallbacks = true 57 | 58 | # Send deprecation notices to registered listeners 59 | config.active_support.deprecation = :notify 60 | end 61 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | CarrierwaveJqueryFileUpload::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = "public, max-age=3600" 13 | 14 | # Log error messages when you accidentally call methods on nil 15 | config.whiny_nils = true 16 | 17 | # Show full error reports and disable caching 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Use SQL instead of Active Record's schema dumper when creating the test database. 33 | # This is necessary if your schema can't be completely dumped by the schema dumper, 34 | # like if you have constraints or database-specific column types 35 | # config.active_record.schema_format = :sql 36 | 37 | # Print deprecation notices to the stderr 38 | config.active_support.deprecation = :stderr 39 | end 40 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format 4 | # (all these examples are active by default): 5 | # ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | # inflect.uncountable %w( fish sheep ) 10 | # end 11 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | CarrierwaveJqueryFileUpload::Application.config.secret_token = '355e0206740db869b3c3e5deb928f128d701acd9e1b637e174e9f0bc68149ffa20e7a1927af97cc1ed5fb1015ef0d3b44352f5be5f914d647193ad4482587ad1' 8 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | CarrierwaveJqueryFileUpload::Application.config.session_store :cookie_store, key: '_carrierwave_jquery_file_upload_session' 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # CarrierwaveJqueryFileUpload::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # Disable root element in JSON by default. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | CarrierwaveJqueryFileUpload::Application.routes.draw do 2 | resources :pictures 3 | root :to => 'pictures#index' 4 | 5 | # The priority is based upon order of creation: 6 | # first created -> highest priority. 7 | 8 | # Sample of regular route: 9 | # match 'products/:id' => 'catalog#view' 10 | # Keep in mind you can assign values other than :controller and :action 11 | 12 | # Sample of named route: 13 | # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase 14 | # This route can be invoked with purchase_url(:id => product.id) 15 | 16 | # Sample resource route (maps HTTP verbs to controller actions automatically): 17 | # resources :products 18 | 19 | # Sample resource route with options: 20 | # resources :products do 21 | # member do 22 | # get 'short' 23 | # post 'toggle' 24 | # end 25 | # 26 | # collection do 27 | # get 'sold' 28 | # end 29 | # end 30 | 31 | # Sample resource route with sub-resources: 32 | # resources :products do 33 | # resources :comments, :sales 34 | # resource :seller 35 | # end 36 | 37 | # Sample resource route with more complex sub-resources 38 | # resources :products do 39 | # resources :comments 40 | # resources :sales do 41 | # get 'recent', :on => :collection 42 | # end 43 | # end 44 | 45 | # Sample resource route within a namespace: 46 | # namespace :admin do 47 | # # Directs /admin/products/* to Admin::ProductsController 48 | # # (app/controllers/admin/products_controller.rb) 49 | # resources :products 50 | # end 51 | 52 | # You can have the root of your site routed with "root" 53 | # just remember to delete public/index.html. 54 | # root :to => 'welcome#index' 55 | 56 | # See how all your routes lay out with "rake routes" 57 | 58 | # This is a legacy wild controller route that's not recommended for RESTful applications. 59 | # Note: This route will make all actions in every controller accessible via GET requests. 60 | # match ':controller(/:action(/:id(.:format)))' 61 | end 62 | -------------------------------------------------------------------------------- /db/migrate/20111021151343_create_pictures.rb: -------------------------------------------------------------------------------- 1 | class CreatePictures < ActiveRecord::Migration 2 | def change 3 | create_table :pictures do |t| 4 | t.string :title 5 | t.string :description 6 | t.string :file 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended to check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(:version => 20111021151343) do 15 | 16 | create_table "pictures", :force => true do |t| 17 | t.string "title" 18 | t.string "description" 19 | t.string "file" 20 | t.datetime "created_at" 21 | t.datetime "updated_at" 22 | end 23 | 24 | end 25 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | -------------------------------------------------------------------------------- /doc/README_FOR_APP: -------------------------------------------------------------------------------- 1 | Use this README file to introduce your application and point to useful places in the API for learning more. 2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. 3 | -------------------------------------------------------------------------------- /lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/lib/assets/.gitkeep -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/lib/tasks/.gitkeep -------------------------------------------------------------------------------- /log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/log/.gitkeep -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |

We've been notified about this issue and we'll take a look at it shortly.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-Agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /vendor/assets/images/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/vendor/assets/images/close.png -------------------------------------------------------------------------------- /vendor/assets/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/vendor/assets/images/loading.gif -------------------------------------------------------------------------------- /vendor/assets/images/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/vendor/assets/images/next.png -------------------------------------------------------------------------------- /vendor/assets/images/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/vendor/assets/images/pause.png -------------------------------------------------------------------------------- /vendor/assets/images/pbar-ani.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/vendor/assets/images/pbar-ani.gif -------------------------------------------------------------------------------- /vendor/assets/images/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/vendor/assets/images/play.png -------------------------------------------------------------------------------- /vendor/assets/images/previous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/vendor/assets/images/previous.png -------------------------------------------------------------------------------- /vendor/assets/images/red_pen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/vendor/assets/images/red_pen.png -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery.fileupload-ui.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload User Interface Plugin 5.0.17 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2010, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * http://creativecommons.org/licenses/MIT/ 10 | */ 11 | 12 | /*jslint nomen: true, unparam: true, regexp: true */ 13 | /*global window, document, URL, webkitURL, FileReader, jQuery */ 14 | 15 | (function ($) { 16 | 'use strict'; 17 | 18 | // The UI version extends the basic fileupload widget and adds 19 | // a complete user interface based on the given upload/download 20 | // templates. 21 | $.widget('blueimpUI.fileupload', $.blueimp.fileupload, { 22 | 23 | options: { 24 | // By default, files added to the widget are uploaded as soon 25 | // as the user clicks on the start buttons. To enable automatic 26 | // uploads, set the following option to true: 27 | autoUpload: false, 28 | // The following option limits the number of files that are 29 | // allowed to be uploaded using this widget: 30 | maxNumberOfFiles: undefined, 31 | // The maximum allowed file size: 32 | maxFileSize: undefined, 33 | // The minimum allowed file size: 34 | minFileSize: 1, 35 | // The regular expression for allowed file types, matches 36 | // against either file type or file name: 37 | acceptFileTypes: /.+$/i, 38 | // The regular expression to define for which files a preview 39 | // image is shown, matched against the file type: 40 | previewFileTypes: /^image\/(gif|jpeg|png)$/, 41 | // The maximum width of the preview images: 42 | previewMaxWidth: 80, 43 | // The maximum height of the preview images: 44 | previewMaxHeight: 80, 45 | // By default, preview images are displayed as canvas elements 46 | // if supported by the browser. Set the following option to false 47 | // to always display preview images as img elements: 48 | previewAsCanvas: true, 49 | // The file upload template that is given as first argument to the 50 | // jQuery.tmpl method to render the file uploads: 51 | uploadTemplate: $('#template-upload'), 52 | // The file download template, that is given as first argument to the 53 | // jQuery.tmpl method to render the file downloads: 54 | downloadTemplate: $('#template-download'), 55 | // The expected data type of the upload response, sets the dataType 56 | // option of the $.ajax upload requests: 57 | dataType: 'json', 58 | 59 | // The add callback is invoked as soon as files are added to the fileupload 60 | // widget (via file input selection, drag & drop or add API call). 61 | // See the basic file upload widget for more information: 62 | add: function (e, data) { 63 | var that = $(this).data('fileupload'); 64 | that._adjustMaxNumberOfFiles(-data.files.length); 65 | data.isAdjusted = true; 66 | data.isValidated = that._validate(data.files); 67 | data.context = that._renderUpload(data.files) 68 | .appendTo($(this).find('.files')).fadeIn(function () { 69 | // Fix for IE7 and lower: 70 | $(this).show(); 71 | }).data('data', data); 72 | if ((that.options.autoUpload || data.autoUpload) && 73 | data.isValidated) { 74 | data.jqXHR = data.submit(); 75 | } 76 | }, 77 | // Callback for the start of each file upload request: 78 | send: function (e, data) { 79 | if (!data.isValidated) { 80 | var that = $(this).data('fileupload'); 81 | if (!data.isAdjusted) { 82 | that._adjustMaxNumberOfFiles(-data.files.length); 83 | } 84 | if (!that._validate(data.files)) { 85 | return false; 86 | } 87 | } 88 | if (data.context && data.dataType && 89 | data.dataType.substr(0, 6) === 'iframe') { 90 | // Iframe Transport does not support progress events. 91 | // In lack of an indeterminate progress bar, we set 92 | // the progress to 100%, showing the full animated bar: 93 | data.context.find('.ui-progressbar').progressbar( 94 | 'value', 95 | parseInt(100, 10) 96 | ); 97 | } 98 | }, 99 | // Callback for successful uploads: 100 | done: function (e, data) { 101 | var that = $(this).data('fileupload'); 102 | if (data.context) { 103 | data.context.each(function (index) { 104 | var file = ($.isArray(data.result) && 105 | data.result[index]) || {error: 'emptyResult'}; 106 | if (file.error) { 107 | that._adjustMaxNumberOfFiles(1); 108 | } 109 | $(this).fadeOut(function () { 110 | that._renderDownload([file]) 111 | .css('display', 'none') 112 | .replaceAll(this) 113 | .fadeIn(function () { 114 | // Fix for IE7 and lower: 115 | $(this).show(); 116 | }); 117 | }); 118 | }); 119 | } else { 120 | that._renderDownload(data.result) 121 | .css('display', 'none') 122 | .appendTo($(this).find('.files')) 123 | .fadeIn(function () { 124 | // Fix for IE7 and lower: 125 | $(this).show(); 126 | }); 127 | } 128 | }, 129 | // Callback for failed (abort or error) uploads: 130 | fail: function (e, data) { 131 | var that = $(this).data('fileupload'); 132 | that._adjustMaxNumberOfFiles(data.files.length); 133 | if (data.context) { 134 | data.context.each(function (index) { 135 | $(this).fadeOut(function () { 136 | if (data.errorThrown !== 'abort') { 137 | var file = data.files[index]; 138 | file.error = file.error || data.errorThrown 139 | || true; 140 | that._renderDownload([file]) 141 | .css('display', 'none') 142 | .replaceAll(this) 143 | .fadeIn(function () { 144 | // Fix for IE7 and lower: 145 | $(this).show(); 146 | }); 147 | } else { 148 | data.context.remove(); 149 | } 150 | }); 151 | }); 152 | } else if (data.errorThrown !== 'abort') { 153 | that._adjustMaxNumberOfFiles(-data.files.length); 154 | data.context = that._renderUpload(data.files) 155 | .css('display', 'none') 156 | .appendTo($(this).find('.files')) 157 | .fadeIn(function () { 158 | // Fix for IE7 and lower: 159 | $(this).show(); 160 | }).data('data', data); 161 | } 162 | }, 163 | // Callback for upload progress events: 164 | progress: function (e, data) { 165 | if (data.context) { 166 | data.context.find('.ui-progressbar').progressbar( 167 | 'value', 168 | parseInt(data.loaded / data.total * 100, 10) 169 | ); 170 | } 171 | }, 172 | // Callback for global upload progress events: 173 | progressall: function (e, data) { 174 | $(this).find('.fileupload-progressbar').progressbar( 175 | 'value', 176 | parseInt(data.loaded / data.total * 100, 10) 177 | ); 178 | }, 179 | // Callback for uploads start, equivalent to the global ajaxStart event: 180 | start: function () { 181 | $(this).find('.fileupload-progressbar') 182 | .progressbar('value', 0).fadeIn(); 183 | }, 184 | // Callback for uploads stop, equivalent to the global ajaxStop event: 185 | stop: function () { 186 | $(this).find('.fileupload-progressbar').fadeOut(); 187 | }, 188 | // Callback for file deletion: 189 | destroy: function (e, data) { 190 | var that = $(this).data('fileupload'); 191 | if (data.url) { 192 | $.ajax(data) 193 | .success(function () { 194 | that._adjustMaxNumberOfFiles(1); 195 | $(this).fadeOut(function () { 196 | $(this).remove(); 197 | }); 198 | }); 199 | } else { 200 | that._adjustMaxNumberOfFiles(1); 201 | data.context.fadeOut(function () { 202 | $(this).remove(); 203 | }); 204 | } 205 | } 206 | }, 207 | 208 | // Scales the given image (img HTML element) 209 | // using the given options. 210 | // Returns a canvas object if the canvas option is true 211 | // and the browser supports canvas, else the scaled image: 212 | _scaleImage: function (img, options) { 213 | options = options || {}; 214 | var canvas = document.createElement('canvas'), 215 | scale = Math.min( 216 | (options.maxWidth || img.width) / img.width, 217 | (options.maxHeight || img.height) / img.height 218 | ); 219 | if (scale >= 1) { 220 | scale = Math.max( 221 | (options.minWidth || img.width) / img.width, 222 | (options.minHeight || img.height) / img.height 223 | ); 224 | } 225 | img.width = parseInt(img.width * scale, 10); 226 | img.height = parseInt(img.height * scale, 10); 227 | if (!options.canvas || !canvas.getContext) { 228 | return img; 229 | } 230 | canvas.width = img.width; 231 | canvas.height = img.height; 232 | canvas.getContext('2d') 233 | .drawImage(img, 0, 0, img.width, img.height); 234 | return canvas; 235 | }, 236 | 237 | _createObjectURL: function (file) { 238 | var undef = 'undefined', 239 | urlAPI = (typeof window.createObjectURL !== undef && window) || 240 | (typeof URL !== undef && URL) || 241 | (typeof webkitURL !== undef && webkitURL); 242 | return urlAPI ? urlAPI.createObjectURL(file) : false; 243 | }, 244 | 245 | _revokeObjectURL: function (url) { 246 | var undef = 'undefined', 247 | urlAPI = (typeof window.revokeObjectURL !== undef && window) || 248 | (typeof URL !== undef && URL) || 249 | (typeof webkitURL !== undef && webkitURL); 250 | return urlAPI ? urlAPI.revokeObjectURL(url) : false; 251 | }, 252 | 253 | // Loads a given File object via FileReader interface, 254 | // invokes the callback with a data url: 255 | _loadFile: function (file, callback) { 256 | if (typeof FileReader !== 'undefined' && 257 | FileReader.prototype.readAsDataURL) { 258 | var fileReader = new FileReader(); 259 | fileReader.onload = function (e) { 260 | callback(e.target.result); 261 | }; 262 | fileReader.readAsDataURL(file); 263 | return true; 264 | } 265 | return false; 266 | }, 267 | 268 | // Loads an image for a given File object. 269 | // Invokes the callback with an img or optional canvas 270 | // element (if supported by the browser) as parameter: 271 | _loadImage: function (file, callback, options) { 272 | var that = this, 273 | url, 274 | img; 275 | if (!options || !options.fileTypes || 276 | options.fileTypes.test(file.type)) { 277 | url = this._createObjectURL(file); 278 | img = $('').bind('load', function () { 279 | $(this).unbind('load'); 280 | that._revokeObjectURL(url); 281 | callback(that._scaleImage(img[0], options)); 282 | }); 283 | if (url) { 284 | img.prop('src', url); 285 | return true; 286 | } else { 287 | return this._loadFile(file, function (url) { 288 | img.prop('src', url); 289 | }); 290 | } 291 | } 292 | return false; 293 | }, 294 | 295 | // Link handler, that allows to download files 296 | // by drag & drop of the links to the desktop: 297 | _enableDragToDesktop: function () { 298 | var link = $(this), 299 | url = link.prop('href'), 300 | name = decodeURIComponent(url.split('/').pop()) 301 | .replace(/:/g, '-'), 302 | type = 'application/octet-stream'; 303 | link.bind('dragstart', function (e) { 304 | try { 305 | e.originalEvent.dataTransfer.setData( 306 | 'DownloadURL', 307 | [type, name, url].join(':') 308 | ); 309 | } catch (err) {} 310 | }); 311 | }, 312 | 313 | _adjustMaxNumberOfFiles: function (operand) { 314 | if (typeof this.options.maxNumberOfFiles === 'number') { 315 | this.options.maxNumberOfFiles += operand; 316 | if (this.options.maxNumberOfFiles < 1) { 317 | this._disableFileInputButton(); 318 | } else { 319 | this._enableFileInputButton(); 320 | } 321 | } 322 | }, 323 | 324 | _formatFileSize: function (file) { 325 | if (typeof file.size !== 'number') { 326 | return ''; 327 | } 328 | if (file.size >= 1000000000) { 329 | return (file.size / 1000000000).toFixed(2) + ' GB'; 330 | } 331 | if (file.size >= 1000000) { 332 | return (file.size / 1000000).toFixed(2) + ' MB'; 333 | } 334 | return (file.size / 1000).toFixed(2) + ' KB'; 335 | }, 336 | 337 | _hasError: function (file) { 338 | if (file.error) { 339 | return file.error; 340 | } 341 | // The number of added files is subtracted from 342 | // maxNumberOfFiles before validation, so we check if 343 | // maxNumberOfFiles is below 0 (instead of below 1): 344 | if (this.options.maxNumberOfFiles < 0) { 345 | return 'maxNumberOfFiles'; 346 | } 347 | // Files are accepted if either the file type or the file name 348 | // matches against the acceptFileTypes regular expression, as 349 | // only browsers with support for the File API report the type: 350 | if (!(this.options.acceptFileTypes.test(file.type) || 351 | this.options.acceptFileTypes.test(file.name))) { 352 | return 'acceptFileTypes'; 353 | } 354 | if (this.options.maxFileSize && 355 | file.size > this.options.maxFileSize) { 356 | return 'maxFileSize'; 357 | } 358 | if (typeof file.size === 'number' && 359 | file.size < this.options.minFileSize) { 360 | return 'minFileSize'; 361 | } 362 | return null; 363 | }, 364 | 365 | _validate: function (files) { 366 | var that = this, 367 | valid = !!files.length; 368 | $.each(files, function (index, file) { 369 | file.error = that._hasError(file); 370 | if (file.error) { 371 | valid = false; 372 | } 373 | }); 374 | return valid; 375 | }, 376 | 377 | _uploadTemplateHelper: function (file) { 378 | file.sizef = this._formatFileSize(file); 379 | return file; 380 | }, 381 | 382 | _renderUploadTemplate: function (files) { 383 | var that = this; 384 | return $.tmpl( 385 | this.options.uploadTemplate, 386 | $.map(files, function (file) { 387 | return that._uploadTemplateHelper(file); 388 | }) 389 | ); 390 | }, 391 | 392 | _renderUpload: function (files) { 393 | var that = this, 394 | options = this.options, 395 | tmpl = this._renderUploadTemplate(files), 396 | isValidated = this._validate(files); 397 | if (!(tmpl instanceof $)) { 398 | return $(); 399 | } 400 | tmpl.css('display', 'none'); 401 | // .slice(1).remove().end().first() removes all but the first 402 | // element and selects only the first for the jQuery collection: 403 | tmpl.find('.progress div').slice( 404 | isValidated ? 1 : 0 405 | ).remove().end().first() 406 | .progressbar(); 407 | tmpl.find('.start button').slice( 408 | this.options.autoUpload || !isValidated ? 0 : 1 409 | ).remove().end().first() 410 | .button({ 411 | text: false, 412 | icons: {primary: 'ui-icon-circle-arrow-e'} 413 | }); 414 | tmpl.find('.cancel button').slice(1).remove().end().first() 415 | .button({ 416 | text: false, 417 | icons: {primary: 'ui-icon-cancel'} 418 | }); 419 | tmpl.find('.preview').each(function (index, node) { 420 | that._loadImage( 421 | files[index], 422 | function (img) { 423 | $(img).hide().appendTo(node).fadeIn(); 424 | }, 425 | { 426 | maxWidth: options.previewMaxWidth, 427 | maxHeight: options.previewMaxHeight, 428 | fileTypes: options.previewFileTypes, 429 | canvas: options.previewAsCanvas 430 | } 431 | ); 432 | }); 433 | return tmpl; 434 | }, 435 | 436 | _downloadTemplateHelper: function (file) { 437 | file.sizef = this._formatFileSize(file); 438 | return file; 439 | }, 440 | 441 | _renderDownloadTemplate: function (files) { 442 | var that = this; 443 | return $.tmpl( 444 | this.options.downloadTemplate, 445 | $.map(files, function (file) { 446 | return that._downloadTemplateHelper(file); 447 | }) 448 | ); 449 | }, 450 | 451 | _renderDownload: function (files) { 452 | var tmpl = this._renderDownloadTemplate(files); 453 | if (!(tmpl instanceof $)) { 454 | return $(); 455 | } 456 | tmpl.css('display', 'none'); 457 | tmpl.find('.delete button').button({ 458 | text: false, 459 | icons: {primary: 'ui-icon-trash'} 460 | }); 461 | tmpl.find('a').each(this._enableDragToDesktop); 462 | return tmpl; 463 | }, 464 | 465 | _startHandler: function (e) { 466 | e.preventDefault(); 467 | var tmpl = $(this).closest('.template-upload'), 468 | data = tmpl.data('data'); 469 | if (data && data.submit && !data.jqXHR) { 470 | data.jqXHR = data.submit(); 471 | $(this).fadeOut(); 472 | } 473 | }, 474 | 475 | _cancelHandler: function (e) { 476 | e.preventDefault(); 477 | var tmpl = $(this).closest('.template-upload'), 478 | data = tmpl.data('data') || {}; 479 | if (!data.jqXHR) { 480 | data.errorThrown = 'abort'; 481 | e.data.fileupload._trigger('fail', e, data); 482 | } else { 483 | data.jqXHR.abort(); 484 | } 485 | }, 486 | 487 | _deleteHandler: function (e) { 488 | e.preventDefault(); 489 | var button = $(this); 490 | e.data.fileupload._trigger('destroy', e, { 491 | context: button.closest('.template-download'), 492 | url: button.attr('data-url'), 493 | type: button.attr('data-type'), 494 | dataType: e.data.fileupload.options.dataType 495 | }); 496 | }, 497 | 498 | _initEventHandlers: function () { 499 | $.blueimp.fileupload.prototype._initEventHandlers.call(this); 500 | var filesList = this.element.find('.files'), 501 | eventData = {fileupload: this}; 502 | filesList.find('.start button') 503 | .live( 504 | 'click.' + this.options.namespace, 505 | eventData, 506 | this._startHandler 507 | ); 508 | filesList.find('.cancel button') 509 | .live( 510 | 'click.' + this.options.namespace, 511 | eventData, 512 | this._cancelHandler 513 | ); 514 | filesList.find('.delete button') 515 | .live( 516 | 'click.' + this.options.namespace, 517 | eventData, 518 | this._deleteHandler 519 | ); 520 | }, 521 | 522 | _destroyEventHandlers: function () { 523 | var filesList = this.element.find('.files'); 524 | filesList.find('.start button') 525 | .die('click.' + this.options.namespace); 526 | filesList.find('.cancel button') 527 | .die('click.' + this.options.namespace); 528 | filesList.find('.delete button') 529 | .die('click.' + this.options.namespace); 530 | $.blueimp.fileupload.prototype._destroyEventHandlers.call(this); 531 | }, 532 | 533 | _initFileUploadButtonBar: function () { 534 | var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'), 535 | filesList = this.element.find('.files'), 536 | ns = this.options.namespace; 537 | fileUploadButtonBar 538 | .addClass('ui-widget-header ui-corner-top'); 539 | this.element.find('.fileinput-button').each(function () { 540 | var fileInput = $(this).find('input:file').detach(); 541 | $(this).button({icons: {primary: 'ui-icon-plusthick'}}) 542 | .append(fileInput); 543 | }); 544 | fileUploadButtonBar.find('.start') 545 | .button({icons: {primary: 'ui-icon-circle-arrow-e'}}) 546 | .bind('click.' + ns, function (e) { 547 | e.preventDefault(); 548 | filesList.find('.start button').click(); 549 | }); 550 | fileUploadButtonBar.find('.cancel') 551 | .button({icons: {primary: 'ui-icon-cancel'}}) 552 | .bind('click.' + ns, function (e) { 553 | e.preventDefault(); 554 | filesList.find('.cancel button').click(); 555 | }); 556 | fileUploadButtonBar.find('.delete') 557 | .button({icons: {primary: 'ui-icon-trash'}}) 558 | .bind('click.' + ns, function (e) { 559 | e.preventDefault(); 560 | filesList.find('.delete button').click(); 561 | }); 562 | }, 563 | 564 | _destroyFileUploadButtonBar: function () { 565 | this.element.find('.fileupload-buttonbar') 566 | .removeClass('ui-widget-header ui-corner-top'); 567 | this.element.find('.fileinput-button').each(function () { 568 | var fileInput = $(this).find('input:file').detach(); 569 | $(this).button('destroy') 570 | .append(fileInput); 571 | }); 572 | this.element.find('.fileupload-buttonbar button') 573 | .unbind('click.' + this.options.namespace) 574 | .button('destroy'); 575 | }, 576 | 577 | _enableFileInputButton: function () { 578 | this.element.find('.fileinput-button input:file:disabled') 579 | .each(function () { 580 | var fileInput = $(this), 581 | button = fileInput.parent(); 582 | fileInput.detach().prop('disabled', false); 583 | button.button('enable').append(fileInput); 584 | }); 585 | }, 586 | 587 | _disableFileInputButton: function () { 588 | this.element.find('.fileinput-button input:file:enabled') 589 | .each(function () { 590 | var fileInput = $(this), 591 | button = fileInput.parent(); 592 | fileInput.detach().prop('disabled', true); 593 | button.button('disable').append(fileInput); 594 | }); 595 | }, 596 | 597 | _initTemplates: function () { 598 | // Handle cases where the templates are defined 599 | // after the widget library has been included: 600 | if (this.options.uploadTemplate instanceof $ && 601 | !this.options.uploadTemplate.length) { 602 | this.options.uploadTemplate = $( 603 | this.options.uploadTemplate.selector 604 | ); 605 | } 606 | if (this.options.downloadTemplate instanceof $ && 607 | !this.options.downloadTemplate.length) { 608 | this.options.downloadTemplate = $( 609 | this.options.downloadTemplate.selector 610 | ); 611 | } 612 | }, 613 | 614 | _create: function () { 615 | $.blueimp.fileupload.prototype._create.call(this); 616 | this._initTemplates(); 617 | this.element 618 | .addClass('ui-widget'); 619 | this._initFileUploadButtonBar(); 620 | this.element.find('.fileupload-content') 621 | .addClass('ui-widget-content ui-corner-bottom'); 622 | this.element.find('.fileupload-progressbar') 623 | .hide().progressbar(); 624 | }, 625 | 626 | destroy: function () { 627 | this.element.find('.fileupload-progressbar') 628 | .progressbar('destroy'); 629 | this.element.find('.fileupload-content') 630 | .removeClass('ui-widget-content ui-corner-bottom'); 631 | this._destroyFileUploadButtonBar(); 632 | this.element.removeClass('ui-widget'); 633 | $.blueimp.fileupload.prototype.destroy.call(this); 634 | }, 635 | 636 | enable: function () { 637 | $.blueimp.fileupload.prototype.enable.call(this); 638 | this.element.find(':ui-button').not('.fileinput-button') 639 | .button('enable'); 640 | this._enableFileInputButton(); 641 | }, 642 | 643 | disable: function () { 644 | this.element.find(':ui-button').not('.fileinput-button') 645 | .button('disable'); 646 | this._disableFileInputButton(); 647 | $.blueimp.fileupload.prototype.disable.call(this); 648 | } 649 | 650 | }); 651 | 652 | }(jQuery)); -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery.fileupload.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload Plugin 5.2.1 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2010, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * http://creativecommons.org/licenses/MIT/ 10 | */ 11 | 12 | /*jslint nomen: true, unparam: true, regexp: true */ 13 | /*global document, XMLHttpRequestUpload, Blob, File, FormData, location, jQuery */ 14 | 15 | (function ($) { 16 | 'use strict'; 17 | 18 | // The fileupload widget listens for change events on file input fields 19 | // defined via fileInput setting and drop events of the given dropZone. 20 | // In addition to the default jQuery Widget methods, the fileupload widget 21 | // exposes the "add" and "send" methods, to add or directly send files 22 | // using the fileupload API. 23 | // By default, files added via file input selection, drag & drop or 24 | // "add" method are uploaded immediately, but it is possible to override 25 | // the "add" callback option to queue file uploads. 26 | $.widget('blueimp.fileupload', { 27 | 28 | options: { 29 | // The namespace used for event handler binding on the dropZone and 30 | // fileInput collections. 31 | // If not set, the name of the widget ("fileupload") is used. 32 | namespace: undefined, 33 | // The drop target collection, by the default the complete document. 34 | // Set to null or an empty collection to disable drag & drop support: 35 | dropZone: $(document), 36 | // The file input field collection, that is listened for change events. 37 | // If undefined, it is set to the file input fields inside 38 | // of the widget element on plugin initialization. 39 | // Set to null or an empty collection to disable the change listener. 40 | fileInput: undefined, 41 | // By default, the file input field is replaced with a clone after 42 | // each input field change event. This is required for iframe transport 43 | // queues and allows change events to be fired for the same file 44 | // selection, but can be disabled by setting the following option to false: 45 | replaceFileInput: true, 46 | // The parameter name for the file form data (the request argument name). 47 | // If undefined or empty, the name property of the file input field is 48 | // used, or "files[]" if the file input name property is also empty: 49 | paramName: undefined, 50 | // By default, each file of a selection is uploaded using an individual 51 | // request for XHR type uploads. Set to false to upload file 52 | // selections in one request each: 53 | singleFileUploads: true, 54 | // To limit the number of files uploaded with one XHR request, 55 | // set the following option to an integer greater than 0: 56 | limitMultiFileUploads: undefined, 57 | // Set the following option to true to issue all file upload requests 58 | // in a sequential order: 59 | sequentialUploads: false, 60 | // To limit the number of concurrent uploads, 61 | // set the following option to an integer greater than 0: 62 | limitConcurrentUploads: undefined, 63 | // Set the following option to true to force iframe transport uploads: 64 | forceIframeTransport: false, 65 | // By default, XHR file uploads are sent as multipart/form-data. 66 | // The iframe transport is always using multipart/form-data. 67 | // Set to false to enable non-multipart XHR uploads: 68 | multipart: true, 69 | // To upload large files in smaller chunks, set the following option 70 | // to a preferred maximum chunk size. If set to 0, null or undefined, 71 | // or the browser does not support the required Blob API, files will 72 | // be uploaded as a whole. 73 | maxChunkSize: undefined, 74 | // When a non-multipart upload or a chunked multipart upload has been 75 | // aborted, this option can be used to resume the upload by setting 76 | // it to the size of the already uploaded bytes. This option is most 77 | // useful when modifying the options object inside of the "add" or 78 | // "send" callbacks, as the options are cloned for each file upload. 79 | uploadedBytes: undefined, 80 | // By default, failed (abort or error) file uploads are removed from the 81 | // global progress calculation. Set the following option to false to 82 | // prevent recalculating the global progress data: 83 | recalculateProgress: true, 84 | 85 | // Additional form data to be sent along with the file uploads can be set 86 | // using this option, which accepts an array of objects with name and 87 | // value properties, a function returning such an array, a FormData 88 | // object (for XHR file uploads), or a simple object. 89 | // The form of the first fileInput is given as parameter to the function: 90 | formData: function (form) { 91 | return form.serializeArray(); 92 | }, 93 | 94 | // The add callback is invoked as soon as files are added to the fileupload 95 | // widget (via file input selection, drag & drop or add API call). 96 | // If the singleFileUploads option is enabled, this callback will be 97 | // called once for each file in the selection for XHR file uplaods, else 98 | // once for each file selection. 99 | // The upload starts when the submit method is invoked on the data parameter. 100 | // The data object contains a files property holding the added files 101 | // and allows to override plugin options as well as define ajax settings. 102 | // Listeners for this callback can also be bound the following way: 103 | // .bind('fileuploadadd', func); 104 | // data.submit() returns a Promise object and allows to attach additional 105 | // handlers using jQuery's Deferred callbacks: 106 | // data.submit().done(func).fail(func).always(func); 107 | add: function (e, data) { 108 | data.submit(); 109 | }, 110 | 111 | // Other callbacks: 112 | // Callback for the start of each file upload request: 113 | // send: function (e, data) {}, // .bind('fileuploadsend', func); 114 | // Callback for successful uploads: 115 | // done: function (e, data) {}, // .bind('fileuploaddone', func); 116 | // Callback for failed (abort or error) uploads: 117 | // fail: function (e, data) {}, // .bind('fileuploadfail', func); 118 | // Callback for completed (success, abort or error) requests: 119 | // always: function (e, data) {}, // .bind('fileuploadalways', func); 120 | // Callback for upload progress events: 121 | // progress: function (e, data) {}, // .bind('fileuploadprogress', func); 122 | // Callback for global upload progress events: 123 | // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func); 124 | // Callback for uploads start, equivalent to the global ajaxStart event: 125 | // start: function (e) {}, // .bind('fileuploadstart', func); 126 | // Callback for uploads stop, equivalent to the global ajaxStop event: 127 | // stop: function (e) {}, // .bind('fileuploadstop', func); 128 | // Callback for change events of the fileInput collection: 129 | // change: function (e, data) {}, // .bind('fileuploadchange', func); 130 | // Callback for drop events of the dropZone collection: 131 | // drop: function (e, data) {}, // .bind('fileuploaddrop', func); 132 | // Callback for dragover events of the dropZone collection: 133 | // dragover: function (e) {}, // .bind('fileuploaddragover', func); 134 | 135 | // The plugin options are used as settings object for the ajax calls. 136 | // The following are jQuery ajax settings required for the file uploads: 137 | processData: false, 138 | contentType: false, 139 | cache: false 140 | }, 141 | 142 | // A list of options that require a refresh after assigning a new value: 143 | _refreshOptionsList: ['namespace', 'dropZone', 'fileInput'], 144 | 145 | _isXHRUpload: function (options) { 146 | var undef = 'undefined'; 147 | return !options.forceIframeTransport && 148 | typeof XMLHttpRequestUpload !== undef && typeof File !== undef && 149 | (!options.multipart || typeof FormData !== undef); 150 | }, 151 | 152 | _getFormData: function (options) { 153 | var formData; 154 | if (typeof options.formData === 'function') { 155 | return options.formData(options.form); 156 | } else if ($.isArray(options.formData)) { 157 | return options.formData; 158 | } else if (options.formData) { 159 | formData = []; 160 | $.each(options.formData, function (name, value) { 161 | formData.push({name: name, value: value}); 162 | }); 163 | return formData; 164 | } 165 | return []; 166 | }, 167 | 168 | _getTotal: function (files) { 169 | var total = 0; 170 | $.each(files, function (index, file) { 171 | total += file.size || 1; 172 | }); 173 | return total; 174 | }, 175 | 176 | _onProgress: function (e, data) { 177 | if (e.lengthComputable) { 178 | var total = data.total || this._getTotal(data.files), 179 | loaded = parseInt( 180 | e.loaded / e.total * (data.chunkSize || total), 181 | 10 182 | ) + (data.uploadedBytes || 0); 183 | this._loaded += loaded - (data.loaded || data.uploadedBytes || 0); 184 | data.lengthComputable = true; 185 | data.loaded = loaded; 186 | data.total = total; 187 | // Trigger a custom progress event with a total data property set 188 | // to the file size(s) of the current upload and a loaded data 189 | // property calculated accordingly: 190 | this._trigger('progress', e, data); 191 | // Trigger a global progress event for all current file uploads, 192 | // including ajax calls queued for sequential file uploads: 193 | this._trigger('progressall', e, { 194 | lengthComputable: true, 195 | loaded: this._loaded, 196 | total: this._total 197 | }); 198 | } 199 | }, 200 | 201 | _initProgressListener: function (options) { 202 | var that = this, 203 | xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); 204 | // Accesss to the native XHR object is required to add event listeners 205 | // for the upload progress event: 206 | if (xhr.upload && xhr.upload.addEventListener) { 207 | xhr.upload.addEventListener('progress', function (e) { 208 | that._onProgress(e, options); 209 | }, false); 210 | options.xhr = function () { 211 | return xhr; 212 | }; 213 | } 214 | }, 215 | 216 | _initXHRData: function (options) { 217 | var formData, 218 | file = options.files[0]; 219 | if (!options.multipart || options.blob) { 220 | // For non-multipart uploads and chunked uploads, 221 | // file meta data is not part of the request body, 222 | // so we transmit this data as part of the HTTP headers. 223 | // For cross domain requests, these headers must be allowed 224 | // via Access-Control-Allow-Headers or removed using 225 | // the beforeSend callback: 226 | options.headers = $.extend(options.headers, { 227 | 'X-File-Name': file.name, 228 | 'X-File-Type': file.type, 229 | 'X-File-Size': file.size 230 | }); 231 | if (!options.blob) { 232 | // Non-chunked non-multipart upload: 233 | options.contentType = file.type; 234 | options.data = file; 235 | } else if (!options.multipart) { 236 | // Chunked non-multipart upload: 237 | options.contentType = 'application/octet-stream'; 238 | options.data = options.blob; 239 | } 240 | } 241 | if (options.multipart && typeof FormData !== 'undefined') { 242 | if (options.formData instanceof FormData) { 243 | formData = options.formData; 244 | } else { 245 | formData = new FormData(); 246 | $.each(this._getFormData(options), function (index, field) { 247 | formData.append(field.name, field.value); 248 | }); 249 | } 250 | if (options.blob) { 251 | formData.append(options.paramName, options.blob); 252 | } else { 253 | $.each(options.files, function (index, file) { 254 | // File objects are also Blob instances. 255 | // This check allows the tests to run with 256 | // dummy objects: 257 | if (file instanceof Blob) { 258 | formData.append(options.paramName, file); 259 | } 260 | }); 261 | } 262 | options.data = formData; 263 | } 264 | // Blob reference is not needed anymore, free memory: 265 | options.blob = null; 266 | }, 267 | 268 | _initIframeSettings: function (options) { 269 | // Setting the dataType to iframe enables the iframe transport: 270 | options.dataType = 'iframe ' + (options.dataType || ''); 271 | // The iframe transport accepts a serialized array as form data: 272 | options.formData = this._getFormData(options); 273 | }, 274 | 275 | _initDataSettings: function (options) { 276 | if (this._isXHRUpload(options)) { 277 | if (!this._chunkedUpload(options, true)) { 278 | if (!options.data) { 279 | this._initXHRData(options); 280 | } 281 | this._initProgressListener(options); 282 | } 283 | } else { 284 | this._initIframeSettings(options); 285 | } 286 | }, 287 | 288 | _initFormSettings: function (options) { 289 | // Retrieve missing options from the input field and the 290 | // associated form, if available: 291 | if (!options.form || !options.form.length) { 292 | options.form = $(options.fileInput.prop('form')); 293 | } 294 | if (!options.paramName) { 295 | options.paramName = options.fileInput.prop('name') || 296 | 'files[]'; 297 | } 298 | if (!options.url) { 299 | options.url = options.form.prop('action') || location.href; 300 | } 301 | // The HTTP request method must be "POST" or "PUT": 302 | options.type = (options.type || options.form.prop('method') || '') 303 | .toUpperCase(); 304 | if (options.type !== 'POST' && options.type !== 'PUT') { 305 | options.type = 'POST'; 306 | } 307 | }, 308 | 309 | _getAJAXSettings: function (data) { 310 | var options = $.extend({}, this.options, data); 311 | this._initFormSettings(options); 312 | this._initDataSettings(options); 313 | return options; 314 | }, 315 | 316 | // Maps jqXHR callbacks to the equivalent 317 | // methods of the given Promise object: 318 | _enhancePromise: function (promise) { 319 | promise.success = promise.done; 320 | promise.error = promise.fail; 321 | promise.complete = promise.always; 322 | return promise; 323 | }, 324 | 325 | // Creates and returns a Promise object enhanced with 326 | // the jqXHR methods abort, success, error and complete: 327 | _getXHRPromise: function (resolveOrReject, context, args) { 328 | var dfd = $.Deferred(), 329 | promise = dfd.promise(); 330 | context = context || this.options.context || promise; 331 | if (resolveOrReject === true) { 332 | dfd.resolveWith(context, args); 333 | } else if (resolveOrReject === false) { 334 | dfd.rejectWith(context, args); 335 | } 336 | promise.abort = dfd.promise; 337 | return this._enhancePromise(promise); 338 | }, 339 | 340 | // Uploads a file in multiple, sequential requests 341 | // by splitting the file up in multiple blob chunks. 342 | // If the second parameter is true, only tests if the file 343 | // should be uploaded in chunks, but does not invoke any 344 | // upload requests: 345 | _chunkedUpload: function (options, testOnly) { 346 | var that = this, 347 | file = options.files[0], 348 | fs = file.size, 349 | ub = options.uploadedBytes = options.uploadedBytes || 0, 350 | mcs = options.maxChunkSize || fs, 351 | // Use the Blob methods with the slice implementation 352 | // according to the W3C Blob API specification: 353 | slice = file.webkitSlice || file.mozSlice || file.slice, 354 | upload, 355 | n, 356 | jqXHR, 357 | pipe; 358 | if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) || 359 | options.data) { 360 | return false; 361 | } 362 | if (testOnly) { 363 | return true; 364 | } 365 | if (ub >= fs) { 366 | file.error = 'uploadedBytes'; 367 | return this._getXHRPromise(false); 368 | } 369 | // n is the number of blobs to upload, 370 | // calculated via filesize, uploaded bytes and max chunk size: 371 | n = Math.ceil((fs - ub) / mcs); 372 | // The chunk upload method accepting the chunk number as parameter: 373 | upload = function (i) { 374 | if (!i) { 375 | return that._getXHRPromise(true); 376 | } 377 | // Upload the blobs in sequential order: 378 | return upload(i -= 1).pipe(function () { 379 | // Clone the options object for each chunk upload: 380 | var o = $.extend({}, options); 381 | o.blob = slice.call( 382 | file, 383 | ub + i * mcs, 384 | ub + (i + 1) * mcs 385 | ); 386 | // Store the current chunk size, as the blob itself 387 | // will be dereferenced after data processing: 388 | o.chunkSize = o.blob.size; 389 | // Process the upload data (the blob and potential form data): 390 | that._initXHRData(o); 391 | // Add progress listeners for this chunk upload: 392 | that._initProgressListener(o); 393 | jqXHR = ($.ajax(o) || that._getXHRPromise(false, o.context)) 394 | .done(function () { 395 | // Create a progress event if upload is done and 396 | // no progress event has been invoked for this chunk: 397 | if (!o.loaded) { 398 | that._onProgress($.Event('progress', { 399 | lengthComputable: true, 400 | loaded: o.chunkSize, 401 | total: o.chunkSize 402 | }), o); 403 | } 404 | options.uploadedBytes = o.uploadedBytes 405 | += o.chunkSize; 406 | }); 407 | return jqXHR; 408 | }); 409 | }; 410 | // Return the piped Promise object, enhanced with an abort method, 411 | // which is delegated to the jqXHR object of the current upload, 412 | // and jqXHR callbacks mapped to the equivalent Promise methods: 413 | pipe = upload(n); 414 | pipe.abort = function () { 415 | return jqXHR.abort(); 416 | }; 417 | return this._enhancePromise(pipe); 418 | }, 419 | 420 | _beforeSend: function (e, data) { 421 | if (this._active === 0) { 422 | // the start callback is triggered when an upload starts 423 | // and no other uploads are currently running, 424 | // equivalent to the global ajaxStart event: 425 | this._trigger('start'); 426 | } 427 | this._active += 1; 428 | // Initialize the global progress values: 429 | this._loaded += data.uploadedBytes || 0; 430 | this._total += this._getTotal(data.files); 431 | }, 432 | 433 | _onDone: function (result, textStatus, jqXHR, options) { 434 | if (!this._isXHRUpload(options)) { 435 | // Create a progress event for each iframe load: 436 | this._onProgress($.Event('progress', { 437 | lengthComputable: true, 438 | loaded: 1, 439 | total: 1 440 | }), options); 441 | } 442 | options.result = result; 443 | options.textStatus = textStatus; 444 | options.jqXHR = jqXHR; 445 | this._trigger('done', null, options); 446 | }, 447 | 448 | _onFail: function (jqXHR, textStatus, errorThrown, options) { 449 | options.jqXHR = jqXHR; 450 | options.textStatus = textStatus; 451 | options.errorThrown = errorThrown; 452 | this._trigger('fail', null, options); 453 | if (options.recalculateProgress) { 454 | // Remove the failed (error or abort) file upload from 455 | // the global progress calculation: 456 | this._loaded -= options.loaded || options.uploadedBytes || 0; 457 | this._total -= options.total || this._getTotal(options.files); 458 | } 459 | }, 460 | 461 | _onAlways: function (result, textStatus, jqXHR, errorThrown, options) { 462 | this._active -= 1; 463 | options.result = result; 464 | options.textStatus = textStatus; 465 | options.jqXHR = jqXHR; 466 | options.errorThrown = errorThrown; 467 | this._trigger('always', null, options); 468 | if (this._active === 0) { 469 | // The stop callback is triggered when all uploads have 470 | // been completed, equivalent to the global ajaxStop event: 471 | this._trigger('stop'); 472 | // Reset the global progress values: 473 | this._loaded = this._total = 0; 474 | } 475 | }, 476 | 477 | _onSend: function (e, data) { 478 | var that = this, 479 | jqXHR, 480 | slot, 481 | pipe, 482 | options = that._getAJAXSettings(data), 483 | send = function (resolve, args) { 484 | that._sending += 1; 485 | jqXHR = jqXHR || ( 486 | (resolve !== false && 487 | that._trigger('send', e, options) !== false && 488 | (that._chunkedUpload(options) || $.ajax(options))) || 489 | that._getXHRPromise(false, options.context, args) 490 | ).done(function (result, textStatus, jqXHR) { 491 | that._onDone(result, textStatus, jqXHR, options); 492 | }).fail(function (jqXHR, textStatus, errorThrown) { 493 | that._onFail(jqXHR, textStatus, errorThrown, options); 494 | }).always(function (a1, a2, a3) { 495 | that._sending -= 1; 496 | if (a3 && a3.done) { 497 | that._onAlways(a1, a2, a3, undefined, options); 498 | } else { 499 | that._onAlways(undefined, a2, a1, a3, options); 500 | } 501 | if (options.limitConcurrentUploads && 502 | options.limitConcurrentUploads > that._sending) { 503 | // Start the next queued upload, 504 | // that has not been aborted: 505 | var nextSlot = that._slots.shift(); 506 | while (nextSlot) { 507 | if (!nextSlot.isRejected()) { 508 | nextSlot.resolve(); 509 | break; 510 | } 511 | nextSlot = that._slots.shift(); 512 | } 513 | } 514 | }); 515 | return jqXHR; 516 | }; 517 | this._beforeSend(e, options); 518 | if (this.options.sequentialUploads || 519 | (this.options.limitConcurrentUploads && 520 | this.options.limitConcurrentUploads <= this._sending)) { 521 | if (this.options.limitConcurrentUploads > 1) { 522 | slot = $.Deferred(); 523 | this._slots.push(slot); 524 | pipe = slot.pipe(send); 525 | } else { 526 | pipe = (this._sequence = this._sequence.pipe(send, send)); 527 | } 528 | // Return the piped Promise object, enhanced with an abort method, 529 | // which is delegated to the jqXHR object of the current upload, 530 | // and jqXHR callbacks mapped to the equivalent Promise methods: 531 | pipe.abort = function () { 532 | var args = [undefined, 'abort', 'abort']; 533 | if (!jqXHR) { 534 | if (slot) { 535 | slot.rejectWith(args); 536 | } 537 | return send(false, args); 538 | } 539 | return jqXHR.abort(); 540 | }; 541 | return this._enhancePromise(pipe); 542 | } 543 | return send(); 544 | }, 545 | 546 | _onAdd: function (e, data) { 547 | var that = this, 548 | result = true, 549 | options = $.extend({}, this.options, data), 550 | fileSet = data.files, 551 | limit = options.limitMultiFileUploads, 552 | i; 553 | if (!(options.singleFileUploads || limit) || 554 | !this._isXHRUpload(options)) { 555 | fileSet = [fileSet]; 556 | } else if (!options.singleFileUploads && limit) { 557 | fileSet = []; 558 | for (i = 0; i < data.files.length; i += limit) { 559 | fileSet.push(data.files.slice(i, i + limit)); 560 | } 561 | } 562 | $.each(fileSet, function (index, file) { 563 | var files = $.isArray(file) ? file : [file], 564 | newData = $.extend({}, data, {files: files}); 565 | newData.submit = function () { 566 | return that._onSend(e, newData); 567 | }; 568 | return (result = that._trigger('add', e, newData)); 569 | }); 570 | return result; 571 | }, 572 | 573 | // File Normalization for Gecko 1.9.1 (Firefox 3.5) support: 574 | _normalizeFile: function (index, file) { 575 | if (file.name === undefined && file.size === undefined) { 576 | file.name = file.fileName; 577 | file.size = file.fileSize; 578 | } 579 | }, 580 | 581 | _replaceFileInput: function (input) { 582 | var inputClone = input.clone(true); 583 | $('
').append(inputClone)[0].reset(); 584 | // Detaching allows to insert the fileInput on another form 585 | // without loosing the file input value: 586 | input.after(inputClone).detach(); 587 | // Avoid memory leaks with the detached file input: 588 | $.cleanData(input.unbind('remove')); 589 | // Replace the original file input element in the fileInput 590 | // collection with the clone, which has been copied including 591 | // event handlers: 592 | this.options.fileInput = this.options.fileInput.map(function (i, el) { 593 | if (el === input[0]) { 594 | return inputClone[0]; 595 | } 596 | return el; 597 | }); 598 | // If the widget has been initialized on the file input itself, 599 | // override this.element with the file input clone: 600 | if (input[0] === this.element[0]) { 601 | this.element = inputClone; 602 | } 603 | }, 604 | 605 | _onChange: function (e) { 606 | var that = e.data.fileupload, 607 | data = { 608 | files: $.each($.makeArray(e.target.files), that._normalizeFile), 609 | fileInput: $(e.target), 610 | form: $(e.target.form) 611 | }; 612 | if (!data.files.length) { 613 | // If the files property is not available, the browser does not 614 | // support the File API and we add a pseudo File object with 615 | // the input value as name with path information removed: 616 | data.files = [{name: e.target.value.replace(/^.*\\/, '')}]; 617 | } 618 | if (that.options.replaceFileInput) { 619 | that._replaceFileInput(data.fileInput); 620 | } 621 | if (that._trigger('change', e, data) === false || 622 | that._onAdd(e, data) === false) { 623 | return false; 624 | } 625 | }, 626 | 627 | _onDrop: function (e) { 628 | var that = e.data.fileupload, 629 | dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer, 630 | data = { 631 | files: $.each( 632 | $.makeArray(dataTransfer && dataTransfer.files), 633 | that._normalizeFile 634 | ) 635 | }; 636 | if (that._trigger('drop', e, data) === false || 637 | that._onAdd(e, data) === false) { 638 | return false; 639 | } 640 | e.preventDefault(); 641 | }, 642 | 643 | _onDragOver: function (e) { 644 | var that = e.data.fileupload, 645 | dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer; 646 | if (that._trigger('dragover', e) === false) { 647 | return false; 648 | } 649 | if (dataTransfer) { 650 | dataTransfer.dropEffect = dataTransfer.effectAllowed = 'copy'; 651 | } 652 | e.preventDefault(); 653 | }, 654 | 655 | _initEventHandlers: function () { 656 | var ns = this.options.namespace || this.widgetName; 657 | this.options.dropZone 658 | .bind('dragover.' + ns, {fileupload: this}, this._onDragOver) 659 | .bind('drop.' + ns, {fileupload: this}, this._onDrop); 660 | this.options.fileInput 661 | .bind('change.' + ns, {fileupload: this}, this._onChange); 662 | }, 663 | 664 | _destroyEventHandlers: function () { 665 | var ns = this.options.namespace || this.widgetName; 666 | this.options.dropZone 667 | .unbind('dragover.' + ns, this._onDragOver) 668 | .unbind('drop.' + ns, this._onDrop); 669 | this.options.fileInput 670 | .unbind('change.' + ns, this._onChange); 671 | }, 672 | 673 | _beforeSetOption: function (key, value) { 674 | this._destroyEventHandlers(); 675 | }, 676 | 677 | _afterSetOption: function (key, value) { 678 | var options = this.options; 679 | if (!options.fileInput) { 680 | options.fileInput = $(); 681 | } 682 | if (!options.dropZone) { 683 | options.dropZone = $(); 684 | } 685 | this._initEventHandlers(); 686 | }, 687 | 688 | _setOption: function (key, value) { 689 | var refresh = $.inArray(key, this._refreshOptionsList) !== -1; 690 | if (refresh) { 691 | this._beforeSetOption(key, value); 692 | } 693 | $.Widget.prototype._setOption.call(this, key, value); 694 | if (refresh) { 695 | this._afterSetOption(key, value); 696 | } 697 | }, 698 | 699 | _create: function () { 700 | var options = this.options; 701 | if (options.fileInput === undefined) { 702 | options.fileInput = this.element.is('input:file') ? 703 | this.element : this.element.find('input:file'); 704 | } else if (!options.fileInput) { 705 | options.fileInput = $(); 706 | } 707 | if (!options.dropZone) { 708 | options.dropZone = $(); 709 | } 710 | this._slots = []; 711 | this._sequence = this._getXHRPromise(true); 712 | this._sending = this._active = this._loaded = this._total = 0; 713 | this._initEventHandlers(); 714 | }, 715 | 716 | destroy: function () { 717 | this._destroyEventHandlers(); 718 | $.Widget.prototype.destroy.call(this); 719 | }, 720 | 721 | enable: function () { 722 | $.Widget.prototype.enable.call(this); 723 | this._initEventHandlers(); 724 | }, 725 | 726 | disable: function () { 727 | this._destroyEventHandlers(); 728 | $.Widget.prototype.disable.call(this); 729 | }, 730 | 731 | // This method is exposed to the widget API and allows adding files 732 | // using the fileupload API. The data parameter accepts an object which 733 | // must have a files property and can contain additional options: 734 | // .fileupload('add', {files: filesList}); 735 | add: function (data) { 736 | if (!data || this.options.disabled) { 737 | return; 738 | } 739 | data.files = $.each($.makeArray(data.files), this._normalizeFile); 740 | this._onAdd(null, data); 741 | }, 742 | 743 | // This method is exposed to the widget API and allows sending files 744 | // using the fileupload API. The data parameter accepts an object which 745 | // must have a files property and can contain additional options: 746 | // .fileupload('send', {files: filesList}); 747 | // The method returns a Promise object for the file upload call. 748 | send: function (data) { 749 | if (data && !this.options.disabled) { 750 | data.files = $.each($.makeArray(data.files), this._normalizeFile); 751 | if (data.files.length) { 752 | return this._onSend(null, data); 753 | } 754 | } 755 | return this._getXHRPromise(false, data && data.context); 756 | } 757 | 758 | }); 759 | 760 | }(jQuery)); -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery.iframe-transport.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Iframe Transport Plugin 1.2.2 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2011, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * http://creativecommons.org/licenses/MIT/ 10 | */ 11 | 12 | /*jslint unparam: true */ 13 | /*global jQuery */ 14 | 15 | (function ($) { 16 | 'use strict'; 17 | 18 | // Helper variable to create unique names for the transport iframes: 19 | var counter = 0; 20 | 21 | // The iframe transport accepts three additional options: 22 | // options.fileInput: a jQuery collection of file input fields 23 | // options.paramName: the parameter name for the file form data, 24 | // overrides the name property of the file input field(s) 25 | // options.formData: an array of objects with name and value properties, 26 | // equivalent to the return data of .serializeArray(), e.g.: 27 | // [{name: a, value: 1}, {name: b, value: 2}] 28 | $.ajaxTransport('iframe', function (options, originalOptions, jqXHR) { 29 | if (options.type === 'POST' || options.type === 'GET') { 30 | var form, 31 | iframe; 32 | return { 33 | send: function (headers, completeCallback) { 34 | form = $('
'); 35 | // javascript:false as initial iframe src 36 | // prevents warning popups on HTTPS in IE6. 37 | // IE versions below IE8 cannot set the name property of 38 | // elements that have already been added to the DOM, 39 | // so we set the name along with the iframe HTML markup: 40 | iframe = $( 41 | '' 43 | ).bind('load', function () { 44 | var fileInputClones; 45 | iframe 46 | .unbind('load') 47 | .bind('load', function () { 48 | var response; 49 | // Wrap in a try/catch block to catch exceptions thrown 50 | // when trying to access cross-domain iframe contents: 51 | try { 52 | response = iframe.contents(); 53 | // Google Chrome and Firefox do not throw an 54 | // exception when calling iframe.contents() on 55 | // cross-domain requests, so we unify the response: 56 | if (!response.length || !response[0].firstChild) { 57 | throw new Error(); 58 | } 59 | } catch (e) { 60 | response = undefined; 61 | } 62 | // The complete callback returns the 63 | // iframe content document as response object: 64 | completeCallback( 65 | 200, 66 | 'success', 67 | {'iframe': response} 68 | ); 69 | // Fix for IE endless progress bar activity bug 70 | // (happens on form submits to iframe targets): 71 | $('') 72 | .appendTo(form); 73 | form.remove(); 74 | }); 75 | form 76 | .prop('target', iframe.prop('name')) 77 | .prop('action', options.url) 78 | .prop('method', options.type); 79 | if (options.formData) { 80 | $.each(options.formData, function (index, field) { 81 | $('') 82 | .prop('name', field.name) 83 | .val(field.value) 84 | .appendTo(form); 85 | }); 86 | } 87 | if (options.fileInput && options.fileInput.length && 88 | options.type === 'POST') { 89 | fileInputClones = options.fileInput.clone(); 90 | // Insert a clone for each file input field: 91 | options.fileInput.after(function (index) { 92 | return fileInputClones[index]; 93 | }); 94 | if (options.paramName) { 95 | options.fileInput.each(function () { 96 | $(this).prop('name', options.paramName); 97 | }); 98 | } 99 | // Appending the file input fields to the hidden form 100 | // removes them from their original location: 101 | form 102 | .append(options.fileInput) 103 | .prop('enctype', 'multipart/form-data') 104 | // enctype must be set as encoding for IE: 105 | .prop('encoding', 'multipart/form-data'); 106 | } 107 | form.submit(); 108 | // Insert the file input fields at their original location 109 | // by replacing the clones with the originals: 110 | if (fileInputClones && fileInputClones.length) { 111 | options.fileInput.each(function (index, input) { 112 | var clone = $(fileInputClones[index]); 113 | $(input).prop('name', clone.prop('name')); 114 | clone.replaceWith(input); 115 | }); 116 | } 117 | }); 118 | form.append(iframe).appendTo('body'); 119 | }, 120 | abort: function () { 121 | if (iframe) { 122 | // javascript:false as iframe src aborts the request 123 | // and prevents warning popups on HTTPS in IE6. 124 | // concat is used to avoid the "Script URL" JSLint error: 125 | iframe 126 | .unbind('load') 127 | .prop('src', 'javascript'.concat(':false;')); 128 | } 129 | if (form) { 130 | form.remove(); 131 | } 132 | } 133 | }; 134 | } 135 | }); 136 | 137 | // The iframe transport returns the iframe content document as response. 138 | // The following adds converters from iframe to text, json, html, and script: 139 | $.ajaxSetup({ 140 | converters: { 141 | 'iframe text': function (iframe) { 142 | return iframe.text(); 143 | }, 144 | 'iframe json': function (iframe) { 145 | return $.parseJSON(iframe.text()); 146 | }, 147 | 'iframe html': function (iframe) { 148 | return iframe.find('body').html(); 149 | }, 150 | 'iframe script': function (iframe) { 151 | return $.globalEval(iframe.text()); 152 | } 153 | } 154 | }); 155 | 156 | }(jQuery)); -------------------------------------------------------------------------------- /vendor/assets/javascripts/shadowbox.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Shadowbox.js, version 3.0.3 3 | * http://shadowbox-js.com/ 4 | * 5 | * Copyright 2007-2010, Michael J. I. Jackson 6 | * Date: 2011-05-14 06:45:18 +0000 7 | */ 8 | (function(au,k){var Q={version:"3.0.3"};var J=navigator.userAgent.toLowerCase();if(J.indexOf("windows")>-1||J.indexOf("win32")>-1){Q.isWindows=true}else{if(J.indexOf("macintosh")>-1||J.indexOf("mac os x")>-1){Q.isMac=true}else{if(J.indexOf("linux")>-1){Q.isLinux=true}}}Q.isIE=J.indexOf("msie")>-1;Q.isIE6=J.indexOf("msie 6")>-1;Q.isIE7=J.indexOf("msie 7")>-1;Q.isGecko=J.indexOf("gecko")>-1&&J.indexOf("safari")==-1;Q.isWebKit=J.indexOf("applewebkit/")>-1;var ab=/#(.+)$/,af=/^(light|shadow)box\[(.*?)\]/i,az=/\s*([a-z_]*?)\s*=\s*(.+)\s*/,f=/[0-9a-z]+$/i,aD=/(.+\/)shadowbox\.js/i;var A=false,a=false,l={},z=0,R,ap;Q.current=-1;Q.dimensions=null;Q.ease=function(K){return 1+Math.pow(K-1,3)};Q.errorInfo={fla:{name:"Flash",url:"http://www.adobe.com/products/flashplayer/"},qt:{name:"QuickTime",url:"http://www.apple.com/quicktime/download/"},wmp:{name:"Windows Media Player",url:"http://www.microsoft.com/windows/windowsmedia/"},f4m:{name:"Flip4Mac",url:"http://www.flip4mac.com/wmv_download.htm"}};Q.gallery=[];Q.onReady=aj;Q.path=null;Q.player=null;Q.playerId="sb-player";Q.options={animate:true,animateFade:true,autoplayMovies:true,continuous:false,enableKeys:true,flashParams:{bgcolor:"#000000",allowfullscreen:true},flashVars:{},flashVersion:"9.0.115",handleOversize:"resize",handleUnsupported:"link",onChange:aj,onClose:aj,onFinish:aj,onOpen:aj,showMovieControls:true,skipSetup:false,slideshowDelay:0,viewportPadding:20};Q.getCurrent=function(){return Q.current>-1?Q.gallery[Q.current]:null};Q.hasNext=function(){return Q.gallery.length>1&&(Q.current!=Q.gallery.length-1||Q.options.continuous)};Q.isOpen=function(){return A};Q.isPaused=function(){return ap=="pause"};Q.applyOptions=function(K){l=aC({},Q.options);aC(Q.options,K)};Q.revertOptions=function(){aC(Q.options,l)};Q.init=function(aG,aJ){if(a){return}a=true;if(Q.skin.options){aC(Q.options,Q.skin.options)}if(aG){aC(Q.options,aG)}if(!Q.path){var aI,S=document.getElementsByTagName("script");for(var aH=0,K=S.length;aHaQ){aS=aQ-aM}var aG=2*aO+K;if(aJ+aG>aR){aJ=aR-aG}var S=(aN-aS)/aN,aP=(aH-aJ)/aH,aK=(S>0||aP>0);if(aL&&aK){if(S>aP){aJ=Math.round((aH/aN)*aS)}else{if(aP>S){aS=Math.round((aN/aH)*aJ)}}}Q.dimensions={height:aS+aI,width:aJ+K,innerHeight:aS,innerWidth:aJ,top:Math.floor((aQ-(aS+aM))/2+aO),left:Math.floor((aR-(aJ+aG))/2+aO),oversized:aK};return Q.dimensions};Q.makeGallery=function(aI){var K=[],aH=-1;if(typeof aI=="string"){aI=[aI]}if(typeof aI.length=="number"){aF(aI,function(aK,aL){if(aL.content){K[aK]=aL}else{K[aK]={content:aL}}});aH=0}else{if(aI.tagName){var S=Q.getCache(aI);aI=S?S:Q.makeObject(aI)}if(aI.gallery){K=[];var aJ;for(var aG in Q.cache){aJ=Q.cache[aG];if(aJ.gallery&&aJ.gallery==aI.gallery){if(aH==-1&&aJ.content==aI.content){aH=K.length}K.push(aJ)}}if(aH==-1){K.unshift(aI);aH=0}}else{K=[aI];aH=0}}aF(K,function(aK,aL){K[aK]=aC({},aL)});return[K,aH]};Q.makeObject=function(aH,aG){var aI={content:aH.href,title:aH.getAttribute("title")||"",link:aH};if(aG){aG=aC({},aG);aF(["player","title","height","width","gallery"],function(aJ,aK){if(typeof aG[aK]!="undefined"){aI[aK]=aG[aK];delete aG[aK]}});aI.options=aG}else{aI.options={}}if(!aI.player){aI.player=Q.getPlayer(aI.content)}var K=aH.getAttribute("rel");if(K){var S=K.match(af);if(S){aI.gallery=escape(S[2])}aF(K.split(";"),function(aJ,aK){S=aK.match(az);if(S){aI[S[1]]=S[2]}})}return aI};Q.getPlayer=function(aG){if(aG.indexOf("#")>-1&&aG.indexOf(document.location.href)==0){return"inline"}var aH=aG.indexOf("?");if(aH>-1){aG=aG.substring(0,aH)}var S,K=aG.match(f);if(K){S=K[0].toLowerCase()}if(S){if(Q.img&&Q.img.ext.indexOf(S)>-1){return"img"}if(Q.swf&&Q.swf.ext.indexOf(S)>-1){return"swf"}if(Q.flv&&Q.flv.ext.indexOf(S)>-1){return"flv"}if(Q.qt&&Q.qt.ext.indexOf(S)>-1){if(Q.wmp&&Q.wmp.ext.indexOf(S)>-1){return"qtwmp"}else{return"qt"}}if(Q.wmp&&Q.wmp.ext.indexOf(S)>-1){return"wmp"}}return"iframe"};function G(){var aH=Q.errorInfo,aI=Q.plugins,aK,aL,aO,aG,aN,S,aM,K;for(var aJ=0;aJ'+s(Q.lang.errors[aN],S)+""}else{aL=true}}else{if(aK.player=="inline"){aG=ab.exec(aK.content);if(aG){aM=ad(aG[1]);if(aM){aK.content=aM.innerHTML}else{aL=true}}else{aL=true}}else{if(aK.player=="swf"||aK.player=="flv"){K=(aK.options&&aK.options.flashVersion)||Q.options.flashVersion;if(Q.flash&&!Q.flash.hasFlashPlayerVersion(K)){aK.width=310;aK.height=177}}}}if(aL){Q.gallery.splice(aJ,1);if(aJ0?aJ-1:aJ}}--aJ}}}function aq(K){if(!Q.options.enableKeys){return}(K?F:M)(document,"keydown",an)}function an(aG){if(aG.metaKey||aG.shiftKey||aG.altKey||aG.ctrlKey){return}var S=v(aG),K;switch(S){case 81:case 88:case 27:K=Q.close;break;case 37:K=Q.previous;break;case 39:K=Q.next;break;case 32:K=typeof ap=="number"?Q.pause:Q.play;break}if(K){n(aG);K()}}function c(aK){aq(false);var aJ=Q.getCurrent();var aG=(aJ.player=="inline"?"html":aJ.player);if(typeof Q[aG]!="function"){throw"unknown player "+aG}if(aK){Q.player.remove();Q.revertOptions();Q.applyOptions(aJ.options||{})}Q.player=new Q[aG](aJ,Q.playerId);if(Q.gallery.length>1){var aH=Q.gallery[Q.current+1]||Q.gallery[0];if(aH.player=="img"){var S=new Image();S.src=aH.content}var aI=Q.gallery[Q.current-1]||Q.gallery[Q.gallery.length-1];if(aI.player=="img"){var K=new Image();K.src=aI.content}}Q.skin.onLoad(aK,W)}function W(){if(!A){return}if(typeof Q.player.ready!="undefined"){var K=setInterval(function(){if(A){if(Q.player.ready){clearInterval(K);K=null;Q.skin.onReady(e)}}else{clearInterval(K);K=null}},10)}else{Q.skin.onReady(e)}}function e(){if(!A){return}Q.player.append(Q.skin.body,Q.dimensions);Q.skin.onShow(I)}function I(){if(!A){return}if(Q.player.onLoad){Q.player.onLoad()}Q.options.onFinish(Q.getCurrent());if(!Q.isPaused()){Q.play()}aq(true)}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(S,aG){var K=this.length>>>0;aG=aG||0;if(aG<0){aG+=K}for(;aG-1;Q.plugins={fla:w.indexOf("Shockwave Flash")>-1,qt:w.indexOf("QuickTime")>-1,wmp:!ai&&w.indexOf("Windows Media")>-1,f4m:ai}}else{var p=function(K){var S;try{S=new ActiveXObject(K)}catch(aG){}return !!S};Q.plugins={fla:p("ShockwaveFlash.ShockwaveFlash"),qt:p("QuickTime.QuickTime"),wmp:p("wmplayer.ocx"),f4m:false}}var X=/^(light|shadow)box/i,am="shadowboxCacheKey",b=1;Q.cache={};Q.select=function(S){var aG=[];if(!S){var K;aF(document.getElementsByTagName("a"),function(aJ,aK){K=aK.getAttribute("rel");if(K&&X.test(K)){aG.push(aK)}})}else{var aI=S.length;if(aI){if(typeof S=="string"){if(Q.find){aG=Q.find(S)}}else{if(aI==2&&typeof S[0]=="string"&&S[1].nodeType){if(Q.find){aG=Q.find(S[0],S[1])}}else{for(var aH=0;aH+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,aQ=0,aS=Object.prototype.toString,aK=false,aJ=true;[0,0].sort(function(){aJ=false;return 0});var aG=function(a1,aW,a4,a5){a4=a4||[];var a7=aW=aW||document;if(aW.nodeType!==1&&aW.nodeType!==9){return[]}if(!a1||typeof a1!=="string"){return a4}var a2=[],aY,a9,bc,aX,a0=true,aZ=aH(aW),a6=a1;while((aP.exec(""),aY=aP.exec(a6))!==null){a6=aY[3];a2.push(aY[1]);if(aY[2]){aX=aY[3];break}}if(a2.length>1&&aL.exec(a1)){if(a2.length===2&&aM.relative[a2[0]]){a9=aT(a2[0]+a2[1],aW)}else{a9=aM.relative[a2[0]]?[aW]:aG(a2.shift(),aW);while(a2.length){a1=a2.shift();if(aM.relative[a1]){a1+=a2.shift()}a9=aT(a1,a9)}}}else{if(!a5&&a2.length>1&&aW.nodeType===9&&!aZ&&aM.match.ID.test(a2[0])&&!aM.match.ID.test(a2[a2.length-1])){var a8=aG.find(a2.shift(),aW,aZ);aW=a8.expr?aG.filter(a8.expr,a8.set)[0]:a8.set[0]}if(aW){var a8=a5?{expr:a2.pop(),set:aO(a5)}:aG.find(a2.pop(),a2.length===1&&(a2[0]==="~"||a2[0]==="+")&&aW.parentNode?aW.parentNode:aW,aZ);a9=a8.expr?aG.filter(a8.expr,a8.set):a8.set;if(a2.length>0){bc=aO(a9)}else{a0=false}while(a2.length){var bb=a2.pop(),ba=bb;if(!aM.relative[bb]){bb=""}else{ba=a2.pop()}if(ba==null){ba=aW}aM.relative[bb](bc,ba,aZ)}}else{bc=a2=[]}}if(!bc){bc=a9}if(!bc){throw"Syntax error, unrecognized expression: "+(bb||a1)}if(aS.call(bc)==="[object Array]"){if(!a0){a4.push.apply(a4,bc)}else{if(aW&&aW.nodeType===1){for(var a3=0;bc[a3]!=null;a3++){if(bc[a3]&&(bc[a3]===true||bc[a3].nodeType===1&&aN(aW,bc[a3]))){a4.push(a9[a3])}}}else{for(var a3=0;bc[a3]!=null;a3++){if(bc[a3]&&bc[a3].nodeType===1){a4.push(a9[a3])}}}}}else{aO(bc,a4)}if(aX){aG(aX,a7,a4,a5);aG.uniqueSort(a4)}return a4};aG.uniqueSort=function(aX){if(aR){aK=aJ;aX.sort(aR);if(aK){for(var aW=1;aW":function(a2,aX){var a0=typeof aX==="string";if(a0&&!/\W/.test(aX)){aX=aX.toLowerCase();for(var aY=0,aW=a2.length;aY=0)){if(!aY){aW.push(a1)}}else{if(aY){aX[a0]=false}}}}return false},ID:function(aW){return aW[1].replace(/\\/g,"")},TAG:function(aX,aW){return aX[1].toLowerCase()},CHILD:function(aW){if(aW[1]==="nth"){var aX=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(aW[2]==="even"&&"2n"||aW[2]==="odd"&&"2n+1"||!/\D/.test(aW[2])&&"0n+"+aW[2]||aW[2]);aW[2]=(aX[1]+(aX[2]||1))-0;aW[3]=aX[3]-0}aW[0]=aQ++;return aW},ATTR:function(a0,aX,aY,aW,a1,a2){var aZ=a0[1].replace(/\\/g,"");if(!a2&&aM.attrMap[aZ]){a0[1]=aM.attrMap[aZ]}if(a0[2]==="~="){a0[4]=" "+a0[4]+" "}return a0},PSEUDO:function(a0,aX,aY,aW,a1){if(a0[1]==="not"){if((aP.exec(a0[3])||"").length>1||/^\w/.test(a0[3])){a0[3]=aG(a0[3],null,null,aX)}else{var aZ=aG.filter(a0[3],aX,aY,true^a1);if(!aY){aW.push.apply(aW,aZ)}return false}}else{if(aM.match.POS.test(a0[0])||aM.match.CHILD.test(a0[0])){return true}}return a0},POS:function(aW){aW.unshift(true);return aW}},filters:{enabled:function(aW){return aW.disabled===false&&aW.type!=="hidden"},disabled:function(aW){return aW.disabled===true},checked:function(aW){return aW.checked===true},selected:function(aW){aW.parentNode.selectedIndex;return aW.selected===true},parent:function(aW){return !!aW.firstChild},empty:function(aW){return !aW.firstChild},has:function(aY,aX,aW){return !!aG(aW[3],aY).length},header:function(aW){return/h\d/i.test(aW.nodeName)},text:function(aW){return"text"===aW.type},radio:function(aW){return"radio"===aW.type},checkbox:function(aW){return"checkbox"===aW.type},file:function(aW){return"file"===aW.type},password:function(aW){return"password"===aW.type},submit:function(aW){return"submit"===aW.type},image:function(aW){return"image"===aW.type},reset:function(aW){return"reset"===aW.type},button:function(aW){return"button"===aW.type||aW.nodeName.toLowerCase()==="button"},input:function(aW){return/input|select|textarea|button/i.test(aW.nodeName)}},setFilters:{first:function(aX,aW){return aW===0},last:function(aY,aX,aW,aZ){return aX===aZ.length-1},even:function(aX,aW){return aW%2===0},odd:function(aX,aW){return aW%2===1},lt:function(aY,aX,aW){return aXaW[3]-0},nth:function(aY,aX,aW){return aW[3]-0===aX},eq:function(aY,aX,aW){return aW[3]-0===aX}},filter:{PSEUDO:function(a2,aY,aZ,a3){var aX=aY[1],a0=aM.filters[aX];if(a0){return a0(a2,aZ,aY,a3)}else{if(aX==="contains"){return(a2.textContent||a2.innerText||S([a2])||"").indexOf(aY[3])>=0}else{if(aX==="not"){var a1=aY[3];for(var aZ=0,aW=a1.length;aZ=0)}}},ID:function(aX,aW){return aX.nodeType===1&&aX.getAttribute("id")===aW},TAG:function(aX,aW){return(aW==="*"&&aX.nodeType===1)||aX.nodeName.toLowerCase()===aW},CLASS:function(aX,aW){return(" "+(aX.className||aX.getAttribute("class"))+" ").indexOf(aW)>-1},ATTR:function(a1,aZ){var aY=aZ[1],aW=aM.attrHandle[aY]?aM.attrHandle[aY](a1):a1[aY]!=null?a1[aY]:a1.getAttribute(aY),a2=aW+"",a0=aZ[2],aX=aZ[4];return aW==null?a0==="!=":a0==="="?a2===aX:a0==="*="?a2.indexOf(aX)>=0:a0==="~="?(" "+a2+" ").indexOf(aX)>=0:!aX?a2&&aW!==false:a0==="!="?a2!==aX:a0==="^="?a2.indexOf(aX)===0:a0==="$="?a2.substr(a2.length-aX.length)===aX:a0==="|="?a2===aX||a2.substr(0,aX.length+1)===aX+"-":false},POS:function(a0,aX,aY,a1){var aW=aX[2],aZ=aM.setFilters[aW];if(aZ){return aZ(a0,aY,aX,a1)}}}};var aL=aM.match.POS;for(var aI in aM.match){aM.match[aI]=new RegExp(aM.match[aI].source+/(?![^\[]*\])(?![^\(]*\))/.source);aM.leftMatch[aI]=new RegExp(/(^(?:.|\r|\n)*?)/.source+aM.match[aI].source)}var aO=function(aX,aW){aX=Array.prototype.slice.call(aX,0);if(aW){aW.push.apply(aW,aX);return aW}return aX};try{Array.prototype.slice.call(document.documentElement.childNodes,0)}catch(aV){aO=function(a0,aZ){var aX=aZ||[];if(aS.call(a0)==="[object Array]"){Array.prototype.push.apply(aX,a0)}else{if(typeof a0.length==="number"){for(var aY=0,aW=a0.length;aY";var aW=document.documentElement;aW.insertBefore(aX,aW.firstChild);if(document.getElementById(aY)){aM.find.ID=function(a0,a1,a2){if(typeof a1.getElementById!=="undefined"&&!a2){var aZ=a1.getElementById(a0[1]);return aZ?aZ.id===a0[1]||typeof aZ.getAttributeNode!=="undefined"&&aZ.getAttributeNode("id").nodeValue===a0[1]?[aZ]:k:[]}};aM.filter.ID=function(a1,aZ){var a0=typeof a1.getAttributeNode!=="undefined"&&a1.getAttributeNode("id");return a1.nodeType===1&&a0&&a0.nodeValue===aZ}}aW.removeChild(aX);aW=aX=null})();(function(){var aW=document.createElement("div");aW.appendChild(document.createComment(""));if(aW.getElementsByTagName("*").length>0){aM.find.TAG=function(aX,a1){var a0=a1.getElementsByTagName(aX[1]);if(aX[1]==="*"){var aZ=[];for(var aY=0;a0[aY];aY++){if(a0[aY].nodeType===1){aZ.push(a0[aY])}}a0=aZ}return a0}}aW.innerHTML="";if(aW.firstChild&&typeof aW.firstChild.getAttribute!=="undefined"&&aW.firstChild.getAttribute("href")!=="#"){aM.attrHandle.href=function(aX){return aX.getAttribute("href",2)}}aW=null})();if(document.querySelectorAll){(function(){var aW=aG,aY=document.createElement("div");aY.innerHTML="

";if(aY.querySelectorAll&&aY.querySelectorAll(".TEST").length===0){return}aG=function(a2,a1,aZ,a0){a1=a1||document;if(!a0&&a1.nodeType===9&&!aH(a1)){try{return aO(a1.querySelectorAll(a2),aZ)}catch(a3){}}return aW(a2,a1,aZ,a0)};for(var aX in aW){aG[aX]=aW[aX]}aY=null})()}(function(){var aW=document.createElement("div");aW.innerHTML="
";if(!aW.getElementsByClassName||aW.getElementsByClassName("e").length===0){return}aW.lastChild.className="e";if(aW.getElementsByClassName("e").length===1){return}aM.order.splice(1,0,"CLASS");aM.find.CLASS=function(aX,aY,aZ){if(typeof aY.getElementsByClassName!=="undefined"&&!aZ){return aY.getElementsByClassName(aX[1])}};aW=null})();function K(aX,a2,a1,a5,a3,a4){for(var aZ=0,aY=a5.length;aZ0){a0=aW;break}}}aW=aW[aX]}a5[aZ]=a0}}}var aN=document.compareDocumentPosition?function(aX,aW){return aX.compareDocumentPosition(aW)&16}:function(aX,aW){return aX!==aW&&(aX.contains?aX.contains(aW):true)};var aH=function(aW){var aX=(aW?aW.ownerDocument||aW:0).documentElement;return aX?aX.nodeName!=="HTML":false};var aT=function(aW,a3){var aZ=[],a0="",a1,aY=a3.nodeType?[a3]:a3;while((a1=aM.match.PSEUDO.exec(aW))){a0+=a1[0];aW=aW.replace(aM.match.PSEUDO,"")}aW=aM.relative[aW]?aW+"*":aW;for(var a2=0,aX=aY.length;a2{1} browser plugin to view this content.',shared:'You must install both the {1} and {3} browser plugins to view this content.',either:'You must install either the {1} or the {3} browser plugin to view this content.'}};var D,at="sb-drag-proxy",E,j,ag;function ax(){E={x:0,y:0,startX:null,startY:null}}function aA(){var K=Q.dimensions;aC(j.style,{height:K.innerHeight+"px",width:K.innerWidth+"px"})}function O(){ax();var K=["position:absolute","cursor:"+(Q.isGecko?"-moz-grab":"move"),"background-color:"+(Q.isIE?"#fff;filter:alpha(opacity=0)":"transparent")].join(";");Q.appendHTML(Q.skin.body,'
');j=ad(at);aA();F(j,"mousedown",L)}function B(){if(j){M(j,"mousedown",L);C(j);j=null}ag=null}function L(S){n(S);var K=V(S);E.startX=K[0];E.startY=K[1];ag=ad(Q.player.id);F(document,"mousemove",H);F(document,"mouseup",i);if(Q.isGecko){j.style.cursor="-moz-grabbing"}}function H(aI){var K=Q.player,aJ=Q.dimensions,aH=V(aI);var aG=aH[0]-E.startX;E.startX+=aG;E.x=Math.max(Math.min(0,E.x+aG),aJ.innerWidth-K.width);var S=aH[1]-E.startY;E.startY+=S;E.y=Math.max(Math.min(0,E.y+S),aJ.innerHeight-K.height);aC(ag.style,{left:E.x+"px",top:E.y+"px"})}function i(){M(document,"mousemove",H);M(document,"mouseup",i);if(Q.isGecko){j.style.cursor="-moz-grab"}}Q.img=function(S,aG){this.obj=S;this.id=aG;this.ready=false;var K=this;D=new Image();D.onload=function(){K.height=S.height?parseInt(S.height,10):D.height;K.width=S.width?parseInt(S.width,10):D.width;K.ready=true;D.onload=null;D=null};D.src=S.content};Q.img.ext=["bmp","gif","jpg","jpeg","png"];Q.img.prototype={append:function(S,aI){var aG=document.createElement("img");aG.id=this.id;aG.src=this.obj.content;aG.style.position="absolute";var K,aH;if(aI.oversized&&Q.options.handleOversize=="resize"){K=aI.innerHeight;aH=aI.innerWidth}else{K=this.height;aH=this.width}aG.setAttribute("height",K);aG.setAttribute("width",aH);S.appendChild(aG)},remove:function(){var K=ad(this.id);if(K){C(K)}B();if(D){D.onload=null;D=null}},onLoad:function(){var K=Q.dimensions;if(K.oversized&&Q.options.handleOversize=="drag"){O()}},onWindowResize:function(){var aH=Q.dimensions;switch(Q.options.handleOversize){case"resize":var K=ad(this.id);K.height=aH.innerHeight;K.width=aH.innerWidth;break;case"drag":if(ag){var aG=parseInt(Q.getStyle(ag,"top")),S=parseInt(Q.getStyle(ag,"left"));if(aG+this.height=aJ){clearInterval(S);S=null;aM(aG,aN);if(aR){aR()}}else{aM(aG,aO+aK((aI-aH)/aL)*aP)}},10)}function aB(){aa.style.height=Q.getWindowSize("Height")+"px";aa.style.width=Q.getWindowSize("Width")+"px"}function aE(){aa.style.top=document.documentElement.scrollTop+"px";aa.style.left=document.documentElement.scrollLeft+"px"}function ay(K){if(K){aF(Y,function(S,aG){aG[0].style.visibility=aG[1]||""})}else{Y=[];aF(Q.options.troubleElements,function(aG,S){aF(document.getElementsByTagName(S),function(aH,aI){Y.push([aI,aI.style.visibility]);aI.style.visibility="hidden"})})}}function r(aG,K){var S=ad("sb-nav-"+aG);if(S){S.style.display=K?"":"none"}}function ah(K,aJ){var aI=ad("sb-loading"),aG=Q.getCurrent().player,aH=(aG=="img"||aG=="html");if(K){Q.setOpacity(aI,0);aI.style.display="block";var S=function(){Q.clearOpacity(aI);if(aJ){aJ()}};if(aH){N(aI,"opacity",1,Q.options.fadeDuration,S)}else{S()}}else{var S=function(){aI.style.display="none";Q.clearOpacity(aI);if(aJ){aJ()}};if(aH){N(aI,"opacity",0,Q.options.fadeDuration,S)}else{S()}}}function t(aO){var aJ=Q.getCurrent();ad("sb-title-inner").innerHTML=aJ.title||"";var aP,aL,S,aQ,aM;if(Q.options.displayNav){aP=true;var aN=Q.gallery.length;if(aN>1){if(Q.options.continuous){aL=aM=true}else{aL=(aN-1)>Q.current;aM=Q.current>0}}if(Q.options.slideshowDelay>0&&Q.hasNext()){aQ=!Q.isPaused();S=!aQ}}else{aP=aL=S=aQ=aM=false}r("close",aP);r("next",aL);r("play",S);r("pause",aQ);r("previous",aM);var K="";if(Q.options.displayCounter&&Q.gallery.length>1){var aN=Q.gallery.length;if(Q.options.counterType=="skip"){var aI=0,aH=aN,aG=parseInt(Q.options.counterLimit)||0;if(aG2){var aK=Math.floor(aG/2);aI=Q.current-aK;if(aI<0){aI+=aN}aH=Q.current+(aG-aK);if(aH>aN){aH-=aN}}while(aI!=aH){if(aI==aN){aI=0}K+='"}}else{K=[Q.current+1,Q.lang.of,aN].join(" ")}}ad("sb-counter").innerHTML=K;aO()}function U(aH){var K=ad("sb-title-inner"),aG=ad("sb-info-inner"),S=0.35;K.style.visibility=aG.style.visibility="";if(K.innerHTML!=""){N(K,"marginTop",0,S)}N(aG,"marginTop",0,S,aH)}function av(aG,aM){var aK=ad("sb-title"),K=ad("sb-info"),aH=aK.offsetHeight,aI=K.offsetHeight,aJ=ad("sb-title-inner"),aL=ad("sb-info-inner"),S=(aG?0.35:0);N(aJ,"marginTop",aH,S);N(aL,"marginTop",aI*-1,S,function(){aJ.style.visibility=aL.style.visibility="hidden";aM()})}function ac(K,aH,S,aJ){var aI=ad("sb-wrapper-inner"),aG=(S?Q.options.resizeDuration:0);N(Z,"top",aH,aG);N(aI,"height",K,aG,aJ)}function ar(K,aH,S,aI){var aG=(S?Q.options.resizeDuration:0);N(Z,"left",aH,aG);N(Z,"width",K,aG,aI)}function ak(aM,aG){var aI=ad("sb-body-inner"),aM=parseInt(aM),aG=parseInt(aG),S=Z.offsetHeight-aI.offsetHeight,K=Z.offsetWidth-aI.offsetWidth,aK=ae.offsetHeight,aL=ae.offsetWidth,aJ=parseInt(Q.options.viewportPadding)||20,aH=(Q.player&&Q.options.handleOversize!="drag");return Q.setDimensions(aM,aG,aK,aL,S,K,aJ,aH)}var T={};T.markup='';T.options={animSequence:"sync",counterLimit:10,counterType:"default",displayCounter:true,displayNav:true,fadeDuration:0.35,initialHeight:160,initialWidth:320,modal:false,overlayColor:"#000",overlayOpacity:0.5,resizeDuration:0.35,showOverlay:true,troubleElements:["select","object","embed","canvas"]};T.init=function(){Q.appendHTML(document.body,s(T.markup,Q.lang));T.body=ad("sb-body-inner");aa=ad("sb-container");ae=ad("sb-overlay");Z=ad("sb-wrapper");if(!x){aa.style.position="absolute"}if(!h){var aG,K,S=/url\("(.*\.png)"\)/;aF(q,function(aI,aJ){aG=ad(aJ);if(aG){K=Q.getStyle(aG,"backgroundImage").match(S);if(K){aG.style.backgroundImage="none";aG.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,src="+K[1]+",sizingMethod=scale);"}}})}var aH;F(au,"resize",function(){if(aH){clearTimeout(aH);aH=null}if(A){aH=setTimeout(T.onWindowResize,10)}})};T.onOpen=function(K,aG){m=false;aa.style.display="block";aB();var S=ak(Q.options.initialHeight,Q.options.initialWidth);ac(S.innerHeight,S.top);ar(S.width,S.left);if(Q.options.showOverlay){ae.style.backgroundColor=Q.options.overlayColor;Q.setOpacity(ae,0);if(!Q.options.modal){F(ae,"click",Q.close)}ao=true}if(!x){aE();F(au,"scroll",aE)}ay();aa.style.visibility="visible";if(ao){N(ae,"opacity",Q.options.overlayOpacity,Q.options.fadeDuration,aG)}else{aG()}};T.onLoad=function(S,K){ah(true);while(T.body.firstChild){C(T.body.firstChild)}av(S,function(){if(!A){return}if(!S){Z.style.visibility="visible"}t(K)})};T.onReady=function(aH){if(!A){return}var S=Q.player,aG=ak(S.height,S.width);var K=function(){U(aH)};switch(Q.options.animSequence){case"hw":ac(aG.innerHeight,aG.top,true,function(){ar(aG.width,aG.left,true,K)});break;case"wh":ar(aG.width,aG.left,true,function(){ac(aG.innerHeight,aG.top,true,K)});break;default:ar(aG.width,aG.left,true);ac(aG.innerHeight,aG.top,true,K)}};T.onShow=function(K){ah(false,K);m=true};T.onClose=function(){if(!x){M(au,"scroll",aE)}M(ae,"click",Q.close);Z.style.visibility="hidden";var K=function(){aa.style.visibility="hidden";aa.style.display="none";ay(true)};if(ao){N(ae,"opacity",0,Q.options.fadeDuration,K)}else{K()}};T.onPlay=function(){r("play",false);r("pause",true)};T.onPause=function(){r("pause",false);r("play",true)};T.onWindowResize=function(){if(!m){return}aB();var K=Q.player,S=ak(K.height,K.width);ar(S.width,S.left);ac(S.innerHeight,S.top);if(K.onWindowResize){K.onWindowResize()}};Q.skin=T;au.Shadowbox=Q})(window); -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/vendor/assets/stylesheets/.gitkeep -------------------------------------------------------------------------------- /vendor/assets/stylesheets/best_in_place.css: -------------------------------------------------------------------------------- 1 | .best_in_place { 2 | padding-right: 1.5em; 3 | padding: .1m; 4 | cursor: hand; 5 | cursor: pointer; 6 | -moz-transition: background 0.5s linear; 7 | -o-transition: background 0.5s linear; 8 | -webkit-transition: background 0.5s linear; 9 | -moz-border-radius: 5px; 10 | -webkit-border-radius: 5px; 11 | -o-border-radius: 5px; 12 | -ms-border-radius: 5px; 13 | -khtml-border-radius: 5px; 14 | border-radius: 5px; 15 | } 16 | .best_in_place:hover, #user_account .do_hover { 17 | background: url(../assets/red_pen.png) no-repeat right; 18 | background-color: #CCC; 19 | } -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jquery.fileupload-ui.css: -------------------------------------------------------------------------------- 1 | @charset 'UTF-8';/* 2 | * jQuery File Upload UI Plugin CSS 5.0.6 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2010,Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license:* http://creativecommons.org/licenses/MIT/ 9 | */ 10 | .fileupload-buttonbar .ui-button input{position:absolute;top:0;right:0;margin:0;border:solid transparent;border-width:0 0 100px 200px;opacity:0;filter:alpha(opacity=0);-o-transform:translate(250px,-50px) scale(1);-moz-transform:translate(-300px,0) scale(4);direction:ltr;cursor:pointer;} 11 | .fileinput-button{overflow:hidden;} 12 | /* Fix for IE 6:*/ 13 | *html .fileinput-button{padding:2px 0;} 14 | /* Fix for IE 7:*/ 15 | *+html .fileinput-button{padding:2px 0;} 16 | .fileupload-buttonbar{padding:0.2em 0.4em;} 17 | .fileupload-buttonbar .ui-button{vertical-align:middle;} 18 | .fileupload-content{padding:0.2em 0.4em;border-top-width:0;} 19 | .fileupload-content .ui-progressbar{width:200px;height:20px;} 20 | .fileupload-content .ui-progressbar-value{background:url(../assets/pbar-ani.gif);} 21 | .fileupload-content .fileupload-progressbar{width:400px;margin:10px 0;} 22 | .files{margin:10px 0;border-collapse:collapse;} 23 | .files td{padding:5px;border-spacing:5px;} 24 | .files img{border:none;} 25 | .files .name{padding:0 10px;} 26 | .files .size{padding:0 10px 0 0;text-align:right;white-space:nowrap;} 27 | .ui-state-disabled .ui-state-disabled{opacity:1;filter:alpha(opacity=100);} 28 | .ui-state-disabled input{cursor:default;} 29 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/nifty-layout.css: -------------------------------------------------------------------------------- 1 | body{background-color:#4B7399;font-family:Verdana,Helvetica,Arial;font-size:14px;} 2 | a img{border:none;} 3 | a{color:#0000FF;} 4 | .clear{clear:both;height:0;overflow:hidden;} 5 | #container{width:75%;margin:0 auto;background-color:#FFF;padding:20px 40px;border:solid 1px black;margin-top:20px;} 6 | #flash_notice,#flash_error,#flash_alert{padding:5px 8px;margin:10px 0;} 7 | #flash_notice{background-color:#CFC;border:solid 1px #6C6;} 8 | #flash_error,#flash_alert{background-color:#FCC;border:solid 1px #C66;} 9 | .fieldWithErrors{display:inline;} 10 | .error_messages{width:400px;border:2px solid #CF0000;padding:0px;padding-bottom:12px;margin-bottom:20px;background-color:#f0f0f0;font-size:12px;} 11 | .error_messages h2{text-align:left;font-weight:bold;padding:5px 10px;font-size:12px;margin:0;background-color:#c00;color:#fff;} 12 | .error_messages p{margin:8px 10px;} 13 | .error_messages ul{margin:0;} 14 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/shadowbox.css: -------------------------------------------------------------------------------- 1 | #sb-title-inner,#sb-info-inner,#sb-loading-inner,div.sb-message{font-family:"HelveticaNeue-Light","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:200;color:#fff;} 2 | #sb-container{position:fixed;margin:0;padding:0;top:0;left:0;z-index:999;text-align:left;visibility:hidden;display:none;} 3 | #sb-overlay{position:relative;height:100%;width:100%;} 4 | #sb-wrapper{position:absolute;visibility:hidden;width:100px;} 5 | #sb-wrapper-inner{position:relative;border:1px solid #303030;overflow:hidden;height:100px;} 6 | #sb-body{position:relative;height:100%;} 7 | #sb-body-inner{position:absolute;height:100%;width:100%;} 8 | #sb-player.html{height:100%;overflow:auto;} 9 | #sb-body img{border:none;} 10 | #sb-loading{position:relative;height:100%;} 11 | #sb-loading-inner{position:absolute;font-size:14px;line-height:24px;height:24px;top:50%;margin-top:-12px;width:100%;text-align:center;} 12 | #sb-loading-inner span{background:url(../assets/loading.gif) no-repeat;padding-left:34px;display:inline-block;} 13 | #sb-body,#sb-loading{background-color:#060606;} 14 | #sb-title,#sb-info{position:relative;margin:0;padding:0;overflow:hidden;} 15 | #sb-title,#sb-title-inner{height:26px;line-height:26px;} 16 | #sb-title-inner{font-size:16px;} 17 | #sb-info,#sb-info-inner{height:20px;line-height:20px;} 18 | #sb-info-inner{font-size:12px;} 19 | #sb-nav{float:right;height:16px;padding:2px 0;width:45%;} 20 | #sb-nav a{display:block;float:right;height:16px;width:16px;margin-left:3px;cursor:pointer;background-repeat:no-repeat;} 21 | #sb-nav-close{background-image:url(../assets/close.png);} 22 | #sb-nav-next{background-image:url(../assets/next.png);} 23 | #sb-nav-previous{background-image:url(../assets/previous.png);} 24 | #sb-nav-play{background-image:url(../assets/play.png);} 25 | #sb-nav-pause{background-image:url(../assets/pause.png);} 26 | #sb-counter{float:left;width:45%;} 27 | #sb-counter a{padding:0 4px 0 0;text-decoration:none;cursor:pointer;color:#fff;} 28 | #sb-counter a.sb-counter-current{text-decoration:underline;} 29 | div.sb-message{font-size:12px;padding:10px;text-align:center;} 30 | div.sb-message a:link,div.sb-message a:visited{color:#fff;text-decoration:underline;} 31 | -------------------------------------------------------------------------------- /vendor/plugins/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yortz/carrierwave_jquery_file_upload/85abe7a45c51f5dab2a2d476e8d997e778d3ff3c/vendor/plugins/.gitkeep --------------------------------------------------------------------------------