update archive
This commit is contained in:
		
							parent
							
								
									3ebe7378b9
								
							
						
					
					
						commit
						a1560ebcf5
					
				|  | @ -0,0 +1,9 @@ | ||||||
|  | $('.archive_file_multiples_block a.delete').live('click', function(){ | ||||||
|  |   $(this).parents('.list_item').remove(); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | $(document).on('click', '.action a.remove_existing_record', function(){ | ||||||
|  |   $(this).next('.should_destroy').attr('value', 1); | ||||||
|  |   $("tr#archive_file_multiple_" + $(this).prev().attr('value')).hide(); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | @ -28,7 +28,10 @@ class Admin::PagePartsController < ApplicationController | ||||||
|     @tag_objects = @r_tag.classify.constantize.all rescue nil |     @tag_objects = @r_tag.classify.constantize.all rescue nil | ||||||
| 	 | 	 | ||||||
| 	@widget_path = @part.widget_path ? @part.widget_path : @module_app.widgets.keys[0] | 	@widget_path = @part.widget_path ? @part.widget_path : @module_app.widgets.keys[0] | ||||||
|     @widget_style =  @module_app.widgets[@widget_path] | 	 | ||||||
|  | 	if @module_app.widgets.any?{|b| b.class == Array} | ||||||
|  |       @widget_style =  @module_app.widgets[@widget_path] if !@widget_path.blank? && !@module_app.widgets.blank? | ||||||
|  | 	end | ||||||
| 	 | 	 | ||||||
|       case @module_app.key |       case @module_app.key | ||||||
|         when 'announcement' |         when 'announcement' | ||||||
|  | @ -50,7 +53,7 @@ class Admin::PagePartsController < ApplicationController | ||||||
|   def update |   def update | ||||||
|     @part = PagePart.find(params[:id]) |     @part = PagePart.find(params[:id]) | ||||||
| 	 | 	 | ||||||
| 	params[:page_part][:widget_field] = params[:page_part][:widget_field].zip( params[:page_part][:widget_field_type] )	   | 	params[:page_part][:widget_field] = params[:page_part][:widget_field].zip( params[:page_part][:widget_field_type] ) if params[:page_part][:widget_field]	   | ||||||
| 	params[:page_part][:widget_field_type] = nil | 	params[:page_part][:widget_field_type] = nil | ||||||
| 	   | 	   | ||||||
|     if @part.update_attributes(params[:page_part]) |     if @part.update_attributes(params[:page_part]) | ||||||
|  |  | ||||||
|  | @ -39,8 +39,11 @@ class Admin::PagesController < ApplicationController | ||||||
|       @module_app = @item.module_app |       @module_app = @item.module_app | ||||||
| 	 | 	 | ||||||
| 	  @frontend_path = @item.app_frontend_url ? @item.app_frontend_url : @module_app.widgets.keys[0] | 	  @frontend_path = @item.app_frontend_url ? @item.app_frontend_url : @module_app.widgets.keys[0] | ||||||
|       @frontend_style =  @module_app.widgets[@frontend_path] if !@frontend_path.blank? && !@module_app.widgets.blank? | 	   | ||||||
| 	 | 	  if @module_app.widgets.any?{|b| b.class == Array} | ||||||
|  |         @frontend_style =  @module_app.widgets[@frontend_path] if !@frontend_path.blank? && !@module_app.widgets.blank? | ||||||
|  | 	  end | ||||||
|  | 	   | ||||||
|       case @item.module_app.key |       case @item.module_app.key | ||||||
|         when 'announcement' |         when 'announcement' | ||||||
|           @categories =  BulletinCategory.all |           @categories =  BulletinCategory.all | ||||||
|  | @ -89,7 +92,7 @@ class Admin::PagesController < ApplicationController | ||||||
| 	    @item.page_contexts.build(:create_user_id => current_user.id, :update_user_id => current_user.id ) | 	    @item.page_contexts.build(:create_user_id => current_user.id, :update_user_id => current_user.id ) | ||||||
| 	  end | 	  end | ||||||
| 	 | 	 | ||||||
| 	params[:page][:frontend_field] = params[:page][:frontend_field].zip( params[:page][:frontend_field_type] )	   | 	params[:page][:frontend_field] = params[:page][:frontend_field].zip( params[:page][:frontend_field_type] ) if params[:page][:frontend_field]  | ||||||
| 	params[:page][:frontend_field_type] = nil | 	params[:page][:frontend_field_type] = nil | ||||||
| 	 | 	 | ||||||
|     if @item.update_attributes(params[:page]) |     if @item.update_attributes(params[:page]) | ||||||
|  |  | ||||||
|  | @ -19,7 +19,8 @@ | ||||||
| </span> | </span> | ||||||
| 
 | 
 | ||||||
| <span id='widget_style_list'> | <span id='widget_style_list'> | ||||||
| 	<%= f.select :widget_style, @widget_style, :selected => @part.widget_style %> | 	<%#= f.select :widget_style, @widget_style, :selected => @part.widget_style %> | ||||||
|  | 	<%= select('page_part','widget_style', @widget_style, :selected => @part[:widget_style], :include_blank => true ) rescue ''%> | ||||||
| </span> | </span> | ||||||
| 
 | 
 | ||||||
| : | : | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| $('#widget_list select').html("<%= j options_for_select(@module_app.widgets.collect{|k,v| k}) %>") | $('#widget_list select').html("<%= j options_for_select(@module_app.widgets.collect{|k,v| k}) %>"); | ||||||
| $('#widget_style_list select').html("<%= j options_for_select( @module_app.widgets[@widget_path] ) if !@widget_path.blank? %>") | $('#widget_style_list').html("<%= escape_javascript(select 'page_part', 'widget_style', @module_app.widgets[@widget_path]) if !@widget_path.blank? %>"); | ||||||
| $('#widget_field').html("<%= j render 'widget_fields' %>") | $('#widget_field').html("<%= j render 'widget_fields' %>"); | ||||||
| $('#widget_category').html("<%= j render 'widget_categories' %>") | $('#widget_category').html("<%= j render 'widget_categories' %>"); | ||||||
| $('#widget_tag').html("<%= j render 'widget_tags' %>") | $('#widget_tag').html("<%= j render 'widget_tags' %>"); | ||||||
|  | @ -0,0 +1,92 @@ | ||||||
|  | class Panel::Archive::FrontEnd::ArchiveFilesController < OrbitWidgetController | ||||||
|  | 
 | ||||||
|  |   def initialize | ||||||
|  |     super | ||||||
|  |     @app_title = 'archive_files' | ||||||
|  |   end | ||||||
|  |    | ||||||
|  |   def index | ||||||
|  |      | ||||||
|  | 	@item = Page.find(params[:page_id]) | ||||||
|  | 	 | ||||||
|  | 	@title = @item.i18n_variable[I18n.locale] | ||||||
|  |    | ||||||
|  |   	if @item.frontend_data_count | ||||||
|  | 		@page_num = @item.frontend_data_count | ||||||
|  | 	else | ||||||
|  | 		@page_num = 0 | ||||||
|  | 	end | ||||||
|  |    | ||||||
|  | 	date_now = Time.now | ||||||
|  | 	 | ||||||
|  | 	@archive_file_categorys = ArchiveFileCategory.all | ||||||
|  | 	 | ||||||
|  | 	# @archive_files = ArchiveFile.where( :is_hidden => false ).desc(:is_top).page(params[:page]).per(@page_num) | ||||||
|  | 	 | ||||||
|  |     if !params[:category_id].blank? | ||||||
|  |       @archive_files = ArchiveFile.can_display.where(:archive_file_category_id => params[:category_id]).desc( :is_top ).page( params[:page_main] ).per(@page_num) | ||||||
|  |       @current_category = ArchiveFileCategory.from_id(params[:category_id]) rescue nil | ||||||
|  |     elsif !params[:tag_id].blank? | ||||||
|  |       @tag = ArchiveTag.find(params[:tag_id]) rescue nil | ||||||
|  |       @tag = ArchiveTag.where(key: params[:tag_id])[0] unless @tag | ||||||
|  |       @archive_files = @tag.archive_files.can_display.desc( :is_top ).page( params[:page_main] ).per(@page_num) | ||||||
|  |     else | ||||||
|  |       @archive_files = ArchiveFile.can_display.desc( :is_top ).page( params[:page_main] ).per(@page_num) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  | 	get_categorys | ||||||
|  |   end | ||||||
|  |    | ||||||
|  |   def show | ||||||
|  |      | ||||||
|  | 	@item = Page.find(params[:page_id]) | ||||||
|  | 	 | ||||||
|  | 	@title = @item.i18n_variable[I18n.locale] | ||||||
|  | 	 | ||||||
|  |     @archive_file = ArchiveFile.find(params[:id]) | ||||||
|  | 	 | ||||||
|  | 	get_categorys | ||||||
|  | 	 | ||||||
|  |   end | ||||||
|  |    | ||||||
|  |   protected | ||||||
|  |    | ||||||
|  |   def reload_archive_files | ||||||
|  |      | ||||||
|  | 	@item = Page.find(params[:page_id]) | ||||||
|  | 	 | ||||||
|  | 	@title = @item.i18n_variable[I18n.locale] | ||||||
|  |    | ||||||
|  |   	if @item.frontend_data_count | ||||||
|  | 		@page_num = @item.frontend_data_count | ||||||
|  | 	else | ||||||
|  | 		@page_num = 0 | ||||||
|  | 	end | ||||||
|  |    | ||||||
|  | 	date_now = Time.now | ||||||
|  | 	 | ||||||
|  | 	@archive_file_categorys = ArchiveFileCategory.all | ||||||
|  | 	 | ||||||
|  | 	# @archive_files = ArchiveFile.where( :is_hidden => false ).desc(:is_top).page(params[:page]).per(@page_num) | ||||||
|  | 	 | ||||||
|  | 	 | ||||||
|  |     if !params[:category_id].blank? | ||||||
|  |       @archive_files = ArchiveFile.can_display.where(:archive_file_category_id => params[:category_id]).desc( :is_top ).page( params[:page_main] ).per(@page_num) | ||||||
|  |       @current_category = ArchiveFileCategory.from_id(params[:category_id]) rescue nil | ||||||
|  |     elsif !params[:tag_id].blank? | ||||||
|  |       @tag = ArchiveTag.find(params[:tag_id]) rescue nil | ||||||
|  |       @tag = ArchiveTag.where(key: params[:tag_id])[0] unless @tag | ||||||
|  |       @archive_files = @tag.archive_files.can_display.desc( :is_top ).page( params[:page_main] ).per(@page_num) | ||||||
|  |     else | ||||||
|  |       @archive_files = ArchiveFile.can_display.desc( :is_top ).page( params[:page_main] ).per(@page_num) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  | 	get_categorys | ||||||
|  | 	 | ||||||
|  |   end | ||||||
|  |    | ||||||
|  |   def get_categorys | ||||||
|  |     @archive_file_categorys = ArchiveFileCategory.excludes('disabled' => true) | ||||||
|  |   end | ||||||
|  |    | ||||||
|  | end | ||||||
|  | @ -6,13 +6,8 @@ class ArchiveFile | ||||||
|   include Mongoid::MultiParameterAttributes |   include Mongoid::MultiParameterAttributes | ||||||
| 
 | 
 | ||||||
|   PAYMENT_TYPES = @site_valid_locales |   PAYMENT_TYPES = @site_valid_locales | ||||||
|    | 
 | ||||||
| <<<<<<< HEAD |   field :title, localize: true | ||||||
| ======= |  | ||||||
|   PAYMENT_TYPES = @site_valid_locales |  | ||||||
|    |  | ||||||
| >>>>>>> archive checkbox |  | ||||||
|   has_one :title, :class_name => "I18nVariable", :as => :language_value, :autosave => true, :dependent => :destroy |  | ||||||
|    |    | ||||||
|   has_and_belongs_to_many :tags, :class_name => "ArchiveTag" |   has_and_belongs_to_many :tags, :class_name => "ArchiveTag" | ||||||
|    |    | ||||||
|  | @ -23,6 +18,8 @@ class ArchiveFile | ||||||
|   field :is_hot, :type => Boolean, :default => false  |   field :is_hot, :type => Boolean, :default => false  | ||||||
|   field :is_hidden, :type => Boolean, :default => false  |   field :is_hidden, :type => Boolean, :default => false  | ||||||
|    |    | ||||||
|  |   scope :can_display,where(is_hidden: false) | ||||||
|  |    | ||||||
|   belongs_to :archive_file_category |   belongs_to :archive_file_category | ||||||
| 
 | 
 | ||||||
|   has_many :archive_file_multiples, :autosave => true, :dependent => :destroy |   has_many :archive_file_multiples, :autosave => true, :dependent => :destroy | ||||||
|  |  | ||||||
|  | @ -5,16 +5,22 @@ class ArchiveFileMultiple | ||||||
| 
 | 
 | ||||||
|   mount_uploader :file, AssetUploader |   mount_uploader :file, AssetUploader | ||||||
|    |    | ||||||
|   # field :filetitle |   field :file_title, localize: true | ||||||
|   # field :description |   # field :description | ||||||
|   has_one :i18n_variable, :as => :language_value, :autosave => true, :dependent => :destroy |   field :choose_lang, :type => Array, :default => nil | ||||||
|  |    | ||||||
|  |   # has_one :i18n_variable, :as => :language_value, :autosave => true, :dependent => :destroy | ||||||
|    |    | ||||||
|   field :should_destroy, :type => Boolean |   field :should_destroy, :type => Boolean | ||||||
|  | 
 | ||||||
|  |   def choose_lang_display(lang) | ||||||
|  |     self.choose_lang.include?(lang) | ||||||
|  |   end | ||||||
|    |    | ||||||
|   belongs_to :archive_file |   belongs_to :archive_file | ||||||
|    |    | ||||||
|   has_many :archive_file_multiple_langs, :autosave => true, :dependent => :destroy |   # has_many :archive_file_multiple_langs, :autosave => true, :dependent => :destroy | ||||||
|    |    | ||||||
|   accepts_nested_attributes_for :archive_file_multiple_langs, :allow_destroy => true |   # accepts_nested_attributes_for :archive_file_multiple_langs, :allow_destroy => true | ||||||
|    |    | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -1,10 +0,0 @@ | ||||||
| class ArchiveFileMultipleLang |  | ||||||
| 
 |  | ||||||
|   include Mongoid::Document |  | ||||||
|   include Mongoid::Timestamps |  | ||||||
|    |  | ||||||
|   field :choose_lang |  | ||||||
|    |  | ||||||
|   belongs_to :archive_file_multiple |  | ||||||
| 
 |  | ||||||
| end |  | ||||||
|  | @ -19,7 +19,7 @@ | ||||||
| 	</td> | 	</td> | ||||||
| 	<td><%= post.archive_file_category.i18n_variable[I18n.locale] %></td> | 	<td><%= post.archive_file_category.i18n_variable[I18n.locale] %></td> | ||||||
| 	<td> | 	<td> | ||||||
| 	<%= link_to post.title[I18n.locale], panel_archive_back_end_archive_file_path(post) %> | 	<%= link_to post.title, panel_archive_front_end_archive_file_path(post) %> | ||||||
| 	</td> | 	</td> | ||||||
| 	<td> | 	<td> | ||||||
| 		<% post.tags.each do |tag| %> | 		<% post.tags.each do |tag| %> | ||||||
|  |  | ||||||
|  | @ -46,8 +46,8 @@ | ||||||
| 			<%= f.select :archive_file_category_id, @archive_file_categorys.collect {|t| [ t.i18n_variable[I18n.locale], t.id ]} %> | 			<%= f.select :archive_file_category_id, @archive_file_categorys.collect {|t| [ t.i18n_variable[I18n.locale], t.id ]} %> | ||||||
| 			 | 			 | ||||||
| 			<ul class="nav nav-tabs"> | 			<ul class="nav nav-tabs"> | ||||||
| 				<%# @site_valid_locales.each_with_index do |locale, i| %> | 				<% @site_valid_locales.each_with_index do |locale, i| %> | ||||||
| 				<% site_valid_locales_default_head.each_with_index do |locale, i| %> | 				<%# site_valid_locales_default_head.each_with_index do |locale, i| %> | ||||||
| 			    <li <%= ( i == 0 ) ? " class='active'" : '' %>><a data-toggle="tab" href=".<%= locale %>"><%= I18nVariable.from_locale(locale) %></a></li> | 			    <li <%= ( i == 0 ) ? " class='active'" : '' %>><a data-toggle="tab" href=".<%= locale %>"><%= I18nVariable.from_locale(locale) %></a></li> | ||||||
| 				<% end %> | 				<% end %> | ||||||
| 			</ul> | 			</ul> | ||||||
|  | @ -59,10 +59,10 @@ | ||||||
| 				<div class="<%= locale %> fade tab-pane <%= ( i == 0 ) ? "in active" : '' %>"> | 				<div class="<%= locale %> fade tab-pane <%= ( i == 0 ) ? "in active" : '' %>"> | ||||||
| 					<div class="title"> | 					<div class="title"> | ||||||
| 						<%= f.label :title %> | 						<%= f.label :title %> | ||||||
| 						<%= f.fields_for :title, (@archive_file.new_record? ? @archive_file.build_title : @archive_file.title ) do |f| %> | 						<%= f.fields_for :title_translations do |f| %> | ||||||
| 							<%= I18nVariable.from_locale(locale) %> | 							<%= I18nVariable.from_locale(locale) %> | ||||||
| 							<%= f.text_field locale, :class=>'post-title' %> | 							<%= f.text_field locale, :class=>'post-title', :value => (@archive_file.title_translations[locale] rescue nil) %> | ||||||
| 						<% end %> | 						<% end %>		 | ||||||
| 					</div> | 					</div> | ||||||
| 					 | 					 | ||||||
| 				</div> | 				</div> | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ | ||||||
| 				<div class="control-group"> | 				<div class="control-group"> | ||||||
| 					<div class="controls"> | 					<div class="controls"> | ||||||
| 					<%= f.file_field :file %> | 					<%= f.file_field :file %> | ||||||
|  | 					<%= form_file.file.file ? ( link_to t(:view), form_file.file.url, {:class => 'btn', :target => '_blank', :title => t(:view)} ) : '' %> | ||||||
| 					</div> | 					</div> | ||||||
| 				</div> | 				</div> | ||||||
| 			</td>	 | 			</td>	 | ||||||
|  | @ -15,15 +16,15 @@ | ||||||
| 					<% @site_valid_locales.each_with_index do |locale, i| %> | 					<% @site_valid_locales.each_with_index do |locale, i| %> | ||||||
| 					 | 					 | ||||||
| 					<div class="<%= locale %> fade tab-pane <%= ( i == 0 ) ? "in active" : '' %>"> | 					<div class="<%= locale %> fade tab-pane <%= ( i == 0 ) ? "in active" : '' %>"> | ||||||
| 						 | 						<%#= f.fields_for :i18n_variable, (form_file.new_record? ? form_file.build_i18n_variable : form_file.i18n_variable ) do |f| %> | ||||||
| 						<%= f.fields_for :i18n_variable, (form_file.new_record? ? form_file.build_i18n_variable : form_file.i18n_variable ) do |f| %> | 						<%= f.fields_for :file_title_translations do |f| %> | ||||||
| 							<div class="control-group"> | 							<div class="control-group"> | ||||||
| 								<label for="link-<%= locale %>" class="control-label"><%= I18nVariable.first(:conditions => {:key => locale})[I18n.locale] %></label> | 							<label for="link-<%= locale %>" class="control-label"><%= I18nVariable.from_locale(locale) %></label> | ||||||
| 								<div class="controls"> | 							<div class="controls"> | ||||||
| 								<%= f.text_field locale, :id => "link-#{locale}", :class => "input-xlarge" %> | 							<%= f.text_field locale, :class=>'post-file_title', :value => (form_file.file_title_translations[locale] rescue nil) %> | ||||||
| 								</div> |  | ||||||
| 							</div> | 							</div> | ||||||
| 						<% end %> | 							</div> | ||||||
|  | 						<% end %>	 | ||||||
| 						 | 						 | ||||||
| 					</div> | 					</div> | ||||||
| 
 | 
 | ||||||
|  | @ -34,9 +35,10 @@ | ||||||
| 			</td> | 			</td> | ||||||
| 			<td> | 			<td> | ||||||
| 				<% @site_valid_locales.each do |locale| %> | 				<% @site_valid_locales.each do |locale| %> | ||||||
| 				<%= check_box_tag 'archive_file[archive_file_multiple][archive_file_multiple_langs_attributes][choose_lang][]', locale %> | 				<%= check_box_tag "archive_file[archive_file_multiples_attributes][#{( form_file.new_record? ? 'new_archive_file_multiples' : "#{i}" )}][choose_lang][]", locale, (form_file.choose_lang.nil? ? true : form_file.choose_lang.include?(locale)) %> | ||||||
| 				<%= I18nVariable.from_locale(locale) %> | 				<%= I18nVariable.from_locale(locale) %> | ||||||
| 				<% end %> | 				<% end %> | ||||||
|  | 				<%= hidden_field_tag 'archive_file[archive_file_multiples_attributes][0][choose_lang][]', '' %> | ||||||
| 			</td> | 			</td> | ||||||
| 			 | 			 | ||||||
| 			<td> | 			<td> | ||||||
|  |  | ||||||
|  | @ -0,0 +1,219 @@ | ||||||
|  | /* | ||||||
|  |  * jQuery File Upload File Processing Plugin 1.0 | ||||||
|  |  * https://github.com/blueimp/jQuery-File-Upload
 | ||||||
|  |  * | ||||||
|  |  * Copyright 2012, Sebastian Tschan | ||||||
|  |  * https://blueimp.net
 | ||||||
|  |  * | ||||||
|  |  * Licensed under the MIT license: | ||||||
|  |  * http://www.opensource.org/licenses/MIT
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /*jslint nomen: true, unparam: true, regexp: true */ | ||||||
|  | /*global define, window, document */ | ||||||
|  | 
 | ||||||
|  | (function (factory) { | ||||||
|  |     'use strict'; | ||||||
|  |     if (typeof define === 'function' && define.amd) { | ||||||
|  |         // Register as an anonymous AMD module:
 | ||||||
|  |         define([ | ||||||
|  |             'jquery', | ||||||
|  |             'load-image', | ||||||
|  |             'canvas-to-blob', | ||||||
|  |             './jquery.fileupload' | ||||||
|  |         ], factory); | ||||||
|  |     } else { | ||||||
|  |         // Browser globals:
 | ||||||
|  |         factory( | ||||||
|  |             window.jQuery, | ||||||
|  |             window.loadImage | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | }(function ($, loadImage) { | ||||||
|  |     'use strict'; | ||||||
|  | 
 | ||||||
|  |     // The File Upload IP version extends the basic fileupload widget
 | ||||||
|  |     // with file processing functionality:
 | ||||||
|  |     $.widget('blueimpFP.fileupload', $.blueimp.fileupload, { | ||||||
|  | 
 | ||||||
|  |         options: { | ||||||
|  |             // The list of file processing actions:
 | ||||||
|  |             process: [ | ||||||
|  |             /* | ||||||
|  |                 { | ||||||
|  |                     action: 'load', | ||||||
|  |                     fileTypes: /^image\/(gif|jpeg|png)$/, | ||||||
|  |                     maxFileSize: 20000000 // 20MB
 | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     action: 'resize', | ||||||
|  |                     maxWidth: 1920, | ||||||
|  |                     maxHeight: 1200, | ||||||
|  |                     minWidth: 800, | ||||||
|  |                     minHeight: 600 | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     action: 'save' | ||||||
|  |                 } | ||||||
|  |             */ | ||||||
|  |             ], | ||||||
|  | 
 | ||||||
|  |             // The add callback is invoked as soon as files are added to the
 | ||||||
|  |             // fileupload widget (via file input selection, drag & drop or add
 | ||||||
|  |             // API call). See the basic file upload widget for more information:
 | ||||||
|  |             add: function (e, data) { | ||||||
|  |                 $(this).fileupload('process', data).done(function () { | ||||||
|  |                     data.submit(); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         processActions: { | ||||||
|  |             // Loads the image given via data.files and data.index
 | ||||||
|  |             // as canvas element.
 | ||||||
|  |             // Accepts the options fileTypes (regular expression)
 | ||||||
|  |             // and maxFileSize (integer) to limit the files to load:
 | ||||||
|  |             load: function (data, options) { | ||||||
|  |                 var that = this, | ||||||
|  |                     file = data.files[data.index], | ||||||
|  |                     dfd = $.Deferred(); | ||||||
|  |                 if (window.HTMLCanvasElement && | ||||||
|  |                         window.HTMLCanvasElement.prototype.toBlob && | ||||||
|  |                         ($.type(options.maxFileSize) !== 'number' || | ||||||
|  |                             file.size < options.maxFileSize) && | ||||||
|  |                         (!options.fileTypes || | ||||||
|  |                             options.fileTypes.test(file.type))) { | ||||||
|  |                     loadImage( | ||||||
|  |                         file, | ||||||
|  |                         function (canvas) { | ||||||
|  |                             data.canvas = canvas; | ||||||
|  |                             dfd.resolveWith(that, [data]); | ||||||
|  |                         }, | ||||||
|  |                         {canvas: true} | ||||||
|  |                     ); | ||||||
|  |                 } else { | ||||||
|  |                     dfd.rejectWith(that, [data]); | ||||||
|  |                 } | ||||||
|  |                 return dfd.promise(); | ||||||
|  |             }, | ||||||
|  |             // Resizes the image given as data.canvas and updates
 | ||||||
|  |             // data.canvas with the resized image.
 | ||||||
|  |             // Accepts the options maxWidth, maxHeight, minWidth and
 | ||||||
|  |             // minHeight to scale the given image:
 | ||||||
|  |             resize: function (data, options) { | ||||||
|  |                 if (data.canvas) { | ||||||
|  |                     var canvas = loadImage.scale(data.canvas, options); | ||||||
|  |                     if (canvas.width !== data.canvas.width || | ||||||
|  |                             canvas.height !== data.canvas.height) { | ||||||
|  |                         data.canvas = canvas; | ||||||
|  |                         data.processed = true; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 return data; | ||||||
|  |             }, | ||||||
|  |             // Saves the processed image given as data.canvas
 | ||||||
|  |             // inplace at data.index of data.files:
 | ||||||
|  |             save: function (data, options) { | ||||||
|  |                 // Do nothing if no processing has happened:
 | ||||||
|  |                 if (!data.canvas || !data.processed) { | ||||||
|  |                     return data; | ||||||
|  |                 } | ||||||
|  |                 var that = this, | ||||||
|  |                     file = data.files[data.index], | ||||||
|  |                     name = file.name, | ||||||
|  |                     dfd = $.Deferred(), | ||||||
|  |                     callback = function (blob) { | ||||||
|  |                         if (!blob.name) { | ||||||
|  |                             if (file.type === blob.type) { | ||||||
|  |                                 blob.name = file.name; | ||||||
|  |                             } else if (file.name) { | ||||||
|  |                                 blob.name = file.name.replace( | ||||||
|  |                                     /\..+$/, | ||||||
|  |                                     '.' + blob.type.substr(6) | ||||||
|  |                                 ); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         // Store the created blob at the position
 | ||||||
|  |                         // of the original file in the files list:
 | ||||||
|  |                         data.files[data.index] = blob; | ||||||
|  |                         dfd.resolveWith(that, [data]); | ||||||
|  |                     }; | ||||||
|  |                 // Use canvas.mozGetAsFile directly, to retain the filename, as
 | ||||||
|  |                 // Gecko doesn't support the filename option for FormData.append:
 | ||||||
|  |                 if (data.canvas.mozGetAsFile) { | ||||||
|  |                     callback(data.canvas.mozGetAsFile( | ||||||
|  |                         (/^image\/(jpeg|png)$/.test(file.type) && name) || | ||||||
|  |                             ((name && name.replace(/\..+$/, '')) || | ||||||
|  |                                 'blob') + '.png', | ||||||
|  |                         file.type | ||||||
|  |                     )); | ||||||
|  |                 } else { | ||||||
|  |                     data.canvas.toBlob(callback, file.type); | ||||||
|  |                 } | ||||||
|  |                 return dfd.promise(); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         // Resizes the file at the given index and stores the created blob at
 | ||||||
|  |         // the original position of the files list, returns a Promise object:
 | ||||||
|  |         _processFile: function (files, index, options) { | ||||||
|  |             var that = this, | ||||||
|  |                 dfd = $.Deferred().resolveWith(that, [{ | ||||||
|  |                     files: files, | ||||||
|  |                     index: index | ||||||
|  |                 }]), | ||||||
|  |                 chain = dfd.promise(); | ||||||
|  |             that._processing += 1; | ||||||
|  |             $.each(options.process, function (i, settings) { | ||||||
|  |                 chain = chain.pipe(function (data) { | ||||||
|  |                     return that.processActions[settings.action] | ||||||
|  |                         .call(this, data, settings); | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  |             chain.always(function () { | ||||||
|  |                 that._processing -= 1; | ||||||
|  |                 if (that._processing === 0) { | ||||||
|  |                     that.element | ||||||
|  |                         .removeClass('fileupload-processing'); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |             if (that._processing === 1) { | ||||||
|  |                 that.element.addClass('fileupload-processing'); | ||||||
|  |             } | ||||||
|  |             return chain; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         // Processes the files given as files property of the data parameter,
 | ||||||
|  |         // returns a Promise object that allows to bind a done handler, which
 | ||||||
|  |         // will be invoked after processing all files (inplace) is done:
 | ||||||
|  |         process: function (data) { | ||||||
|  |             var that = this, | ||||||
|  |                 options = $.extend({}, this.options, data); | ||||||
|  |             if (options.process && options.process.length && | ||||||
|  |                     this._isXHRUpload(options)) { | ||||||
|  |                 $.each(data.files, function (index, file) { | ||||||
|  |                     that._processingQueue = that._processingQueue.pipe( | ||||||
|  |                         function () { | ||||||
|  |                             var dfd = $.Deferred(); | ||||||
|  |                             that._processFile(data.files, index, options) | ||||||
|  |                                 .always(function () { | ||||||
|  |                                     dfd.resolveWith(that); | ||||||
|  |                                 }); | ||||||
|  |                             return dfd.promise(); | ||||||
|  |                         } | ||||||
|  |                     ); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             return this._processingQueue; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _create: function () { | ||||||
|  |             $.blueimp.fileupload.prototype._create.call(this); | ||||||
|  |             this._processing = 0; | ||||||
|  |             this._processingQueue = $.Deferred().resolveWith(this) | ||||||
|  |                 .promise(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  | })); | ||||||
|  | @ -0,0 +1,736 @@ | ||||||
|  | /* | ||||||
|  |  * jQuery File Upload User Interface Plugin 6.9.4 | ||||||
|  |  * https://github.com/blueimp/jQuery-File-Upload
 | ||||||
|  |  * | ||||||
|  |  * Copyright 2010, Sebastian Tschan | ||||||
|  |  * https://blueimp.net
 | ||||||
|  |  * | ||||||
|  |  * Licensed under the MIT license: | ||||||
|  |  * http://www.opensource.org/licenses/MIT
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /*jslint nomen: true, unparam: true, regexp: true */ | ||||||
|  | /*global define, window, document, URL, webkitURL, FileReader */ | ||||||
|  | 
 | ||||||
|  | (function (factory) { | ||||||
|  |     'use strict'; | ||||||
|  |     if (typeof define === 'function' && define.amd) { | ||||||
|  |         // Register as an anonymous AMD module:
 | ||||||
|  |         define([ | ||||||
|  |             'jquery', | ||||||
|  |             'tmpl', | ||||||
|  |             'load-image', | ||||||
|  |             './jquery.fileupload-fp' | ||||||
|  |         ], factory); | ||||||
|  |     } else { | ||||||
|  |         // Browser globals:
 | ||||||
|  |         factory( | ||||||
|  |             window.jQuery, | ||||||
|  |             window.tmpl, | ||||||
|  |             window.loadImage | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | }(function ($, tmpl, loadImage) { | ||||||
|  |     'use strict'; | ||||||
|  | 
 | ||||||
|  |     // The UI version extends the FP (file processing) version or the basic
 | ||||||
|  |     // file upload widget and adds complete user interface interaction:
 | ||||||
|  |     var parentWidget = ($.blueimpFP || $.blueimp).fileupload; | ||||||
|  |     $.widget('blueimpUI.fileupload', parentWidget, { | ||||||
|  | 
 | ||||||
|  |         options: { | ||||||
|  |             // By default, files added to the widget are uploaded as soon
 | ||||||
|  |             // as the user clicks on the start buttons. To enable automatic
 | ||||||
|  |             // uploads, set the following option to true:
 | ||||||
|  |             autoUpload: false, | ||||||
|  |             // The following option limits the number of files that are
 | ||||||
|  |             // allowed to be uploaded using this widget:
 | ||||||
|  |             maxNumberOfFiles: undefined, | ||||||
|  |             // The maximum allowed file size:
 | ||||||
|  |             maxFileSize: undefined, | ||||||
|  |             // The minimum allowed file size:
 | ||||||
|  |             minFileSize: undefined, | ||||||
|  |             // The regular expression for allowed file types, matches
 | ||||||
|  |             // against either file type or file name:
 | ||||||
|  |             acceptFileTypes:  /.+$/i, | ||||||
|  |             // The regular expression to define for which files a preview
 | ||||||
|  |             // image is shown, matched against the file type:
 | ||||||
|  |             previewSourceFileTypes: /^image\/(gif|jpeg|png)$/, | ||||||
|  |             // The maximum file size of images that are to be displayed as preview:
 | ||||||
|  |             previewSourceMaxFileSize: 5000000, // 5MB
 | ||||||
|  |             // The maximum width of the preview images:
 | ||||||
|  |             previewMaxWidth: 80, | ||||||
|  |             // The maximum height of the preview images:
 | ||||||
|  |             previewMaxHeight: 80, | ||||||
|  |             // By default, preview images are displayed as canvas elements
 | ||||||
|  |             // if supported by the browser. Set the following option to false
 | ||||||
|  |             // to always display preview images as img elements:
 | ||||||
|  |             previewAsCanvas: true, | ||||||
|  |             // The ID of the upload template:
 | ||||||
|  |             uploadTemplateId: 'template-upload', | ||||||
|  |             // The ID of the download template:
 | ||||||
|  |             downloadTemplateId: 'template-download', | ||||||
|  |             // The container for the list of files. If undefined, it is set to
 | ||||||
|  |             // an element with class "files" inside of the widget element:
 | ||||||
|  |             filesContainer: undefined, | ||||||
|  |             // By default, files are appended to the files container.
 | ||||||
|  |             // Set the following option to true, to prepend files instead:
 | ||||||
|  |             prependFiles: false, | ||||||
|  |             // The expected data type of the upload response, sets the dataType
 | ||||||
|  |             // option of the $.ajax upload requests:
 | ||||||
|  |             dataType: 'json', | ||||||
|  | 
 | ||||||
|  |             // The add callback is invoked as soon as files are added to the fileupload
 | ||||||
|  |             // widget (via file input selection, drag & drop or add API call).
 | ||||||
|  |             // See the basic file upload widget for more information:
 | ||||||
|  |             add: function (e, data) { | ||||||
|  |                 var that = $(this).data('fileupload'), | ||||||
|  |                     options = that.options, | ||||||
|  |                     files = data.files; | ||||||
|  |                 $(this).fileupload('process', data).done(function () { | ||||||
|  |                     that._adjustMaxNumberOfFiles(-files.length); | ||||||
|  |                     data.maxNumberOfFilesAdjusted = true; | ||||||
|  |                     data.files.valid = data.isValidated = that._validate(files); | ||||||
|  |                     data.context = that._renderUpload(files).data('data', data); | ||||||
|  |                     options.filesContainer[ | ||||||
|  |                         options.prependFiles ? 'prepend' : 'append' | ||||||
|  |                     ](data.context); | ||||||
|  |                     that._renderPreviews(files, data.context); | ||||||
|  |                     that._forceReflow(data.context); | ||||||
|  |                     that._transition(data.context).done( | ||||||
|  |                         function () { | ||||||
|  |                             if ((that._trigger('added', e, data) !== false) && | ||||||
|  |                                     (options.autoUpload || data.autoUpload) && | ||||||
|  |                                     data.autoUpload !== false && data.isValidated) { | ||||||
|  |                                 data.submit(); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     ); | ||||||
|  |                 }); | ||||||
|  |             }, | ||||||
|  |             // Callback for the start of each file upload request:
 | ||||||
|  |             send: function (e, data) { | ||||||
|  |                 var that = $(this).data('fileupload'); | ||||||
|  |                 if (!data.isValidated) { | ||||||
|  |                     if (!data.maxNumberOfFilesAdjusted) { | ||||||
|  |                         that._adjustMaxNumberOfFiles(-data.files.length); | ||||||
|  |                         data.maxNumberOfFilesAdjusted = true; | ||||||
|  |                     } | ||||||
|  |                     if (!that._validate(data.files)) { | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (data.context && data.dataType && | ||||||
|  |                         data.dataType.substr(0, 6) === 'iframe') { | ||||||
|  |                     // Iframe Transport does not support progress events.
 | ||||||
|  |                     // In lack of an indeterminate progress bar, we set
 | ||||||
|  |                     // the progress to 100%, showing the full animated bar:
 | ||||||
|  |                     data.context | ||||||
|  |                         .find('.progress').addClass( | ||||||
|  |                             !$.support.transition && 'progress-animated' | ||||||
|  |                         ) | ||||||
|  |                         .attr('aria-valuenow', 100) | ||||||
|  |                         .find('.bar').css( | ||||||
|  |                             'width', | ||||||
|  |                             '100%' | ||||||
|  |                         ); | ||||||
|  |                 } | ||||||
|  |                 return that._trigger('sent', e, data); | ||||||
|  |             }, | ||||||
|  |             // Callback for successful uploads:
 | ||||||
|  |             done: function (e, data) { | ||||||
|  |                 var that = $(this).data('fileupload'), | ||||||
|  |                     template; | ||||||
|  |                 if (data.context) { | ||||||
|  |                     data.context.each(function (index) { | ||||||
|  |                         var file = ($.isArray(data.result) && | ||||||
|  |                                 data.result[index]) || {error: 'emptyResult'}; | ||||||
|  |                         if (file.error) { | ||||||
|  |                             that._adjustMaxNumberOfFiles(1); | ||||||
|  |                         } | ||||||
|  |                         that._transition($(this)).done( | ||||||
|  |                             function () { | ||||||
|  |                                 var node = $(this); | ||||||
|  |                                 template = that._renderDownload([file]) | ||||||
|  |                                     .replaceAll(node); | ||||||
|  |                                 that._forceReflow(template); | ||||||
|  |                                 that._transition(template).done( | ||||||
|  |                                     function () { | ||||||
|  |                                         data.context = $(this); | ||||||
|  |                                         that._trigger('completed', e, data); | ||||||
|  |                                     } | ||||||
|  |                                 ); | ||||||
|  |                             } | ||||||
|  |                         ); | ||||||
|  |                     }); | ||||||
|  |                 } else { | ||||||
|  |                     if ($.isArray(data.result)) { | ||||||
|  |                         $.each(data.result, function (index, file) { | ||||||
|  |                             if (data.maxNumberOfFilesAdjusted && file.error) { | ||||||
|  |                                 that._adjustMaxNumberOfFiles(1); | ||||||
|  |                             } else if (!data.maxNumberOfFilesAdjusted && | ||||||
|  |                                     !file.error) { | ||||||
|  |                                 that._adjustMaxNumberOfFiles(-1); | ||||||
|  |                             } | ||||||
|  |                         }); | ||||||
|  |                         data.maxNumberOfFilesAdjusted = true; | ||||||
|  |                     } | ||||||
|  |                     template = that._renderDownload(data.result) | ||||||
|  |                         .appendTo(that.options.filesContainer); | ||||||
|  |                     that._forceReflow(template); | ||||||
|  |                     that._transition(template).done( | ||||||
|  |                         function () { | ||||||
|  |                             data.context = $(this); | ||||||
|  |                             that._trigger('completed', e, data); | ||||||
|  |                         } | ||||||
|  |                     ); | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             // Callback for failed (abort or error) uploads:
 | ||||||
|  |             fail: function (e, data) { | ||||||
|  |                 var that = $(this).data('fileupload'), | ||||||
|  |                     template; | ||||||
|  |                 if (data.maxNumberOfFilesAdjusted) { | ||||||
|  |                     that._adjustMaxNumberOfFiles(data.files.length); | ||||||
|  |                 } | ||||||
|  |                 if (data.context) { | ||||||
|  |                     data.context.each(function (index) { | ||||||
|  |                         if (data.errorThrown !== 'abort') { | ||||||
|  |                             var file = data.files[index]; | ||||||
|  |                             file.error = file.error || data.errorThrown || | ||||||
|  |                                 true; | ||||||
|  |                             that._transition($(this)).done( | ||||||
|  |                                 function () { | ||||||
|  |                                     var node = $(this); | ||||||
|  |                                     template = that._renderDownload([file]) | ||||||
|  |                                         .replaceAll(node); | ||||||
|  |                                     that._forceReflow(template); | ||||||
|  |                                     that._transition(template).done( | ||||||
|  |                                         function () { | ||||||
|  |                                             data.context = $(this); | ||||||
|  |                                             that._trigger('failed', e, data); | ||||||
|  |                                         } | ||||||
|  |                                     ); | ||||||
|  |                                 } | ||||||
|  |                             ); | ||||||
|  |                         } else { | ||||||
|  |                             that._transition($(this)).done( | ||||||
|  |                                 function () { | ||||||
|  |                                     $(this).remove(); | ||||||
|  |                                     that._trigger('failed', e, data); | ||||||
|  |                                 } | ||||||
|  |                             ); | ||||||
|  |                         } | ||||||
|  |                     }); | ||||||
|  |                 } else if (data.errorThrown !== 'abort') { | ||||||
|  |                     data.context = that._renderUpload(data.files) | ||||||
|  |                         .appendTo(that.options.filesContainer) | ||||||
|  |                         .data('data', data); | ||||||
|  |                     that._forceReflow(data.context); | ||||||
|  |                     that._transition(data.context).done( | ||||||
|  |                         function () { | ||||||
|  |                             data.context = $(this); | ||||||
|  |                             that._trigger('failed', e, data); | ||||||
|  |                         } | ||||||
|  |                     ); | ||||||
|  |                 } else { | ||||||
|  |                     that._trigger('failed', e, data); | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             // Callback for upload progress events:
 | ||||||
|  |             progress: function (e, data) { | ||||||
|  |                 if (data.context) { | ||||||
|  |                     var progress = parseInt(data.loaded / data.total * 100, 10); | ||||||
|  |                     data.context.find('.progress') | ||||||
|  |                         .attr('aria-valuenow', progress) | ||||||
|  |                         .find('.bar').css( | ||||||
|  |                             'width', | ||||||
|  |                             progress + '%' | ||||||
|  |                         ); | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             // Callback for global upload progress events:
 | ||||||
|  |             progressall: function (e, data) { | ||||||
|  |                 var $this = $(this), | ||||||
|  |                     progress = parseInt(data.loaded / data.total * 100, 10), | ||||||
|  |                     globalProgressNode = $this.find('.fileupload-progress'), | ||||||
|  |                     extendedProgressNode = globalProgressNode | ||||||
|  |                         .find('.progress-extended'); | ||||||
|  |                 if (extendedProgressNode.length) { | ||||||
|  |                     extendedProgressNode.html( | ||||||
|  |                         $this.data('fileupload')._renderExtendedProgress(data) | ||||||
|  |                     ); | ||||||
|  |                 } | ||||||
|  |                 globalProgressNode | ||||||
|  |                     .find('.progress') | ||||||
|  |                     .attr('aria-valuenow', progress) | ||||||
|  |                     .find('.bar').css( | ||||||
|  |                         'width', | ||||||
|  |                         progress + '%' | ||||||
|  |                     ); | ||||||
|  |             }, | ||||||
|  |             // Callback for uploads start, equivalent to the global ajaxStart event:
 | ||||||
|  |             start: function (e) { | ||||||
|  |                 var that = $(this).data('fileupload'); | ||||||
|  |                 that._transition($(this).find('.fileupload-progress')).done( | ||||||
|  |                     function () { | ||||||
|  |                         that._trigger('started', e); | ||||||
|  |                     } | ||||||
|  |                 ); | ||||||
|  |             }, | ||||||
|  |             // Callback for uploads stop, equivalent to the global ajaxStop event:
 | ||||||
|  |             stop: function (e) { | ||||||
|  |                 var that = $(this).data('fileupload'); | ||||||
|  |                 that._transition($(this).find('.fileupload-progress')).done( | ||||||
|  |                     function () { | ||||||
|  |                         $(this).find('.progress') | ||||||
|  |                             .attr('aria-valuenow', '0') | ||||||
|  |                             .find('.bar').css('width', '0%'); | ||||||
|  |                         $(this).find('.progress-extended').html(' '); | ||||||
|  |                         that._trigger('stopped', e); | ||||||
|  |                     } | ||||||
|  |                 ); | ||||||
|  |             }, | ||||||
|  |             // Callback for file deletion:
 | ||||||
|  |             destroy: function (e, data) { | ||||||
|  |                 var that = $(this).data('fileupload'); | ||||||
|  |                 if (data.url) { | ||||||
|  |                     $.ajax(data); | ||||||
|  |                     that._adjustMaxNumberOfFiles(1); | ||||||
|  |                 } | ||||||
|  |                 that._transition(data.context).done( | ||||||
|  |                     function () { | ||||||
|  |                         $(this).remove(); | ||||||
|  |                         that._trigger('destroyed', e, data); | ||||||
|  |                     } | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         // Link handler, that allows to download files
 | ||||||
|  |         // by drag & drop of the links to the desktop:
 | ||||||
|  |         _enableDragToDesktop: function () { | ||||||
|  |             var link = $(this), | ||||||
|  |                 url = link.prop('href'), | ||||||
|  |                 name = link.prop('download'), | ||||||
|  |                 type = 'application/octet-stream'; | ||||||
|  |             link.bind('dragstart', function (e) { | ||||||
|  |                 try { | ||||||
|  |                     e.originalEvent.dataTransfer.setData( | ||||||
|  |                         'DownloadURL', | ||||||
|  |                         [type, name, url].join(':') | ||||||
|  |                     ); | ||||||
|  |                 } catch (err) {} | ||||||
|  |             }); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _adjustMaxNumberOfFiles: function (operand) { | ||||||
|  |             if (typeof this.options.maxNumberOfFiles === 'number') { | ||||||
|  |                 this.options.maxNumberOfFiles += operand; | ||||||
|  |                 if (this.options.maxNumberOfFiles < 1) { | ||||||
|  |                     this._disableFileInputButton(); | ||||||
|  |                 } else { | ||||||
|  |                     this._enableFileInputButton(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _formatFileSize: function (bytes) { | ||||||
|  |             if (typeof bytes !== 'number') { | ||||||
|  |                 return ''; | ||||||
|  |             } | ||||||
|  |             if (bytes >= 1000000000) { | ||||||
|  |                 return (bytes / 1000000000).toFixed(2) + ' GB'; | ||||||
|  |             } | ||||||
|  |             if (bytes >= 1000000) { | ||||||
|  |                 return (bytes / 1000000).toFixed(2) + ' MB'; | ||||||
|  |             } | ||||||
|  |             return (bytes / 1000).toFixed(2) + ' KB'; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _formatBitrate: function (bits) { | ||||||
|  |             if (typeof bits !== 'number') { | ||||||
|  |                 return ''; | ||||||
|  |             } | ||||||
|  |             if (bits >= 1000000000) { | ||||||
|  |                 return (bits / 1000000000).toFixed(2) + ' Gbit/s'; | ||||||
|  |             } | ||||||
|  |             if (bits >= 1000000) { | ||||||
|  |                 return (bits / 1000000).toFixed(2) + ' Mbit/s'; | ||||||
|  |             } | ||||||
|  |             if (bits >= 1000) { | ||||||
|  |                 return (bits / 1000).toFixed(2) + ' kbit/s'; | ||||||
|  |             } | ||||||
|  |             return bits + ' bit/s'; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _formatTime: function (seconds) { | ||||||
|  |             var date = new Date(seconds * 1000), | ||||||
|  |                 days = parseInt(seconds / 86400, 10); | ||||||
|  |             days = days ? days + 'd ' : ''; | ||||||
|  |             return days + | ||||||
|  |                 ('0' + date.getUTCHours()).slice(-2) + ':' + | ||||||
|  |                 ('0' + date.getUTCMinutes()).slice(-2) + ':' + | ||||||
|  |                 ('0' + date.getUTCSeconds()).slice(-2); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _formatPercentage: function (floatValue) { | ||||||
|  |             return (floatValue * 100).toFixed(2) + ' %'; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _renderExtendedProgress: function (data) { | ||||||
|  |             return this._formatBitrate(data.bitrate) + ' | ' + | ||||||
|  |                 this._formatTime( | ||||||
|  |                     (data.total - data.loaded) * 8 / data.bitrate | ||||||
|  |                 ) + ' | ' + | ||||||
|  |                 this._formatPercentage( | ||||||
|  |                     data.loaded / data.total | ||||||
|  |                 ) + ' | ' + | ||||||
|  |                 this._formatFileSize(data.loaded) + ' / ' + | ||||||
|  |                 this._formatFileSize(data.total); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _hasError: function (file) { | ||||||
|  |             if (file.error) { | ||||||
|  |                 return file.error; | ||||||
|  |             } | ||||||
|  |             // The number of added files is subtracted from
 | ||||||
|  |             // maxNumberOfFiles before validation, so we check if
 | ||||||
|  |             // maxNumberOfFiles is below 0 (instead of below 1):
 | ||||||
|  |             if (this.options.maxNumberOfFiles < 0) { | ||||||
|  |                 return 'maxNumberOfFiles'; | ||||||
|  |             } | ||||||
|  |             // Files are accepted if either the file type or the file name
 | ||||||
|  |             // matches against the acceptFileTypes regular expression, as
 | ||||||
|  |             // only browsers with support for the File API report the type:
 | ||||||
|  |             if (!(this.options.acceptFileTypes.test(file.type) || | ||||||
|  |                     this.options.acceptFileTypes.test(file.name))) { | ||||||
|  |                 return 'acceptFileTypes'; | ||||||
|  |             } | ||||||
|  |             if (this.options.maxFileSize && | ||||||
|  |                     file.size > this.options.maxFileSize) { | ||||||
|  |                 return 'maxFileSize'; | ||||||
|  |             } | ||||||
|  |             if (typeof file.size === 'number' && | ||||||
|  |                     file.size < this.options.minFileSize) { | ||||||
|  |                 return 'minFileSize'; | ||||||
|  |             } | ||||||
|  |             return null; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _validate: function (files) { | ||||||
|  |             var that = this, | ||||||
|  |                 valid = !!files.length; | ||||||
|  |             $.each(files, function (index, file) { | ||||||
|  |                 file.error = that._hasError(file); | ||||||
|  |                 if (file.error) { | ||||||
|  |                     valid = false; | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |             return valid; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _renderTemplate: function (func, files) { | ||||||
|  |             if (!func) { | ||||||
|  |                 return $(); | ||||||
|  |             } | ||||||
|  |             var result = func({ | ||||||
|  |                 files: files, | ||||||
|  |                 formatFileSize: this._formatFileSize, | ||||||
|  |                 options: this.options | ||||||
|  |             }); | ||||||
|  |             if (result instanceof $) { | ||||||
|  |                 return result; | ||||||
|  |             } | ||||||
|  |             return $(this.options.templatesContainer).html(result).children(); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _renderPreview: function (file, node) { | ||||||
|  |             var that = this, | ||||||
|  |                 options = this.options, | ||||||
|  |                 dfd = $.Deferred(); | ||||||
|  |             return ((loadImage && loadImage( | ||||||
|  |                 file, | ||||||
|  |                 function (img) { | ||||||
|  |                     node.append(img); | ||||||
|  |                     that._forceReflow(node); | ||||||
|  |                     that._transition(node).done(function () { | ||||||
|  |                         dfd.resolveWith(node); | ||||||
|  |                     }); | ||||||
|  |                     if (!$.contains(document.body, node[0])) { | ||||||
|  |                         // If the element is not part of the DOM,
 | ||||||
|  |                         // transition events are not triggered,
 | ||||||
|  |                         // so we have to resolve manually:
 | ||||||
|  |                         dfd.resolveWith(node); | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     maxWidth: options.previewMaxWidth, | ||||||
|  |                     maxHeight: options.previewMaxHeight, | ||||||
|  |                     canvas: options.previewAsCanvas | ||||||
|  |                 } | ||||||
|  |             )) || dfd.resolveWith(node)) && dfd; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _renderPreviews: function (files, nodes) { | ||||||
|  |             var that = this, | ||||||
|  |                 options = this.options; | ||||||
|  |             nodes.find('.preview span').each(function (index, element) { | ||||||
|  |                 var file = files[index]; | ||||||
|  |                 if (options.previewSourceFileTypes.test(file.type) && | ||||||
|  |                         ($.type(options.previewSourceMaxFileSize) !== 'number' || | ||||||
|  |                         file.size < options.previewSourceMaxFileSize)) { | ||||||
|  |                     that._processingQueue = that._processingQueue.pipe(function () { | ||||||
|  |                         var dfd = $.Deferred(); | ||||||
|  |                         that._renderPreview(file, $(element)).done( | ||||||
|  |                             function () { | ||||||
|  |                                 dfd.resolveWith(that); | ||||||
|  |                             } | ||||||
|  |                         ); | ||||||
|  |                         return dfd.promise(); | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |             return this._processingQueue; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _renderUpload: function (files) { | ||||||
|  |             return this._renderTemplate( | ||||||
|  |                 this.options.uploadTemplate, | ||||||
|  |                 files | ||||||
|  |             ); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _renderDownload: function (files) { | ||||||
|  |             return this._renderTemplate( | ||||||
|  |                 this.options.downloadTemplate, | ||||||
|  |                 files | ||||||
|  |             ).find('a[download]').each(this._enableDragToDesktop).end(); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _startHandler: function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             var button = $(this), | ||||||
|  |                 template = button.closest('.template-upload'), | ||||||
|  |                 data = template.data('data'); | ||||||
|  |             if (data && data.submit && !data.jqXHR && data.submit()) { | ||||||
|  |                 button.prop('disabled', true); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _cancelHandler: function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             var template = $(this).closest('.template-upload'), | ||||||
|  |                 data = template.data('data') || {}; | ||||||
|  |             if (!data.jqXHR) { | ||||||
|  |                 data.errorThrown = 'abort'; | ||||||
|  |                 e.data.fileupload._trigger('fail', e, data); | ||||||
|  |             } else { | ||||||
|  |                 data.jqXHR.abort(); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _deleteHandler: function (e) { | ||||||
|  |             e.preventDefault(); | ||||||
|  |             var button = $(this); | ||||||
|  |             e.data.fileupload._trigger('destroy', e, { | ||||||
|  |                 context: button.closest('.template-download'), | ||||||
|  |                 url: button.attr('data-url'), | ||||||
|  |                 type: button.attr('data-type') || 'DELETE', | ||||||
|  |                 dataType: e.data.fileupload.options.dataType | ||||||
|  |             }); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _forceReflow: function (node) { | ||||||
|  |             return $.support.transition && node.length && | ||||||
|  |                 node[0].offsetWidth; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _transition: function (node) { | ||||||
|  |             var dfd = $.Deferred(); | ||||||
|  |             if ($.support.transition && node.hasClass('fade')) { | ||||||
|  |                 node.bind( | ||||||
|  |                     $.support.transition.end, | ||||||
|  |                     function (e) { | ||||||
|  |                         // Make sure we don't respond to other transitions events
 | ||||||
|  |                         // in the container element, e.g. from button elements:
 | ||||||
|  |                         if (e.target === node[0]) { | ||||||
|  |                             node.unbind($.support.transition.end); | ||||||
|  |                             dfd.resolveWith(node); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 ).toggleClass('in'); | ||||||
|  |             } else { | ||||||
|  |                 node.toggleClass('in'); | ||||||
|  |                 dfd.resolveWith(node); | ||||||
|  |             } | ||||||
|  |             return dfd; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initButtonBarEventHandlers: function () { | ||||||
|  |             var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'), | ||||||
|  |                 filesList = this.options.filesContainer, | ||||||
|  |                 ns = this.options.namespace; | ||||||
|  |             fileUploadButtonBar.find('.start') | ||||||
|  |                 .bind('click.' + ns, function (e) { | ||||||
|  |                     e.preventDefault(); | ||||||
|  |                     filesList.find('.start button').click(); | ||||||
|  |                 }); | ||||||
|  |             fileUploadButtonBar.find('.cancel') | ||||||
|  |                 .bind('click.' + ns, function (e) { | ||||||
|  |                     e.preventDefault(); | ||||||
|  |                     filesList.find('.cancel button').click(); | ||||||
|  |                 }); | ||||||
|  |             fileUploadButtonBar.find('.delete') | ||||||
|  |                 .bind('click.' + ns, function (e) { | ||||||
|  |                     e.preventDefault(); | ||||||
|  |                     filesList.find('.delete input:checked') | ||||||
|  |                         .siblings('button').click(); | ||||||
|  |                     fileUploadButtonBar.find('.toggle') | ||||||
|  |                         .prop('checked', false); | ||||||
|  |                 }); | ||||||
|  |             fileUploadButtonBar.find('.toggle') | ||||||
|  |                 .bind('change.' + ns, function (e) { | ||||||
|  |                     filesList.find('.delete input').prop( | ||||||
|  |                         'checked', | ||||||
|  |                         $(this).is(':checked') | ||||||
|  |                     ); | ||||||
|  |                 }); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _destroyButtonBarEventHandlers: function () { | ||||||
|  |             this.element.find('.fileupload-buttonbar button') | ||||||
|  |                 .unbind('click.' + this.options.namespace); | ||||||
|  |             this.element.find('.fileupload-buttonbar .toggle') | ||||||
|  |                 .unbind('change.' + this.options.namespace); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initEventHandlers: function () { | ||||||
|  |             parentWidget.prototype._initEventHandlers.call(this); | ||||||
|  |             var eventData = {fileupload: this}; | ||||||
|  |             this.options.filesContainer | ||||||
|  |                 .delegate( | ||||||
|  |                     '.start button', | ||||||
|  |                     'click.' + this.options.namespace, | ||||||
|  |                     eventData, | ||||||
|  |                     this._startHandler | ||||||
|  |                 ) | ||||||
|  |                 .delegate( | ||||||
|  |                     '.cancel button', | ||||||
|  |                     'click.' + this.options.namespace, | ||||||
|  |                     eventData, | ||||||
|  |                     this._cancelHandler | ||||||
|  |                 ) | ||||||
|  |                 .delegate( | ||||||
|  |                     '.delete button', | ||||||
|  |                     'click.' + this.options.namespace, | ||||||
|  |                     eventData, | ||||||
|  |                     this._deleteHandler | ||||||
|  |                 ); | ||||||
|  |             this._initButtonBarEventHandlers(); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _destroyEventHandlers: function () { | ||||||
|  |             var options = this.options; | ||||||
|  |             this._destroyButtonBarEventHandlers(); | ||||||
|  |             options.filesContainer | ||||||
|  |                 .undelegate('.start button', 'click.' + options.namespace) | ||||||
|  |                 .undelegate('.cancel button', 'click.' + options.namespace) | ||||||
|  |                 .undelegate('.delete button', 'click.' + options.namespace); | ||||||
|  |             parentWidget.prototype._destroyEventHandlers.call(this); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _enableFileInputButton: function () { | ||||||
|  |             this.element.find('.fileinput-button input') | ||||||
|  |                 .prop('disabled', false) | ||||||
|  |                 .parent().removeClass('disabled'); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _disableFileInputButton: function () { | ||||||
|  |             this.element.find('.fileinput-button input') | ||||||
|  |                 .prop('disabled', true) | ||||||
|  |                 .parent().addClass('disabled'); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initTemplates: function () { | ||||||
|  |             var options = this.options; | ||||||
|  |             options.templatesContainer = document.createElement( | ||||||
|  |                 options.filesContainer.prop('nodeName') | ||||||
|  |             ); | ||||||
|  |             if (tmpl) { | ||||||
|  |                 if (options.uploadTemplateId) { | ||||||
|  |                     options.uploadTemplate = tmpl(options.uploadTemplateId); | ||||||
|  |                 } | ||||||
|  |                 if (options.downloadTemplateId) { | ||||||
|  |                     options.downloadTemplate = tmpl(options.downloadTemplateId); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initFilesContainer: function () { | ||||||
|  |             var options = this.options; | ||||||
|  |             if (options.filesContainer === undefined) { | ||||||
|  |                 options.filesContainer = this.element.find('.files'); | ||||||
|  |             } else if (!(options.filesContainer instanceof $)) { | ||||||
|  |                 options.filesContainer = $(options.filesContainer); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _stringToRegExp: function (str) { | ||||||
|  |             var parts = str.split('/'), | ||||||
|  |                 modifiers = parts.pop(); | ||||||
|  |             parts.shift(); | ||||||
|  |             return new RegExp(parts.join('/'), modifiers); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initRegExpOptions: function () { | ||||||
|  |             var options = this.options; | ||||||
|  |             if ($.type(options.acceptFileTypes) === 'string') { | ||||||
|  |                 options.acceptFileTypes = this._stringToRegExp( | ||||||
|  |                     options.acceptFileTypes | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             if ($.type(options.previewSourceFileTypes) === 'string') { | ||||||
|  |                 options.previewSourceFileTypes = this._stringToRegExp( | ||||||
|  |                     options.previewSourceFileTypes | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initSpecialOptions: function () { | ||||||
|  |             parentWidget.prototype._initSpecialOptions.call(this); | ||||||
|  |             this._initFilesContainer(); | ||||||
|  |             this._initTemplates(); | ||||||
|  |             this._initRegExpOptions(); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _create: function () { | ||||||
|  |             parentWidget.prototype._create.call(this); | ||||||
|  |             this._refreshOptionsList.push( | ||||||
|  |                 'filesContainer', | ||||||
|  |                 'uploadTemplateId', | ||||||
|  |                 'downloadTemplateId' | ||||||
|  |             ); | ||||||
|  |             if (!$.blueimpFP) { | ||||||
|  |                 this._processingQueue = $.Deferred().resolveWith(this).promise(); | ||||||
|  |                 this.process = function () { | ||||||
|  |                     return this._processingQueue; | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         enable: function () { | ||||||
|  |             parentWidget.prototype.enable.call(this); | ||||||
|  |             this.element.find('input, button').prop('disabled', false); | ||||||
|  |             this._enableFileInputButton(); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         disable: function () { | ||||||
|  |             this.element.find('input, button').prop('disabled', true); | ||||||
|  |             this._disableFileInputButton(); | ||||||
|  |             parentWidget.prototype.disable.call(this); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  | })); | ||||||
|  | @ -0,0 +1,975 @@ | ||||||
|  | /* | ||||||
|  |  * jQuery File Upload Plugin 5.14 | ||||||
|  |  * https://github.com/blueimp/jQuery-File-Upload
 | ||||||
|  |  * | ||||||
|  |  * Copyright 2010, Sebastian Tschan | ||||||
|  |  * https://blueimp.net
 | ||||||
|  |  * | ||||||
|  |  * Licensed under the MIT license: | ||||||
|  |  * http://www.opensource.org/licenses/MIT
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /*jslint nomen: true, unparam: true, regexp: true */ | ||||||
|  | /*global define, window, document, Blob, FormData, location */ | ||||||
|  | 
 | ||||||
|  | (function (factory) { | ||||||
|  |     'use strict'; | ||||||
|  |     if (typeof define === 'function' && define.amd) { | ||||||
|  |         // Register as an anonymous AMD module:
 | ||||||
|  |         define([ | ||||||
|  |             'jquery', | ||||||
|  |             'jquery.ui.widget' | ||||||
|  |         ], factory); | ||||||
|  |     } else { | ||||||
|  |         // Browser globals:
 | ||||||
|  |         factory(window.jQuery); | ||||||
|  |     } | ||||||
|  | }(function ($) { | ||||||
|  |     'use strict'; | ||||||
|  | 
 | ||||||
|  |     // The FileReader API is not actually used, but works as feature detection,
 | ||||||
|  |     // as e.g. Safari supports XHR file uploads via the FormData API,
 | ||||||
|  |     // but not non-multipart XHR file uploads:
 | ||||||
|  |     $.support.xhrFileUpload = !!(window.XMLHttpRequestUpload && window.FileReader); | ||||||
|  |     $.support.xhrFormDataFileUpload = !!window.FormData; | ||||||
|  | 
 | ||||||
|  |     // The fileupload widget listens for change events on file input fields defined
 | ||||||
|  |     // via fileInput setting and paste or drop events of the given dropZone.
 | ||||||
|  |     // In addition to the default jQuery Widget methods, the fileupload widget
 | ||||||
|  |     // exposes the "add" and "send" methods, to add or directly send files using
 | ||||||
|  |     // the fileupload API.
 | ||||||
|  |     // By default, files added via file input selection, paste, drag & drop or
 | ||||||
|  |     // "add" method are uploaded immediately, but it is possible to override
 | ||||||
|  |     // the "add" callback option to queue file uploads.
 | ||||||
|  |     $.widget('blueimp.fileupload', { | ||||||
|  | 
 | ||||||
|  |         options: { | ||||||
|  |             // The namespace used for event handler binding on the dropZone and
 | ||||||
|  |             // fileInput collections.
 | ||||||
|  |             // If not set, the name of the widget ("fileupload") is used.
 | ||||||
|  |             namespace: undefined, | ||||||
|  |             // The drop target collection, by the default the complete document.
 | ||||||
|  |             // Set to null or an empty collection to disable drag & drop support:
 | ||||||
|  |             dropZone: $(document), | ||||||
|  |             // The file input field collection, that is listened for change events.
 | ||||||
|  |             // If undefined, it is set to the file input fields inside
 | ||||||
|  |             // of the widget element on plugin initialization.
 | ||||||
|  |             // Set to null or an empty collection to disable the change listener.
 | ||||||
|  |             fileInput: undefined, | ||||||
|  |             // By default, the file input field is replaced with a clone after
 | ||||||
|  |             // each input field change event. This is required for iframe transport
 | ||||||
|  |             // queues and allows change events to be fired for the same file
 | ||||||
|  |             // selection, but can be disabled by setting the following option to false:
 | ||||||
|  |             replaceFileInput: true, | ||||||
|  |             // The parameter name for the file form data (the request argument name).
 | ||||||
|  |             // If undefined or empty, the name property of the file input field is
 | ||||||
|  |             // used, or "files[]" if the file input name property is also empty,
 | ||||||
|  |             // can be a string or an array of strings:
 | ||||||
|  |             paramName: undefined, | ||||||
|  |             // By default, each file of a selection is uploaded using an individual
 | ||||||
|  |             // request for XHR type uploads. Set to false to upload file
 | ||||||
|  |             // selections in one request each:
 | ||||||
|  |             singleFileUploads: true, | ||||||
|  |             // To limit the number of files uploaded with one XHR request,
 | ||||||
|  |             // set the following option to an integer greater than 0:
 | ||||||
|  |             limitMultiFileUploads: undefined, | ||||||
|  |             // Set the following option to true to issue all file upload requests
 | ||||||
|  |             // in a sequential order:
 | ||||||
|  |             sequentialUploads: false, | ||||||
|  |             // To limit the number of concurrent uploads,
 | ||||||
|  |             // set the following option to an integer greater than 0:
 | ||||||
|  |             limitConcurrentUploads: undefined, | ||||||
|  |             // Set the following option to true to force iframe transport uploads:
 | ||||||
|  |             forceIframeTransport: false, | ||||||
|  |             // Set the following option to the location of a redirect url on the
 | ||||||
|  |             // origin server, for cross-domain iframe transport uploads:
 | ||||||
|  |             redirect: undefined, | ||||||
|  |             // The parameter name for the redirect url, sent as part of the form
 | ||||||
|  |             // data and set to 'redirect' if this option is empty:
 | ||||||
|  |             redirectParamName: undefined, | ||||||
|  |             // Set the following option to the location of a postMessage window,
 | ||||||
|  |             // to enable postMessage transport uploads:
 | ||||||
|  |             postMessage: undefined, | ||||||
|  |             // By default, XHR file uploads are sent as multipart/form-data.
 | ||||||
|  |             // The iframe transport is always using multipart/form-data.
 | ||||||
|  |             // Set to false to enable non-multipart XHR uploads:
 | ||||||
|  |             multipart: true, | ||||||
|  |             // To upload large files in smaller chunks, set the following option
 | ||||||
|  |             // to a preferred maximum chunk size. If set to 0, null or undefined,
 | ||||||
|  |             // or the browser does not support the required Blob API, files will
 | ||||||
|  |             // be uploaded as a whole.
 | ||||||
|  |             maxChunkSize: undefined, | ||||||
|  |             // When a non-multipart upload or a chunked multipart upload has been
 | ||||||
|  |             // aborted, this option can be used to resume the upload by setting
 | ||||||
|  |             // it to the size of the already uploaded bytes. This option is most
 | ||||||
|  |             // useful when modifying the options object inside of the "add" or
 | ||||||
|  |             // "send" callbacks, as the options are cloned for each file upload.
 | ||||||
|  |             uploadedBytes: undefined, | ||||||
|  |             // By default, failed (abort or error) file uploads are removed from the
 | ||||||
|  |             // global progress calculation. Set the following option to false to
 | ||||||
|  |             // prevent recalculating the global progress data:
 | ||||||
|  |             recalculateProgress: true, | ||||||
|  |             // Interval in milliseconds to calculate and trigger progress events:
 | ||||||
|  |             progressInterval: 100, | ||||||
|  |             // Interval in milliseconds to calculate progress bitrate:
 | ||||||
|  |             bitrateInterval: 500, | ||||||
|  | 
 | ||||||
|  |             // Additional form data to be sent along with the file uploads can be set
 | ||||||
|  |             // using this option, which accepts an array of objects with name and
 | ||||||
|  |             // value properties, a function returning such an array, a FormData
 | ||||||
|  |             // object (for XHR file uploads), or a simple object.
 | ||||||
|  |             // The form of the first fileInput is given as parameter to the function:
 | ||||||
|  |             formData: function (form) { | ||||||
|  |                 return form.serializeArray(); | ||||||
|  |             }, | ||||||
|  | 
 | ||||||
|  |             // The add callback is invoked as soon as files are added to the fileupload
 | ||||||
|  |             // widget (via file input selection, drag & drop, paste or add API call).
 | ||||||
|  |             // If the singleFileUploads option is enabled, this callback will be
 | ||||||
|  |             // called once for each file in the selection for XHR file uplaods, else
 | ||||||
|  |             // once for each file selection.
 | ||||||
|  |             // The upload starts when the submit method is invoked on the data parameter.
 | ||||||
|  |             // The data object contains a files property holding the added files
 | ||||||
|  |             // and allows to override plugin options as well as define ajax settings.
 | ||||||
|  |             // Listeners for this callback can also be bound the following way:
 | ||||||
|  |             // .bind('fileuploadadd', func);
 | ||||||
|  |             // data.submit() returns a Promise object and allows to attach additional
 | ||||||
|  |             // handlers using jQuery's Deferred callbacks:
 | ||||||
|  |             // data.submit().done(func).fail(func).always(func);
 | ||||||
|  |             add: function (e, data) { | ||||||
|  |                 data.submit(); | ||||||
|  |             }, | ||||||
|  | 
 | ||||||
|  |             // Other callbacks:
 | ||||||
|  |             // Callback for the submit event of each file upload:
 | ||||||
|  |             // submit: function (e, data) {}, // .bind('fileuploadsubmit', func);
 | ||||||
|  |             // Callback for the start of each file upload request:
 | ||||||
|  |             // send: function (e, data) {}, // .bind('fileuploadsend', func);
 | ||||||
|  |             // Callback for successful uploads:
 | ||||||
|  |             // done: function (e, data) {}, // .bind('fileuploaddone', func);
 | ||||||
|  |             // Callback for failed (abort or error) uploads:
 | ||||||
|  |             // fail: function (e, data) {}, // .bind('fileuploadfail', func);
 | ||||||
|  |             // Callback for completed (success, abort or error) requests:
 | ||||||
|  |             // always: function (e, data) {}, // .bind('fileuploadalways', func);
 | ||||||
|  |             // Callback for upload progress events:
 | ||||||
|  |             // progress: function (e, data) {}, // .bind('fileuploadprogress', func);
 | ||||||
|  |             // Callback for global upload progress events:
 | ||||||
|  |             // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func);
 | ||||||
|  |             // Callback for uploads start, equivalent to the global ajaxStart event:
 | ||||||
|  |             // start: function (e) {}, // .bind('fileuploadstart', func);
 | ||||||
|  |             // Callback for uploads stop, equivalent to the global ajaxStop event:
 | ||||||
|  |             // stop: function (e) {}, // .bind('fileuploadstop', func);
 | ||||||
|  |             // Callback for change events of the fileInput collection:
 | ||||||
|  |             // change: function (e, data) {}, // .bind('fileuploadchange', func);
 | ||||||
|  |             // Callback for paste events to the dropZone collection:
 | ||||||
|  |             // paste: function (e, data) {}, // .bind('fileuploadpaste', func);
 | ||||||
|  |             // Callback for drop events of the dropZone collection:
 | ||||||
|  |             // drop: function (e, data) {}, // .bind('fileuploaddrop', func);
 | ||||||
|  |             // Callback for dragover events of the dropZone collection:
 | ||||||
|  |             // dragover: function (e) {}, // .bind('fileuploaddragover', func);
 | ||||||
|  | 
 | ||||||
|  |             // The plugin options are used as settings object for the ajax calls.
 | ||||||
|  |             // The following are jQuery ajax settings required for the file uploads:
 | ||||||
|  |             processData: false, | ||||||
|  |             contentType: false, | ||||||
|  |             cache: false | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         // A list of options that require a refresh after assigning a new value:
 | ||||||
|  |         _refreshOptionsList: [ | ||||||
|  |             'namespace', | ||||||
|  |             'dropZone', | ||||||
|  |             'fileInput', | ||||||
|  |             'multipart', | ||||||
|  |             'forceIframeTransport' | ||||||
|  |         ], | ||||||
|  | 
 | ||||||
|  |         _BitrateTimer: function () { | ||||||
|  |             this.timestamp = +(new Date()); | ||||||
|  |             this.loaded = 0; | ||||||
|  |             this.bitrate = 0; | ||||||
|  |             this.getBitrate = function (now, loaded, interval) { | ||||||
|  |                 var timeDiff = now - this.timestamp; | ||||||
|  |                 if (!this.bitrate || !interval || timeDiff > interval) { | ||||||
|  |                     this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8; | ||||||
|  |                     this.loaded = loaded; | ||||||
|  |                     this.timestamp = now; | ||||||
|  |                 } | ||||||
|  |                 return this.bitrate; | ||||||
|  |             }; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _isXHRUpload: function (options) { | ||||||
|  |             return !options.forceIframeTransport && | ||||||
|  |                 ((!options.multipart && $.support.xhrFileUpload) || | ||||||
|  |                 $.support.xhrFormDataFileUpload); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _getFormData: function (options) { | ||||||
|  |             var formData; | ||||||
|  |             if (typeof options.formData === 'function') { | ||||||
|  |                 return options.formData(options.form); | ||||||
|  |             } | ||||||
|  | 			if ($.isArray(options.formData)) { | ||||||
|  |                 return options.formData; | ||||||
|  |             } | ||||||
|  | 			if (options.formData) { | ||||||
|  |                 formData = []; | ||||||
|  |                 $.each(options.formData, function (name, value) { | ||||||
|  |                     formData.push({name: name, value: value}); | ||||||
|  |                 }); | ||||||
|  |                 return formData; | ||||||
|  |             } | ||||||
|  |             return []; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _getTotal: function (files) { | ||||||
|  |             var total = 0; | ||||||
|  |             $.each(files, function (index, file) { | ||||||
|  |                 total += file.size || 1; | ||||||
|  |             }); | ||||||
|  |             return total; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _onProgress: function (e, data) { | ||||||
|  |             if (e.lengthComputable) { | ||||||
|  |                 var now = +(new Date()), | ||||||
|  |                     total, | ||||||
|  |                     loaded; | ||||||
|  |                 if (data._time && data.progressInterval && | ||||||
|  |                         (now - data._time < data.progressInterval) && | ||||||
|  |                         e.loaded !== e.total) { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                 data._time = now; | ||||||
|  |                 total = data.total || this._getTotal(data.files); | ||||||
|  |                 loaded = parseInt( | ||||||
|  |                     e.loaded / e.total * (data.chunkSize || total), | ||||||
|  |                     10 | ||||||
|  |                 ) + (data.uploadedBytes || 0); | ||||||
|  |                 this._loaded += loaded - (data.loaded || data.uploadedBytes || 0); | ||||||
|  |                 data.lengthComputable = true; | ||||||
|  |                 data.loaded = loaded; | ||||||
|  |                 data.total = total; | ||||||
|  |                 data.bitrate = data._bitrateTimer.getBitrate( | ||||||
|  |                     now, | ||||||
|  |                     loaded, | ||||||
|  |                     data.bitrateInterval | ||||||
|  |                 ); | ||||||
|  |                 // Trigger a custom progress event with a total data property set
 | ||||||
|  |                 // to the file size(s) of the current upload and a loaded data
 | ||||||
|  |                 // property calculated accordingly:
 | ||||||
|  |                 this._trigger('progress', e, data); | ||||||
|  |                 // Trigger a global progress event for all current file uploads,
 | ||||||
|  |                 // including ajax calls queued for sequential file uploads:
 | ||||||
|  |                 this._trigger('progressall', e, { | ||||||
|  |                     lengthComputable: true, | ||||||
|  |                     loaded: this._loaded, | ||||||
|  |                     total: this._total, | ||||||
|  |                     bitrate: this._bitrateTimer.getBitrate( | ||||||
|  |                         now, | ||||||
|  |                         this._loaded, | ||||||
|  |                         data.bitrateInterval | ||||||
|  |                     ) | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initProgressListener: function (options) { | ||||||
|  |             var that = this, | ||||||
|  |                 xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); | ||||||
|  |             // Accesss to the native XHR object is required to add event listeners
 | ||||||
|  |             // for the upload progress event:
 | ||||||
|  |             if (xhr.upload) { | ||||||
|  |                 $(xhr.upload).bind('progress', function (e) { | ||||||
|  |                     var oe = e.originalEvent; | ||||||
|  |                     // Make sure the progress event properties get copied over:
 | ||||||
|  |                     e.lengthComputable = oe.lengthComputable; | ||||||
|  |                     e.loaded = oe.loaded; | ||||||
|  |                     e.total = oe.total; | ||||||
|  |                     that._onProgress(e, options); | ||||||
|  |                 }); | ||||||
|  |                 options.xhr = function () { | ||||||
|  |                     return xhr; | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initXHRData: function (options) { | ||||||
|  |             var formData, | ||||||
|  |                 file = options.files[0], | ||||||
|  |                 // Ignore non-multipart setting if not supported:
 | ||||||
|  |                 multipart = options.multipart || !$.support.xhrFileUpload, | ||||||
|  |                 paramName = options.paramName[0]; | ||||||
|  |             if (!multipart || options.blob) { | ||||||
|  |                 // For non-multipart uploads and chunked uploads,
 | ||||||
|  |                 // file meta data is not part of the request body,
 | ||||||
|  |                 // so we transmit this data as part of the HTTP headers.
 | ||||||
|  |                 // For cross domain requests, these headers must be allowed
 | ||||||
|  |                 // via Access-Control-Allow-Headers or removed using
 | ||||||
|  |                 // the beforeSend callback:
 | ||||||
|  |                 options.headers = $.extend(options.headers, { | ||||||
|  |                     'X-File-Name': file.name, | ||||||
|  |                     'X-File-Type': file.type, | ||||||
|  |                     'X-File-Size': file.size | ||||||
|  |                 }); | ||||||
|  |                 if (!options.blob) { | ||||||
|  |                     // Non-chunked non-multipart upload:
 | ||||||
|  |                     options.contentType = file.type; | ||||||
|  |                     options.data = file; | ||||||
|  |                 } else if (!multipart) { | ||||||
|  |                     // Chunked non-multipart upload:
 | ||||||
|  |                     options.contentType = 'application/octet-stream'; | ||||||
|  |                     options.data = options.blob; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if (multipart && $.support.xhrFormDataFileUpload) { | ||||||
|  |                 if (options.postMessage) { | ||||||
|  |                     // window.postMessage does not allow sending FormData
 | ||||||
|  |                     // objects, so we just add the File/Blob objects to
 | ||||||
|  |                     // the formData array and let the postMessage window
 | ||||||
|  |                     // create the FormData object out of this array:
 | ||||||
|  |                     formData = this._getFormData(options); | ||||||
|  |                     if (options.blob) { | ||||||
|  |                         formData.push({ | ||||||
|  |                             name: paramName, | ||||||
|  |                             value: options.blob | ||||||
|  |                         }); | ||||||
|  |                     } else { | ||||||
|  |                         $.each(options.files, function (index, file) { | ||||||
|  |                             formData.push({ | ||||||
|  |                                 name: options.paramName[index] || paramName, | ||||||
|  |                                 value: file | ||||||
|  |                             }); | ||||||
|  |                         }); | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     if (options.formData instanceof FormData) { | ||||||
|  |                         formData = options.formData; | ||||||
|  |                     } else { | ||||||
|  |                         formData = new FormData(); | ||||||
|  |                         $.each(this._getFormData(options), function (index, field) { | ||||||
|  |                             formData.append(field.name, field.value); | ||||||
|  |                         }); | ||||||
|  |                     } | ||||||
|  |                     if (options.blob) { | ||||||
|  |                         formData.append(paramName, options.blob, file.name); | ||||||
|  |                     } else { | ||||||
|  |                         $.each(options.files, function (index, file) { | ||||||
|  |                             // File objects are also Blob instances.
 | ||||||
|  |                             // This check allows the tests to run with
 | ||||||
|  |                             // dummy objects:
 | ||||||
|  |                             if (file instanceof Blob) { | ||||||
|  |                                 formData.append( | ||||||
|  |                                     options.paramName[index] || paramName, | ||||||
|  |                                     file, | ||||||
|  |                                     file.name | ||||||
|  |                                 ); | ||||||
|  |                             } | ||||||
|  |                         }); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 options.data = formData; | ||||||
|  |             } | ||||||
|  |             // Blob reference is not needed anymore, free memory:
 | ||||||
|  |             options.blob = null; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initIframeSettings: function (options) { | ||||||
|  |             // Setting the dataType to iframe enables the iframe transport:
 | ||||||
|  |             options.dataType = 'iframe ' + (options.dataType || ''); | ||||||
|  |             // The iframe transport accepts a serialized array as form data:
 | ||||||
|  |             options.formData = this._getFormData(options); | ||||||
|  |             // Add redirect url to form data on cross-domain uploads:
 | ||||||
|  |             if (options.redirect && $('<a></a>').prop('href', options.url) | ||||||
|  |                     .prop('host') !== location.host) { | ||||||
|  |                 options.formData.push({ | ||||||
|  |                     name: options.redirectParamName || 'redirect', | ||||||
|  |                     value: options.redirect | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initDataSettings: function (options) { | ||||||
|  |             if (this._isXHRUpload(options)) { | ||||||
|  |                 if (!this._chunkedUpload(options, true)) { | ||||||
|  |                     if (!options.data) { | ||||||
|  |                         this._initXHRData(options); | ||||||
|  |                     } | ||||||
|  |                     this._initProgressListener(options); | ||||||
|  |                 } | ||||||
|  |                 if (options.postMessage) { | ||||||
|  |                     // Setting the dataType to postmessage enables the
 | ||||||
|  |                     // postMessage transport:
 | ||||||
|  |                     options.dataType = 'postmessage ' + (options.dataType || ''); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 this._initIframeSettings(options, 'iframe'); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _getParamName: function (options) { | ||||||
|  |             var fileInput = $(options.fileInput), | ||||||
|  |                 paramName = options.paramName; | ||||||
|  |             if (!paramName) { | ||||||
|  |                 paramName = []; | ||||||
|  |                 fileInput.each(function () { | ||||||
|  |                     var input = $(this), | ||||||
|  |                         name = input.prop('name') || 'files[]', | ||||||
|  |                         i = (input.prop('files') || [1]).length; | ||||||
|  |                     while (i) { | ||||||
|  |                         paramName.push(name); | ||||||
|  |                         i -= 1; | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |                 if (!paramName.length) { | ||||||
|  |                     paramName = [fileInput.prop('name') || 'files[]']; | ||||||
|  |                 } | ||||||
|  |             } else if (!$.isArray(paramName)) { | ||||||
|  |                 paramName = [paramName]; | ||||||
|  |             } | ||||||
|  |             return paramName; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initFormSettings: function (options) { | ||||||
|  |             // Retrieve missing options from the input field and the
 | ||||||
|  |             // associated form, if available:
 | ||||||
|  |             if (!options.form || !options.form.length) { | ||||||
|  |                 options.form = $(options.fileInput.prop('form')); | ||||||
|  |             } | ||||||
|  |             options.paramName = this._getParamName(options); | ||||||
|  |             if (!options.url) { | ||||||
|  |                 options.url = options.form.prop('action') || location.href; | ||||||
|  |             } | ||||||
|  |             // The HTTP request method must be "POST" or "PUT":
 | ||||||
|  |             options.type = (options.type || options.form.prop('method') || '') | ||||||
|  |                 .toUpperCase(); | ||||||
|  |             if (options.type !== 'POST' && options.type !== 'PUT') { | ||||||
|  |                 options.type = 'POST'; | ||||||
|  |             } | ||||||
|  |             if (!options.formAcceptCharset) { | ||||||
|  |                 options.formAcceptCharset = options.form.attr('accept-charset'); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _getAJAXSettings: function (data) { | ||||||
|  |             var options = $.extend({}, this.options, data); | ||||||
|  |             this._initFormSettings(options); | ||||||
|  |             this._initDataSettings(options); | ||||||
|  |             return options; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         // Maps jqXHR callbacks to the equivalent
 | ||||||
|  |         // methods of the given Promise object:
 | ||||||
|  |         _enhancePromise: function (promise) { | ||||||
|  |             promise.success = promise.done; | ||||||
|  |             promise.error = promise.fail; | ||||||
|  |             promise.complete = promise.always; | ||||||
|  |             return promise; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         // Creates and returns a Promise object enhanced with
 | ||||||
|  |         // the jqXHR methods abort, success, error and complete:
 | ||||||
|  |         _getXHRPromise: function (resolveOrReject, context, args) { | ||||||
|  |             var dfd = $.Deferred(), | ||||||
|  |                 promise = dfd.promise(); | ||||||
|  |             context = context || this.options.context || promise; | ||||||
|  |             if (resolveOrReject === true) { | ||||||
|  |                 dfd.resolveWith(context, args); | ||||||
|  |             } else if (resolveOrReject === false) { | ||||||
|  |                 dfd.rejectWith(context, args); | ||||||
|  |             } | ||||||
|  |             promise.abort = dfd.promise; | ||||||
|  |             return this._enhancePromise(promise); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         // Uploads a file in multiple, sequential requests
 | ||||||
|  |         // by splitting the file up in multiple blob chunks.
 | ||||||
|  |         // If the second parameter is true, only tests if the file
 | ||||||
|  |         // should be uploaded in chunks, but does not invoke any
 | ||||||
|  |         // upload requests:
 | ||||||
|  |         _chunkedUpload: function (options, testOnly) { | ||||||
|  |             var that = this, | ||||||
|  |                 file = options.files[0], | ||||||
|  |                 fs = file.size, | ||||||
|  |                 ub = options.uploadedBytes = options.uploadedBytes || 0, | ||||||
|  |                 mcs = options.maxChunkSize || fs, | ||||||
|  |                 // Use the Blob methods with the slice implementation
 | ||||||
|  |                 // according to the W3C Blob API specification:
 | ||||||
|  |                 slice = file.webkitSlice || file.mozSlice || file.slice, | ||||||
|  |                 upload, | ||||||
|  |                 n, | ||||||
|  |                 jqXHR, | ||||||
|  |                 pipe; | ||||||
|  |             if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) || | ||||||
|  |                     options.data) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             if (testOnly) { | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             if (ub >= fs) { | ||||||
|  |                 file.error = 'uploadedBytes'; | ||||||
|  |                 return this._getXHRPromise( | ||||||
|  |                     false, | ||||||
|  |                     options.context, | ||||||
|  |                     [null, 'error', file.error] | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             // n is the number of blobs to upload,
 | ||||||
|  |             // calculated via filesize, uploaded bytes and max chunk size:
 | ||||||
|  |             n = Math.ceil((fs - ub) / mcs); | ||||||
|  |             // The chunk upload method accepting the chunk number as parameter:
 | ||||||
|  |             upload = function (i) { | ||||||
|  |                 if (!i) { | ||||||
|  |                     return that._getXHRPromise(true, options.context); | ||||||
|  |                 } | ||||||
|  |                 // Upload the blobs in sequential order:
 | ||||||
|  |                 return upload(i -= 1).pipe(function () { | ||||||
|  |                     // Clone the options object for each chunk upload:
 | ||||||
|  |                     var o = $.extend({}, options); | ||||||
|  |                     o.blob = slice.call( | ||||||
|  |                         file, | ||||||
|  |                         ub + i * mcs, | ||||||
|  |                         ub + (i + 1) * mcs | ||||||
|  |                     ); | ||||||
|  |                     // Expose the chunk index:
 | ||||||
|  |                     o.chunkIndex = i; | ||||||
|  |                     // Expose the number of chunks:
 | ||||||
|  |                     o.chunksNumber = n; | ||||||
|  |                     // Store the current chunk size, as the blob itself
 | ||||||
|  |                     // will be dereferenced after data processing:
 | ||||||
|  |                     o.chunkSize = o.blob.size; | ||||||
|  |                     // Process the upload data (the blob and potential form data):
 | ||||||
|  |                     that._initXHRData(o); | ||||||
|  |                     // Add progress listeners for this chunk upload:
 | ||||||
|  |                     that._initProgressListener(o); | ||||||
|  |                     jqXHR = ($.ajax(o) || that._getXHRPromise(false, o.context)) | ||||||
|  |                         .done(function () { | ||||||
|  |                             // Create a progress event if upload is done and
 | ||||||
|  |                             // no progress event has been invoked for this chunk:
 | ||||||
|  |                             if (!o.loaded) { | ||||||
|  |                                 that._onProgress($.Event('progress', { | ||||||
|  |                                     lengthComputable: true, | ||||||
|  |                                     loaded: o.chunkSize, | ||||||
|  |                                     total: o.chunkSize | ||||||
|  |                                 }), o); | ||||||
|  |                             } | ||||||
|  |                             options.uploadedBytes = o.uploadedBytes += | ||||||
|  |                                 o.chunkSize; | ||||||
|  |                         }); | ||||||
|  |                     return jqXHR; | ||||||
|  |                 }); | ||||||
|  |             }; | ||||||
|  |             // Return the piped Promise object, enhanced with an abort method,
 | ||||||
|  |             // which is delegated to the jqXHR object of the current upload,
 | ||||||
|  |             // and jqXHR callbacks mapped to the equivalent Promise methods:
 | ||||||
|  |             pipe = upload(n); | ||||||
|  |             pipe.abort = function () { | ||||||
|  |                 return jqXHR.abort(); | ||||||
|  |             }; | ||||||
|  |             return this._enhancePromise(pipe); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _beforeSend: function (e, data) { | ||||||
|  |             if (this._active === 0) { | ||||||
|  |                 // the start callback is triggered when an upload starts
 | ||||||
|  |                 // and no other uploads are currently running,
 | ||||||
|  |                 // equivalent to the global ajaxStart event:
 | ||||||
|  |                 this._trigger('start'); | ||||||
|  |                 // Set timer for global bitrate progress calculation:
 | ||||||
|  |                 this._bitrateTimer = new this._BitrateTimer(); | ||||||
|  |             } | ||||||
|  |             this._active += 1; | ||||||
|  |             // Initialize the global progress values:
 | ||||||
|  |             this._loaded += data.uploadedBytes || 0; | ||||||
|  |             this._total += this._getTotal(data.files); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _onDone: function (result, textStatus, jqXHR, options) { | ||||||
|  |             if (!this._isXHRUpload(options)) { | ||||||
|  |                 // Create a progress event for each iframe load:
 | ||||||
|  |                 this._onProgress($.Event('progress', { | ||||||
|  |                     lengthComputable: true, | ||||||
|  |                     loaded: 1, | ||||||
|  |                     total: 1 | ||||||
|  |                 }), options); | ||||||
|  |             } | ||||||
|  |             options.result = result; | ||||||
|  |             options.textStatus = textStatus; | ||||||
|  |             options.jqXHR = jqXHR; | ||||||
|  |             this._trigger('done', null, options); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _onFail: function (jqXHR, textStatus, errorThrown, options) { | ||||||
|  |             options.jqXHR = jqXHR; | ||||||
|  |             options.textStatus = textStatus; | ||||||
|  |             options.errorThrown = errorThrown; | ||||||
|  |             this._trigger('fail', null, options); | ||||||
|  |             if (options.recalculateProgress) { | ||||||
|  |                 // Remove the failed (error or abort) file upload from
 | ||||||
|  |                 // the global progress calculation:
 | ||||||
|  |                 this._loaded -= options.loaded || options.uploadedBytes || 0; | ||||||
|  |                 this._total -= options.total || this._getTotal(options.files); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) { | ||||||
|  |             this._active -= 1; | ||||||
|  |             options.textStatus = textStatus; | ||||||
|  |             if (jqXHRorError && jqXHRorError.always) { | ||||||
|  |                 options.jqXHR = jqXHRorError; | ||||||
|  |                 options.result = jqXHRorResult; | ||||||
|  |             } else { | ||||||
|  |                 options.jqXHR = jqXHRorResult; | ||||||
|  |                 options.errorThrown = jqXHRorError; | ||||||
|  |             } | ||||||
|  |             this._trigger('always', null, options); | ||||||
|  |             if (this._active === 0) { | ||||||
|  |                 // The stop callback is triggered when all uploads have
 | ||||||
|  |                 // been completed, equivalent to the global ajaxStop event:
 | ||||||
|  |                 this._trigger('stop'); | ||||||
|  |                 // Reset the global progress values:
 | ||||||
|  |                 this._loaded = this._total = 0; | ||||||
|  |                 this._bitrateTimer = null; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _onSend: function (e, data) { | ||||||
|  |             var that = this, | ||||||
|  |                 jqXHR, | ||||||
|  |                 slot, | ||||||
|  |                 pipe, | ||||||
|  |                 options = that._getAJAXSettings(data), | ||||||
|  |                 send = function (resolve, args) { | ||||||
|  |                     that._sending += 1; | ||||||
|  |                     // Set timer for bitrate progress calculation:
 | ||||||
|  |                     options._bitrateTimer = new that._BitrateTimer(); | ||||||
|  |                     jqXHR = jqXHR || ( | ||||||
|  |                         (resolve !== false && | ||||||
|  |                         that._trigger('send', e, options) !== false && | ||||||
|  |                         (that._chunkedUpload(options) || $.ajax(options))) || | ||||||
|  |                         that._getXHRPromise(false, options.context, args) | ||||||
|  |                     ).done(function (result, textStatus, jqXHR) { | ||||||
|  |                         that._onDone(result, textStatus, jqXHR, options); | ||||||
|  |                     }).fail(function (jqXHR, textStatus, errorThrown) { | ||||||
|  |                         that._onFail(jqXHR, textStatus, errorThrown, options); | ||||||
|  |                     }).always(function (jqXHRorResult, textStatus, jqXHRorError) { | ||||||
|  |                         that._sending -= 1; | ||||||
|  |                         that._onAlways( | ||||||
|  |                             jqXHRorResult, | ||||||
|  |                             textStatus, | ||||||
|  |                             jqXHRorError, | ||||||
|  |                             options | ||||||
|  |                         ); | ||||||
|  |                         if (options.limitConcurrentUploads && | ||||||
|  |                                 options.limitConcurrentUploads > that._sending) { | ||||||
|  |                             // Start the next queued upload,
 | ||||||
|  |                             // that has not been aborted:
 | ||||||
|  |                             var nextSlot = that._slots.shift(); | ||||||
|  |                             while (nextSlot) { | ||||||
|  |                                 if (!nextSlot.isRejected()) { | ||||||
|  |                                     nextSlot.resolve(); | ||||||
|  |                                     break; | ||||||
|  |                                 } | ||||||
|  |                                 nextSlot = that._slots.shift(); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     }); | ||||||
|  |                     return jqXHR; | ||||||
|  |                 }; | ||||||
|  |             this._beforeSend(e, options); | ||||||
|  |             if (this.options.sequentialUploads || | ||||||
|  |                     (this.options.limitConcurrentUploads && | ||||||
|  |                     this.options.limitConcurrentUploads <= this._sending)) { | ||||||
|  |                 if (this.options.limitConcurrentUploads > 1) { | ||||||
|  |                     slot = $.Deferred(); | ||||||
|  |                     this._slots.push(slot); | ||||||
|  |                     pipe = slot.pipe(send); | ||||||
|  |                 } else { | ||||||
|  |                     pipe = (this._sequence = this._sequence.pipe(send, send)); | ||||||
|  |                 } | ||||||
|  |                 // Return the piped Promise object, enhanced with an abort method,
 | ||||||
|  |                 // which is delegated to the jqXHR object of the current upload,
 | ||||||
|  |                 // and jqXHR callbacks mapped to the equivalent Promise methods:
 | ||||||
|  |                 pipe.abort = function () { | ||||||
|  |                     var args = [undefined, 'abort', 'abort']; | ||||||
|  |                     if (!jqXHR) { | ||||||
|  |                         if (slot) { | ||||||
|  |                             slot.rejectWith(args); | ||||||
|  |                         } | ||||||
|  |                         return send(false, args); | ||||||
|  |                     } | ||||||
|  |                     return jqXHR.abort(); | ||||||
|  |                 }; | ||||||
|  |                 return this._enhancePromise(pipe); | ||||||
|  |             } | ||||||
|  |             return send(); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _onAdd: function (e, data) { | ||||||
|  |             var that = this, | ||||||
|  |                 result = true, | ||||||
|  |                 options = $.extend({}, this.options, data), | ||||||
|  |                 limit = options.limitMultiFileUploads, | ||||||
|  |                 paramName = this._getParamName(options), | ||||||
|  |                 paramNameSet, | ||||||
|  |                 paramNameSlice, | ||||||
|  |                 fileSet, | ||||||
|  |                 i; | ||||||
|  |             if (!(options.singleFileUploads || limit) || | ||||||
|  |                     !this._isXHRUpload(options)) { | ||||||
|  |                 fileSet = [data.files]; | ||||||
|  |                 paramNameSet = [paramName]; | ||||||
|  |             } else if (!options.singleFileUploads && limit) { | ||||||
|  |                 fileSet = []; | ||||||
|  |                 paramNameSet = []; | ||||||
|  |                 for (i = 0; i < data.files.length; i += limit) { | ||||||
|  |                     fileSet.push(data.files.slice(i, i + limit)); | ||||||
|  |                     paramNameSlice = paramName.slice(i, i + limit); | ||||||
|  |                     if (!paramNameSlice.length) { | ||||||
|  |                         paramNameSlice = paramName; | ||||||
|  |                     } | ||||||
|  |                     paramNameSet.push(paramNameSlice); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 paramNameSet = paramName; | ||||||
|  |             } | ||||||
|  |             data.originalFiles = data.files; | ||||||
|  |             $.each(fileSet || data.files, function (index, element) { | ||||||
|  |                 var newData = $.extend({}, data); | ||||||
|  |                 newData.files = fileSet ? element : [element]; | ||||||
|  |                 newData.paramName = paramNameSet[index]; | ||||||
|  |                 newData.submit = function () { | ||||||
|  |                     newData.jqXHR = this.jqXHR = | ||||||
|  |                         (that._trigger('submit', e, this) !== false) && | ||||||
|  |                         that._onSend(e, this); | ||||||
|  |                     return this.jqXHR; | ||||||
|  |                 }; | ||||||
|  |                 return (result = that._trigger('add', e, newData)); | ||||||
|  |             }); | ||||||
|  |             return result; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         // File Normalization for Gecko 1.9.1 (Firefox 3.5) support:
 | ||||||
|  |         _normalizeFile: function (index, file) { | ||||||
|  |             if (file.name === undefined && file.size === undefined) { | ||||||
|  |                 file.name = file.fileName; | ||||||
|  |                 file.size = file.fileSize; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _replaceFileInput: function (input) { | ||||||
|  |             var inputClone = input.clone(true); | ||||||
|  |             $('<form></form>').append(inputClone)[0].reset(); | ||||||
|  |             // Detaching allows to insert the fileInput on another form
 | ||||||
|  |             // without loosing the file input value:
 | ||||||
|  |             input.after(inputClone).detach(); | ||||||
|  |             // Avoid memory leaks with the detached file input:
 | ||||||
|  |             $.cleanData(input.unbind('remove')); | ||||||
|  |             // Replace the original file input element in the fileInput
 | ||||||
|  |             // collection with the clone, which has been copied including
 | ||||||
|  |             // event handlers:
 | ||||||
|  |             this.options.fileInput = this.options.fileInput.map(function (i, el) { | ||||||
|  |                 if (el === input[0]) { | ||||||
|  |                     return inputClone[0]; | ||||||
|  |                 } | ||||||
|  |                 return el; | ||||||
|  |             }); | ||||||
|  |             // If the widget has been initialized on the file input itself,
 | ||||||
|  |             // override this.element with the file input clone:
 | ||||||
|  |             if (input[0] === this.element[0]) { | ||||||
|  |                 this.element = inputClone; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _getFileInputFiles: function (fileInput) { | ||||||
|  |             fileInput = $(fileInput); | ||||||
|  |             var files = $.each($.makeArray(fileInput.prop('files')), this._normalizeFile), | ||||||
|  |                 value; | ||||||
|  |             if (!files.length) { | ||||||
|  |                 value = fileInput.prop('value'); | ||||||
|  |                 if (!value) { | ||||||
|  |                     return []; | ||||||
|  |                 } | ||||||
|  |                 // If the files property is not available, the browser does not
 | ||||||
|  |                 // support the File API and we add a pseudo File object with
 | ||||||
|  |                 // the input value as name with path information removed:
 | ||||||
|  |                 files = [{name: value.replace(/^.*\\/, '')}]; | ||||||
|  |             } | ||||||
|  |             return files; | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _onChange: function (e) { | ||||||
|  |             var that = e.data.fileupload, | ||||||
|  |                 data = { | ||||||
|  |                     fileInput: $(e.target), | ||||||
|  |                     form: $(e.target.form) | ||||||
|  |                 }; | ||||||
|  |             data.files = that._getFileInputFiles(data.fileInput); | ||||||
|  |             if (that.options.replaceFileInput) { | ||||||
|  |                 that._replaceFileInput(data.fileInput); | ||||||
|  |             } | ||||||
|  |             if (that._trigger('change', e, data) === false || | ||||||
|  |                     that._onAdd(e, data) === false) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _onPaste: function (e) { | ||||||
|  |             var that = e.data.fileupload, | ||||||
|  |                 cbd = e.originalEvent.clipboardData, | ||||||
|  |                 items = (cbd && cbd.items) || [], | ||||||
|  |                 data = {files: []}; | ||||||
|  |             $.each(items, function (index, item) { | ||||||
|  |                 var file = item.getAsFile && item.getAsFile(); | ||||||
|  |                 if (file) { | ||||||
|  |                     data.files.push(file); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |             if (that._trigger('paste', e, data) === false || | ||||||
|  |                     that._onAdd(e, data) === false) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _onDrop: function (e) { | ||||||
|  |             var that = e.data.fileupload, | ||||||
|  |                 dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer, | ||||||
|  |                 data = { | ||||||
|  |                     files: $.each( | ||||||
|  |                         $.makeArray(dataTransfer && dataTransfer.files), | ||||||
|  |                         that._normalizeFile | ||||||
|  |                     ) | ||||||
|  |                 }; | ||||||
|  |             if (that._trigger('drop', e, data) === false || | ||||||
|  |                     that._onAdd(e, data) === false) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             e.preventDefault(); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _onDragOver: function (e) { | ||||||
|  |             var that = e.data.fileupload, | ||||||
|  |                 dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer; | ||||||
|  |             if (that._trigger('dragover', e) === false) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             if (dataTransfer) { | ||||||
|  |                 dataTransfer.dropEffect = 'copy'; | ||||||
|  |             } | ||||||
|  |             e.preventDefault(); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initEventHandlers: function () { | ||||||
|  |             var ns = this.options.namespace; | ||||||
|  |             if (this._isXHRUpload(this.options)) { | ||||||
|  |                 this.options.dropZone | ||||||
|  |                     .bind('dragover.' + ns, {fileupload: this}, this._onDragOver) | ||||||
|  |                     .bind('drop.' + ns, {fileupload: this}, this._onDrop) | ||||||
|  |                     .bind('paste.' + ns, {fileupload: this}, this._onPaste); | ||||||
|  |             } | ||||||
|  |             this.options.fileInput | ||||||
|  |                 .bind('change.' + ns, {fileupload: this}, this._onChange); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _destroyEventHandlers: function () { | ||||||
|  |             var ns = this.options.namespace; | ||||||
|  |             this.options.dropZone | ||||||
|  |                 .unbind('dragover.' + ns, this._onDragOver) | ||||||
|  |                 .unbind('drop.' + ns, this._onDrop) | ||||||
|  |                 .unbind('paste.' + ns, this._onPaste); | ||||||
|  |             this.options.fileInput | ||||||
|  |                 .unbind('change.' + ns, this._onChange); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _setOption: function (key, value) { | ||||||
|  |             var refresh = $.inArray(key, this._refreshOptionsList) !== -1; | ||||||
|  |             if (refresh) { | ||||||
|  |                 this._destroyEventHandlers(); | ||||||
|  |             } | ||||||
|  |             $.Widget.prototype._setOption.call(this, key, value); | ||||||
|  |             if (refresh) { | ||||||
|  |                 this._initSpecialOptions(); | ||||||
|  |                 this._initEventHandlers(); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _initSpecialOptions: function () { | ||||||
|  |             var options = this.options; | ||||||
|  |             if (options.fileInput === undefined) { | ||||||
|  |                 options.fileInput = this.element.is('input:file') ? | ||||||
|  |                         this.element : this.element.find('input:file'); | ||||||
|  |             } else if (!(options.fileInput instanceof $)) { | ||||||
|  |                 options.fileInput = $(options.fileInput); | ||||||
|  |             } | ||||||
|  |             if (!(options.dropZone instanceof $)) { | ||||||
|  |                 options.dropZone = $(options.dropZone); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         _create: function () { | ||||||
|  |             var options = this.options; | ||||||
|  |             // Initialize options set via HTML5 data-attributes:
 | ||||||
|  |             $.extend(options, $(this.element[0].cloneNode(false)).data()); | ||||||
|  |             options.namespace = options.namespace || this.widgetName; | ||||||
|  |             this._initSpecialOptions(); | ||||||
|  |             this._slots = []; | ||||||
|  |             this._sequence = this._getXHRPromise(true); | ||||||
|  |             this._sending = this._active = this._loaded = this._total = 0; | ||||||
|  |             this._initEventHandlers(); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         destroy: function () { | ||||||
|  |             this._destroyEventHandlers(); | ||||||
|  |             $.Widget.prototype.destroy.call(this); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         enable: function () { | ||||||
|  |             $.Widget.prototype.enable.call(this); | ||||||
|  |             this._initEventHandlers(); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         disable: function () { | ||||||
|  |             this._destroyEventHandlers(); | ||||||
|  |             $.Widget.prototype.disable.call(this); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         // This method is exposed to the widget API and allows adding files
 | ||||||
|  |         // using the fileupload API. The data parameter accepts an object which
 | ||||||
|  |         // must have a files property and can contain additional options:
 | ||||||
|  |         // .fileupload('add', {files: filesList});
 | ||||||
|  |         add: function (data) { | ||||||
|  |             if (!data || this.options.disabled) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             if (data.fileInput && !data.files) { | ||||||
|  |                 data.files = this._getFileInputFiles(data.fileInput); | ||||||
|  |             } else { | ||||||
|  |                 data.files = $.each($.makeArray(data.files), this._normalizeFile); | ||||||
|  |             } | ||||||
|  |             this._onAdd(null, data); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         // This method is exposed to the widget API and allows sending files
 | ||||||
|  |         // using the fileupload API. The data parameter accepts an object which
 | ||||||
|  |         // must have a files property and can contain additional options:
 | ||||||
|  |         // .fileupload('send', {files: filesList});
 | ||||||
|  |         // The method returns a Promise object for the file upload call.
 | ||||||
|  |         send: function (data) { | ||||||
|  |             if (data && !this.options.disabled) { | ||||||
|  |                 if (data.fileInput && !data.files) { | ||||||
|  |                     data.files = this._getFileInputFiles(data.fileInput); | ||||||
|  |                 } else { | ||||||
|  |                     data.files = $.each($.makeArray(data.files), this._normalizeFile); | ||||||
|  |                 } | ||||||
|  |                 if (data.files.length) { | ||||||
|  |                     return this._onSend(null, data); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return this._getXHRPromise(false, data && data.context); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  | })); | ||||||
|  | @ -0,0 +1,172 @@ | ||||||
|  | /* | ||||||
|  |  * jQuery Iframe Transport Plugin 1.5 | ||||||
|  |  * https://github.com/blueimp/jQuery-File-Upload
 | ||||||
|  |  * | ||||||
|  |  * Copyright 2011, Sebastian Tschan | ||||||
|  |  * https://blueimp.net
 | ||||||
|  |  * | ||||||
|  |  * Licensed under the MIT license: | ||||||
|  |  * http://www.opensource.org/licenses/MIT
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /*jslint unparam: true, nomen: true */ | ||||||
|  | /*global define, window, document */ | ||||||
|  | 
 | ||||||
|  | (function (factory) { | ||||||
|  |     'use strict'; | ||||||
|  |     if (typeof define === 'function' && define.amd) { | ||||||
|  |         // Register as an anonymous AMD module:
 | ||||||
|  |         define(['jquery'], factory); | ||||||
|  |     } else { | ||||||
|  |         // Browser globals:
 | ||||||
|  |         factory(window.jQuery); | ||||||
|  |     } | ||||||
|  | }(function ($) { | ||||||
|  |     'use strict'; | ||||||
|  | 
 | ||||||
|  |     // Helper variable to create unique names for the transport iframes:
 | ||||||
|  |     var counter = 0; | ||||||
|  | 
 | ||||||
|  |     // The iframe transport accepts three additional options:
 | ||||||
|  |     // options.fileInput: a jQuery collection of file input fields
 | ||||||
|  |     // options.paramName: the parameter name for the file form data,
 | ||||||
|  |     //  overrides the name property of the file input field(s),
 | ||||||
|  |     //  can be a string or an array of strings.
 | ||||||
|  |     // options.formData: an array of objects with name and value properties,
 | ||||||
|  |     //  equivalent to the return data of .serializeArray(), e.g.:
 | ||||||
|  |     //  [{name: 'a', value: 1}, {name: 'b', value: 2}]
 | ||||||
|  |     $.ajaxTransport('iframe', function (options) { | ||||||
|  |         if (options.async && (options.type === 'POST' || options.type === 'GET')) { | ||||||
|  |             var form, | ||||||
|  |                 iframe; | ||||||
|  |             return { | ||||||
|  |                 send: function (_, completeCallback) { | ||||||
|  |                     form = $('<form style="display:none;"></form>'); | ||||||
|  |                     form.attr('accept-charset', options.formAcceptCharset); | ||||||
|  |                     // javascript:false as initial iframe src
 | ||||||
|  |                     // prevents warning popups on HTTPS in IE6.
 | ||||||
|  |                     // IE versions below IE8 cannot set the name property of
 | ||||||
|  |                     // elements that have already been added to the DOM,
 | ||||||
|  |                     // so we set the name along with the iframe HTML markup:
 | ||||||
|  |                     iframe = $( | ||||||
|  |                         '<iframe src="javascript:false;" name="iframe-transport-' + | ||||||
|  |                             (counter += 1) + '"></iframe>' | ||||||
|  |                     ).bind('load', function () { | ||||||
|  |                         var fileInputClones, | ||||||
|  |                             paramNames = $.isArray(options.paramName) ? | ||||||
|  |                                     options.paramName : [options.paramName]; | ||||||
|  |                         iframe | ||||||
|  |                             .unbind('load') | ||||||
|  |                             .bind('load', function () { | ||||||
|  |                                 var response; | ||||||
|  |                                 // Wrap in a try/catch block to catch exceptions thrown
 | ||||||
|  |                                 // when trying to access cross-domain iframe contents:
 | ||||||
|  |                                 try { | ||||||
|  |                                     response = iframe.contents(); | ||||||
|  |                                     // Google Chrome and Firefox do not throw an
 | ||||||
|  |                                     // exception when calling iframe.contents() on
 | ||||||
|  |                                     // cross-domain requests, so we unify the response:
 | ||||||
|  |                                     if (!response.length || !response[0].firstChild) { | ||||||
|  |                                         throw new Error(); | ||||||
|  |                                     } | ||||||
|  |                                 } catch (e) { | ||||||
|  |                                     response = undefined; | ||||||
|  |                                 } | ||||||
|  |                                 // The complete callback returns the
 | ||||||
|  |                                 // iframe content document as response object:
 | ||||||
|  |                                 completeCallback( | ||||||
|  |                                     200, | ||||||
|  |                                     'success', | ||||||
|  |                                     {'iframe': response} | ||||||
|  |                                 ); | ||||||
|  |                                 // Fix for IE endless progress bar activity bug
 | ||||||
|  |                                 // (happens on form submits to iframe targets):
 | ||||||
|  |                                 $('<iframe src="javascript:false;"></iframe>') | ||||||
|  |                                     .appendTo(form); | ||||||
|  |                                 form.remove(); | ||||||
|  |                             }); | ||||||
|  |                         form | ||||||
|  |                             .prop('target', iframe.prop('name')) | ||||||
|  |                             .prop('action', options.url) | ||||||
|  |                             .prop('method', options.type); | ||||||
|  |                         if (options.formData) { | ||||||
|  |                             $.each(options.formData, function (index, field) { | ||||||
|  |                                 $('<input type="hidden"/>') | ||||||
|  |                                     .prop('name', field.name) | ||||||
|  |                                     .val(field.value) | ||||||
|  |                                     .appendTo(form); | ||||||
|  |                             }); | ||||||
|  |                         } | ||||||
|  |                         if (options.fileInput && options.fileInput.length && | ||||||
|  |                                 options.type === 'POST') { | ||||||
|  |                             fileInputClones = options.fileInput.clone(); | ||||||
|  |                             // Insert a clone for each file input field:
 | ||||||
|  |                             options.fileInput.after(function (index) { | ||||||
|  |                                 return fileInputClones[index]; | ||||||
|  |                             }); | ||||||
|  |                             if (options.paramName) { | ||||||
|  |                                 options.fileInput.each(function (index) { | ||||||
|  |                                     $(this).prop( | ||||||
|  |                                         'name', | ||||||
|  |                                         paramNames[index] || options.paramName | ||||||
|  |                                     ); | ||||||
|  |                                 }); | ||||||
|  |                             } | ||||||
|  |                             // Appending the file input fields to the hidden form
 | ||||||
|  |                             // removes them from their original location:
 | ||||||
|  |                             form | ||||||
|  |                                 .append(options.fileInput) | ||||||
|  |                                 .prop('enctype', 'multipart/form-data') | ||||||
|  |                                 // enctype must be set as encoding for IE:
 | ||||||
|  |                                 .prop('encoding', 'multipart/form-data'); | ||||||
|  |                         } | ||||||
|  |                         form.submit(); | ||||||
|  |                         // Insert the file input fields at their original location
 | ||||||
|  |                         // by replacing the clones with the originals:
 | ||||||
|  |                         if (fileInputClones && fileInputClones.length) { | ||||||
|  |                             options.fileInput.each(function (index, input) { | ||||||
|  |                                 var clone = $(fileInputClones[index]); | ||||||
|  |                                 $(input).prop('name', clone.prop('name')); | ||||||
|  |                                 clone.replaceWith(input); | ||||||
|  |                             }); | ||||||
|  |                         } | ||||||
|  |                     }); | ||||||
|  |                     form.append(iframe).appendTo(document.body); | ||||||
|  |                 }, | ||||||
|  |                 abort: function () { | ||||||
|  |                     if (iframe) { | ||||||
|  |                         // javascript:false as iframe src aborts the request
 | ||||||
|  |                         // and prevents warning popups on HTTPS in IE6.
 | ||||||
|  |                         // concat is used to avoid the "Script URL" JSLint error:
 | ||||||
|  |                         iframe | ||||||
|  |                             .unbind('load') | ||||||
|  |                             .prop('src', 'javascript'.concat(':false;')); | ||||||
|  |                     } | ||||||
|  |                     if (form) { | ||||||
|  |                         form.remove(); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     // The iframe transport returns the iframe content document as response.
 | ||||||
|  |     // The following adds converters from iframe to text, json, html, and script:
 | ||||||
|  |     $.ajaxSetup({ | ||||||
|  |         converters: { | ||||||
|  |             'iframe text': function (iframe) { | ||||||
|  |                 return $(iframe[0].body).text(); | ||||||
|  |             }, | ||||||
|  |             'iframe json': function (iframe) { | ||||||
|  |                 return $.parseJSON($(iframe[0].body).text()); | ||||||
|  |             }, | ||||||
|  |             'iframe html': function (iframe) { | ||||||
|  |                 return $(iframe[0].body).html(); | ||||||
|  |             }, | ||||||
|  |             'iframe script': function (iframe) { | ||||||
|  |                 return $.globalEval($(iframe[0].body).text()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  | })); | ||||||
							
								
								
									
										29
									
								
								vendor/built_in_modules/archive/app/views/panel/archive/back_end/archive_files/js/locale.js
								
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										29
									
								
								vendor/built_in_modules/archive/app/views/panel/archive/back_end/archive_files/js/locale.js
								
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | /* | ||||||
|  |  * jQuery File Upload Plugin Localization Example 6.5.1 | ||||||
|  |  * https://github.com/blueimp/jQuery-File-Upload
 | ||||||
|  |  * | ||||||
|  |  * Copyright 2012, Sebastian Tschan | ||||||
|  |  * https://blueimp.net
 | ||||||
|  |  * | ||||||
|  |  * Licensed under the MIT license: | ||||||
|  |  * http://www.opensource.org/licenses/MIT
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /*global window */ | ||||||
|  | 
 | ||||||
|  | window.locale = { | ||||||
|  |     "fileupload": { | ||||||
|  |         "errors": { | ||||||
|  |             "maxFileSize": "File is too big", | ||||||
|  |             "minFileSize": "File is too small", | ||||||
|  |             "acceptFileTypes": "Filetype not allowed", | ||||||
|  |             "maxNumberOfFiles": "Max number of files exceeded", | ||||||
|  |             "uploadedBytes": "Uploaded bytes exceed file size", | ||||||
|  |             "emptyResult": "Empty file upload result" | ||||||
|  |         }, | ||||||
|  |         "error": "Error", | ||||||
|  |         "start": "Start", | ||||||
|  |         "cancel": "Cancel", | ||||||
|  |         "destroy": "Delete" | ||||||
|  |     } | ||||||
|  | }; | ||||||
							
								
								
									
										78
									
								
								vendor/built_in_modules/archive/app/views/panel/archive/back_end/archive_files/js/main.js
								
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										78
									
								
								vendor/built_in_modules/archive/app/views/panel/archive/back_end/archive_files/js/main.js
								
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,78 @@ | ||||||
|  | /* | ||||||
|  |  * jQuery File Upload Plugin JS Example 6.7 | ||||||
|  |  * https://github.com/blueimp/jQuery-File-Upload
 | ||||||
|  |  * | ||||||
|  |  * Copyright 2010, Sebastian Tschan | ||||||
|  |  * https://blueimp.net
 | ||||||
|  |  * | ||||||
|  |  * Licensed under the MIT license: | ||||||
|  |  * http://www.opensource.org/licenses/MIT
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /*jslint nomen: true, unparam: true, regexp: true */ | ||||||
|  | /*global $, window, document */ | ||||||
|  | 
 | ||||||
|  | $(function () { | ||||||
|  |     'use strict'; | ||||||
|  | 
 | ||||||
|  |     // Initialize the jQuery File Upload widget:
 | ||||||
|  |     $('#fileupload').fileupload(); | ||||||
|  | 
 | ||||||
|  |     // Enable iframe cross-domain access via redirect option:
 | ||||||
|  |     $('#fileupload').fileupload( | ||||||
|  |         'option', | ||||||
|  |         'redirect', | ||||||
|  |         window.location.href.replace( | ||||||
|  |             /\/[^\/]*$/, | ||||||
|  |             '/cors/result.html?%s' | ||||||
|  |         ) | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     if (window.location.hostname === 'blueimp.github.com') { | ||||||
|  |         // Demo settings:
 | ||||||
|  |         $('#fileupload').fileupload('option', { | ||||||
|  |             url: '//jquery-file-upload.appspot.com/', | ||||||
|  |             maxFileSize: 5000000, | ||||||
|  |             acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, | ||||||
|  |             process: [ | ||||||
|  |                 { | ||||||
|  |                     action: 'load', | ||||||
|  |                     fileTypes: /^image\/(gif|jpeg|png)$/, | ||||||
|  |                     maxFileSize: 20000000 // 20MB
 | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     action: 'resize', | ||||||
|  |                     maxWidth: 1440, | ||||||
|  |                     maxHeight: 900 | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     action: 'save' | ||||||
|  |                 } | ||||||
|  |             ] | ||||||
|  |         }); | ||||||
|  |         // Upload server status check for browsers with CORS support:
 | ||||||
|  |         if ($.support.cors) { | ||||||
|  |             $.ajax({ | ||||||
|  |                 url: '//jquery-file-upload.appspot.com/', | ||||||
|  |                 type: 'HEAD' | ||||||
|  |             }).fail(function () { | ||||||
|  |                 $('<span class="alert alert-error"/>') | ||||||
|  |                     .text('Upload server currently unavailable - ' + | ||||||
|  |                             new Date()) | ||||||
|  |                     .appendTo('#fileupload'); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         // Load existing files:
 | ||||||
|  |         $('#fileupload').each(function () { | ||||||
|  |             var that = this; | ||||||
|  |             $.getJSON(this.action, function (result) { | ||||||
|  |                 if (result && result.length) { | ||||||
|  |                     $(that).fileupload('option', 'done') | ||||||
|  |                         .call(that, null, {result: result}); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | }); | ||||||
							
								
								
									
										31
									
								
								vendor/built_in_modules/archive/app/views/panel/archive/front_end/archive_files/index.html.erb
								
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										31
									
								
								vendor/built_in_modules/archive/app/views/panel/archive/front_end/archive_files/index.html.erb
								
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | <% # encoding: utf-8 %> | ||||||
|  | 
 | ||||||
|  | <%= flash_messages %> | ||||||
|  | 
 | ||||||
|  | <%#= paginate @archive_files, :params => {:inner => false}%> | ||||||
|  | 
 | ||||||
|  | <% if @title %> | ||||||
|  | 	<h1 class="h1"><%= @title %></h1> | ||||||
|  | <% end %> | ||||||
|  | 	 | ||||||
|  | 	<ul class="subm"> | ||||||
|  | 	<% @archive_file_categorys.each do |afcpost| %> | ||||||
|  | 		<li><%= link_to afcpost.i18n_variable[I18n.locale], panel_archive_front_end_archive_files_path(:category_id => afcpost.id) %></li> | ||||||
|  | 	<% end %> | ||||||
|  | 	</ul> | ||||||
|  | 	 | ||||||
|  | 	<h3><%= @archive_files.first.archive_file_category.i18n_variable[I18n.locale] rescue nil %></h3> | ||||||
|  | 	 | ||||||
|  | 	<% @archive_files.each do |post| %> | ||||||
|  | 	 | ||||||
|  | 	<%= link_to post.title, panel_archive_front_end_archive_file_path(post, :category_id => post.archive_file_category_id) %> | ||||||
|  | 	 | ||||||
|  | 	<ol> | ||||||
|  | 		<% post.archive_file_multiples.each do | afile |  %>	 | ||||||
|  | 			<%  if afile.file.file and afile.choose_lang_display(I18n.locale.to_s) %> | ||||||
|  | 				<li><%= link_to afile.file_title, afile.file.url, {:target => '_blank', :title => afile.file_title} %></li> | ||||||
|  | 			<% end %> | ||||||
|  | 		<% end %> | ||||||
|  | 	</ol> | ||||||
|  | 	   | ||||||
|  | 	<% end %> | ||||||
							
								
								
									
										19
									
								
								vendor/built_in_modules/archive/app/views/panel/archive/front_end/archive_files/show.html.erb
								
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										19
									
								
								vendor/built_in_modules/archive/app/views/panel/archive/front_end/archive_files/show.html.erb
								
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | <% # encoding: utf-8 %> | ||||||
|  | 
 | ||||||
|  | <% if @title %> | ||||||
|  | 	<h1 class="h1"><%= @title %></h1> | ||||||
|  | <% end %> | ||||||
|  | 
 | ||||||
|  | <h3><%= @archive_file.archive_file_category.i18n_variable[I18n.locale] rescue nil %></h3> | ||||||
|  | 
 | ||||||
|  | <%= @archive_file.title %> | ||||||
|  | 
 | ||||||
|  | <ol> | ||||||
|  | 	<% @archive_file.archive_file_multiples.each do | afile |  %>	 | ||||||
|  | 		<%  if afile.file.file and afile.choose_lang_display(I18n.locale.to_s) %> | ||||||
|  | 			<li><%= link_to afile.file_title, afile.file.url, {:target => '_blank', :title => afile.file_title} %></li> | ||||||
|  | 		<% end %> | ||||||
|  | 	<% end %> | ||||||
|  | </ol> | ||||||
|  | 
 | ||||||
|  | <%#= link_back %> | ||||||
|  | @ -7,6 +7,6 @@ | ||||||
|   "update_info": "Some info", |   "update_info": "Some info", | ||||||
|   "create_date": "11-11-2011", |   "create_date": "11-11-2011", | ||||||
| 	"app_pages":  ["archive_files"], | 	"app_pages":  ["archive_files"], | ||||||
| 	"widgets": ["archive_files"], | 	"widgets": {"archive_files":[]}, | ||||||
| 	"enable_frontend": true | 	"enable_frontend": true | ||||||
| } | } | ||||||
|  |  | ||||||
		Reference in New Issue