Merge branch 'various_bugs' into nccu_master

Conflicts:
	Gemfile.lock
	app/assets/javascripts/ajax_form.js.erb
	app/assets/stylesheets/style.css.erb
	app/controllers/application_controller.rb
	app/controllers/sessions_controller.rb
	app/helpers/admin/web_link_helper.rb
	app/views/admin/attributes/_attribute_field.html.erb
	app/views/admin/designs/_form.html.erb
	app/views/admin/pages/_form.html.erb
	app/views/admin/sites/_side_bar.html.erb
	app/views/layouts/_orbit_bar.html.erb
	app/views/layouts/_side_bar.html.erb
	config/locales/en.yml
	config/locales/zh_tw.yml
	config/mongoid.yml
	vendor/built_in_modules/announcement/app/controllers/panel/announcement/back_end/bulletins_controller.rb
	vendor/built_in_modules/announcement/app/controllers/panel/announcement/front_end/bulletins_controller.rb
	vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/_bulletin.html.erb
	vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/_filter.html.erb
	vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/index.html.erb
	vendor/built_in_modules/announcement/app/views/panel/announcement/widget/bulletins/_index.html.erb
	vendor/built_in_modules/news/app/views/panel/news/back_end/news_bulletins/_filter.html.erb
	vendor/built_in_modules/news/app/views/panel/news/back_end/news_bulletins/_filter_status.html.erb
	vendor/built_in_modules/news/app/views/panel/news/back_end/news_bulletins/_news_bulletin.html.erb
	vendor/built_in_modules/news/app/views/panel/news/back_end/news_bulletins/index.html.erb
	vendor/built_in_modules/web_resource/app/views/panel/web_resource/back_end/web_links/index.html.erb
This commit is contained in:
chris committed 2012-10-29 16:10:07 +08:00
commit 65ac6980c4
2087 files changed
+80434 -3692

No files matched your search

+9 -5
View File
@@ -1,13 +1,17 @@
{
"title": "announcement",
"title": "announcement",
"version": "0.1",
"organization": "Rulingcom",
"author": "RD dep",
"intro": "A simple blog……",
"update_info": "Some info",
"create_date": "11-11-2011",
"app_pages": ["bulletins"],
"widgets": ["bulletins", "bulletins_and_web_links"],
"category": ["BulletinCategory"],
"enable_frontend": true
"app_pages": ["bulletins"],
"widgets": {
"index":["1","2","3","4","5"],
"bulletins_and_web_links":[]
},
"category": ["BulletinCategory"],
"widget_fields":["title","category","postdate"],
"enable_frontend": true
}
@@ -2,16 +2,17 @@ class Panel::Announcement::BackEnd::BulletinsController < OrbitBackendController
include AdminHelper
include OrbitControllerLib::DivisionForDisable
layout 'new_admin'
before_filter :authenticate_user!
before_filter :clean_values, :only => [:create, :update]
# before_filter :for_admin_only,:only => [:]
# before_filter :for_app_manager,:only => [:index,:show,]
before_filter :force_order_for_visitor,:only=>[:index,:show,:get_sorted_and_filtered_bulletins]
before_filter :force_order_for_user,:except => [:index,:show,:get_sorted_and_filtered_bulletins]
before_filter :for_app_sub_manager,:except => [:index,:show,:get_sorted_and_filtered_bulletins]
before_filter :only => [ :new,:create,:edit,:update,:create] do |controller|
controller.get_categorys('BulletinCategory')
end
before_filter :clean_values, :only => [:create, :update]
# before_filter :for_admin_only,:only => [:]
# before_filter :for_app_manager,:only => [:index,:show,]
before_filter :for_app_sub_manager,:except => [:index,:show,:get_sorted_and_filtered_bulletins]
def preview
#@preview_obj = Preview.create(:object=>params[:news_bulletin],:expired_at=>DateTime.now+30.minutes,:preview_at_link=>"panel_news_front_end_news_bulletin_path",:object_class_type=>"NewsBulletin")
@@ -14,6 +14,15 @@ class Panel::Announcement::FrontEnd::BulletinsController < OrbitWidgetController
end
def index
@item = Page.find(params[:page_id])
if @item.frontend_data_count
@page_num = @item.frontend_data_count
else
@page_num = 15
end
@frontend_style = @item.frontend_style
@page = Page.find(params[:page_id]) rescue nil
if !params[:search_query].blank?
# search_cond = {:is_checked=>true,:is_hidden=>false,:is_pending => false}
@@ -25,23 +34,23 @@ class Panel::Announcement::FrontEnd::BulletinsController < OrbitWidgetController
end
search_result = @search.results.collect{|result| result.id}
@bulletins = Bulletin.all.available_for_lang(I18n.locale).can_display.any_in(_id:search_result).desc(:postdate).page( params[:page_main]).per(15)
@bulletins = Bulletin.all.available_for_lang(I18n.locale).can_display.any_in(_id:search_result).page( params[:page_main]).per(@page_num)
else
date_now = Time.now
if !params[:category_id].blank? && !params[:tag_id].blank?
@tag = AnnouncementTag.find(params[:tag_id]) rescue nil
@tag = AnnouncementTag.where(key: params[:tag_id])[0] unless @tag
@bulletins = @tag.bulletins.available_for_lang(I18n.locale).can_display.where(:bulletin_category_id => params[:category_id]).any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page_main]).per(15)
@bulletins = @tag.bulletins.available_for_lang(I18n.locale).can_display.where(:bulletin_category_id => params[:category_id]).any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page_main]).per(@page_num)
@current_category = BulletinCategory.from_id(params[:category_id]) rescue nil
elsif !params[:category_id].blank?
@bulletins = Bulletin.all.available_for_lang(I18n.locale).can_display.where(:bulletin_category_id => params[:category_id]).any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page_main]).per(15)
@bulletins = Bulletin.all.available_for_lang(I18n.locale).can_display.where(:bulletin_category_id => params[:category_id]).any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page_main]).per(@page_num)
@current_category = BulletinCategory.from_id(params[:category_id]) rescue nil
elsif !params[:tag_id].blank?
@tag = AnnouncementTag.find(params[:tag_id]) rescue nil
@tag = AnnouncementTag.where(key: params[:tag_id])[0] unless @tag
@bulletins = @tag.bulletins.available_for_lang(I18n.locale).can_display.any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page_main]).per(15)
@bulletins = @tag.bulletins.available_for_lang(I18n.locale).can_display.any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page_main]).per(@page_num)
else
@bulletins = Bulletin.all.available_for_lang(I18n.locale).can_display.any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page_main]).per(15)
@bulletins = Bulletin.all.available_for_lang(I18n.locale).can_display.any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page_main]).per(@page_num)
end
impressionist(@tag) if @tag
end
@@ -8,17 +8,62 @@ class Panel::Announcement::Widget::BulletinsController < OrbitWidgetController
# GET /bulletins.xml
def index
@part = PagePart.find(params[:part_id])
if @part.widget_data_count
@page_num = @part.widget_data_count
else
@page_num = 4
end
if @part.widget_field
@widget_fields = @part.widget_field
else
@widget_fields = []
end
@title = params[:part_title]
@widget_style = @part.widget_style
@category_id = @part.category
date_now = Time.now
if !@category_id.blank?
@bulletins = Bulletin.can_display.where(:bulletin_category_id => @category_id).any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page] ).per(@page_num)
@current_category = BulletinCategory.from_id(@category_id) rescue nil
elsif !params[:tag_id].blank?
@tag = AnnouncementTag.find(params[:tag_id]) rescue nil
@tag = AnnouncementTag.where(key: params[:tag_id])[0] unless @tag
@bulletins = @tag.bulletins.can_display.any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page] ).per(@page_num)
else
@bulletins = Bulletin.can_display.any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page] ).per(@page_num)
end
get_categorys
end
def bulletins_list_and_pic
if params[:widget_data_count]
@page_num = params[:widget_data_count];
else
@page_num = 4;
end
@title = params[:part_title]
date_now = Time.now
if !params[:category_id].blank?
@bulletins = Bulletin.all.available_for_lang(I18n.locale).can_display.where(:bulletin_category_id => params[:category_id]).any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page]).per(10)
@bulletins = Bulletin.all.available_for_lang(I18n.locale).can_display.where(:bulletin_category_id => params[:category_id]).any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page]).per(@page_num )
@current_category = BulletinCategory.from_id(params[:category_id]) rescue nil
elsif !params[:tag_id].blank?
@tag = AnnouncementTag.find(params[:tag_id]) rescue nil
@tag = AnnouncementTag.where(key: params[:tag_id])[0] unless @tag
@bulletins = @tag.bulletins.available_for_lang(I18n.locale).can_display.any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page]).per(10)
@bulletins = @tag.bulletins.available_for_lang(I18n.locale).can_display.any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page]).per(@page_num )
else
@bulletins = Bulletin.all.available_for_lang(I18n.locale).can_display.any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page]).per(10)
@bulletins = Bulletin.all.available_for_lang(I18n.locale).can_display.any_of( {deadline: nil,:postdate.lte => date_now} , {:deadline.gte => date_now,:postdate.lte => date_now} ).desc( :is_top, :postdate).page( params[:page]).per(@page_num )
end
get_categorys
@@ -1,6 +1,6 @@
<tr id="<%= dom_id bulletin %>" class="with_action">
<td>
<% if (bulletin.create_user_id == current_user.id) || is_manager? %>
<% if (bulletin.create_user_id == current_or_guest_user.id) || is_manager? %>
<%= check_box_tag 'to_delete[]', bulletin.id, false, :class => "checkbox_in_list" %>
<% end -%>
</td>
@@ -33,9 +33,8 @@
<%= show_bulletin_title_at_index bulletin%>
<div class="quick-edit">
<ul class="nav nav-pills hide">
<% if (bulletin.create_user_id == current_user.id) || is_manager? %>
<% if current_user.admin? || (!bulletin.is_rejected? && !bulletin.is_checked?) %>
<% if (bulletin.create_user_id == current_or_guest_user.id) || is_manager? %>
<% if current_or_guest_user.admin? || (!bulletin.is_rejected? && !bulletin.is_checked?) %>
<li><%= link_to t(:edit), edit_panel_announcement_back_end_bulletin_path(bulletin) %></li>
<li class="dropdown">
<a href="#" data-toggle="dropdown" class="dropdown-toggle"><%= t(:quick_edit) %><b class="caret"></b></a>
@@ -43,7 +42,7 @@
<li><%= link_to t(:basic), load_quick_edit_panel_announcement_back_end_bulletin_path(bulletin, :type => 'basic'), :remote => true %></li>
<li><%#= link_to t(:picture), load_quick_edit_panel_announcement_back_end_bulletin_path(bulletin, :type => 'picture'), :remote => true %></li>
<li><%= link_to t(:tags), load_quick_edit_panel_announcement_back_end_bulletin_path(bulletin, :type => 'tags'), :remote => true %></li>
<li><%#= link_to t(:link), load_quick_edit_panel_announcement_back_end_bulletin_path(bulletin, :type => 'links'), :remote => true %></li>
<li><%= link_to t(:link), load_quick_edit_panel_announcement_back_end_bulletin_path(bulletin, :type => 'links'), :remote => true %></li>
<li><%#= link_to t(:file_), load_quick_edit_panel_announcement_back_end_bulletin_path(bulletin, :type => 'files'), :remote => true %></li>
</ul>
</li>
@@ -1,3 +1,3 @@
<div class="filter-clear">
<%= link_to content_tag(:i, nil, :class => 'icons-brush-large') + t(:clear), panel_announcement_back_end_bulletins_path(:filter => @filter, :sort => params[:sort], :direction => params[:direction], :clear => true, :type => type), :class => "btn js_history" %>
<%= link_to content_tag(:i, nil, :class => 'icons-brush-large') + t(:clear), panel_announcement_back_end_bulletins_path(:filter => @filter, :sort => params[:sort], :direction => params[:direction], :clear => true, :type => type), :class => "btn btn-small js_history" %>
</div>
@@ -14,20 +14,6 @@
<div class="accordion-heading">
<a href="#collapse-tags" data-toggle="collapse" data-parent=".filters" class="accordion-toggle"><%= t(:tags) %> <b class="web-symbol"></b></a>
</div>
</li>
</ul>
<div class="filters">
<div class="accordion-body collapse" id="collapse-status">
<%= render 'filter_status' %>
</div>
<div class="accordion-body collapse" id="collapse-category">
<%= render 'filter_categories' %>
</div>
<div class="accordion-body collapse" id="collapse-tags">
<%= render 'filter_tags' %>
</div>
<div id="sort_headers" class="table-label">
<%= render 'sort_headers' %>
</div>
</div>
</div>
@@ -1,6 +1,6 @@
<div class="accordion-inner" data-toggle="buttons-checkbox">
<% @bulletin_categories.each do |category| -%>
<%= link_to category.title, panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'categories', :id => category.id}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn js_history#{is_filter_active?('categories', category.id)}" %>
<%= link_to category.title, panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'categories', :id => category.id}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn btn-small js_history#{is_filter_active?('categories', category.id)}" %>
<% end -%>
</div>
<%= render :partial => 'clear_filters', :locals => {:type => 'categories'} %>
@@ -1,9 +1,9 @@
<div class="accordion-inner" data-toggle="buttons-checkbox">
<%= link_to t(:top), panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'status', :id => 'is_top'}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn js_history#{is_filter_active?('status', 'is_top')}" %>
<%= link_to t(:hot), panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'status', :id => 'is_hot'}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn js_history#{is_filter_active?('status', 'is_hot')}" %>
<%= link_to t(:hidden), panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'status', :id => 'is_hidden'}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn js_history#{is_filter_active?('status', 'is_hidden')}" %>
<%= link_to t(:pending), panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'status', :id => 'is_pending'}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn js_history#{is_filter_active?('status', 'is_pending')}" %>
<%= link_to t(:passed), panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'status', :id => 'is_checked'}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn js_history#{is_filter_active?('status', 'is_checked')}" %>
<%= link_to t(:rejected), panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'status', :id => 'is_rejected'}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn js_history#{is_filter_active?('status', 'is_rejected')}" %>
<%= link_to t(:top), panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'status', :id => 'is_top'}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn btn-small js_history#{is_filter_active?('status', 'is_top')}" %>
<%= link_to t(:hot), panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'status', :id => 'is_hot'}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn btn-small js_history#{is_filter_active?('status', 'is_hot')}" %>
<%= link_to t(:hidden), panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'status', :id => 'is_hidden'}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn btn-small js_history#{is_filter_active?('status', 'is_hidden')}" unless(is_guest?)%>
<%= link_to t(:pending), panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'status', :id => 'is_pending'}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn btn-small js_history#{is_filter_active?('status', 'is_pending')}" if(is_manager?)%>
<%= link_to t(:passed), panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'status', :id => 'is_checked'}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn btn-small js_history#{is_filter_active?('status', 'is_checked')}" if(is_manager?)%>
<%= link_to t(:rejected), panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'status', :id => 'is_rejected'}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn btn-small js_history#{is_filter_active?('status', 'is_rejected')}" if(is_manager?)%>
</div>
<%= render :partial => 'clear_filters', :locals => {:type => 'status'} %>
@@ -1,6 +1,6 @@
<div class="accordion-inner" data-toggle="buttons-checkbox">
<% @tags.each do |tag| -%>
<%= link_to tag[I18n.locale], panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'tags', :id => tag.id}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn js_history#{is_filter_active?('tags', tag.id)}" %>
<%= link_to tag[I18n.locale], panel_announcement_back_end_bulletins_path(:filter => @filter, :new_filter => {:type => 'tags', :id => tag.id}, :sort => params[:sort], :direction => params[:direction], :sort_options => params[:sort_options]), :class => "btn btn-small js_history#{is_filter_active?('tags', tag.id)}" %>
<% end -%>
</div>
<%= render :partial => 'clear_filters', :locals => {:type => 'tags'} %>
@@ -125,7 +125,7 @@
<%= I18nVariable.from_locale(locale) %>
<%= f.text_field locale, :class=>'post-title', :value => (@bulletin.title_translations[locale] rescue nil) %>
<% end %>
</div>
</div>
<div class="editor">
@@ -214,17 +214,56 @@
<p><%= t("sys.limit_of_upload_file_size",:best_size => '3MB') %></p>
<p><%= t("sys.preview_only_for_img") %></p>
</div>
<fieldset>
<input type="hidden" id="MAX_FILE_SIZE" name="MAX_FILE_SIZE" value="300000" />
<div id="filedrag">
<div class="point">Drop files here
<span>or</span>
<label class="file-select" for="fileselect">select from a folder
<!-- <input type="file" class="upload" id="fileselect" name="fileselect[]" multiple="multiple" /> -->
<%= f.fields_for @bulletin.bulletin_files.build, do |f| %>
<%= f.file_field :file, :multiple => true, :class => 'upload', :id => 'fileselect' %>
<% end %>
</label>
</div>
</div>
<div id="submitbutton">
<button type="submit">Upload Files</button>
</div>
</fieldset>
<div>
<table class="table table-condensed">
<thead>
<tr>
<th>File Name</th>
<th class="span2">Chinese</th>
<th class="span2">English</th>
<th class="span1"></th>
</tr>
</thead>
<tfoot>
<tr>
<td>File Name</td>
<td><input type="checkbox" id="optionsCheckbox" value="true" disabled /></td>
<td><input type="checkbox" id="optionsCheckbox" value="true" disabled checked /></td>
<td><a class="action" data-toggle="modal" href="#modal-link"><i class="icon-pencil"></i></a><a class="action" href=""><i class="icon-remove"></i></a></td>
</tr>
</tfoot>
<tbody id="messages">
</tbody>
</table>
</div>
</td>
</tr>
</tfoot>
<tbody>
<% @bulletin.bulletin_files.each_with_index do |bulletin_file, i| %>
<%# @bulletin.bulletin_files.each_with_index do |bulletin_file, i| %>
<%#= fields_for "bulletin[bulletin_files][]", bulletin_file do |f| %>
<%= f.fields_for :bulletin_files, bulletin_file do |f| %>
<%= render :partial => 'form_bulletin_file', :object => bulletin_file, :locals => {:f => f, :i => i} %>
<% end %>
<% end %>
<%#= f.fields_for :bulletin_files do |f| %>
<%#= render :partial => 'form_bulletin_file', :object => bulletin_file, :locals => {:f => f, :i => i} %>
<%# end %>
<%# end %>
</tbody>
</table>
@@ -250,6 +289,7 @@
<% content_for :page_specific_javascript do %>
<%= javascript_include_tag "bulletin_form" %>
<%= javascript_include_tag "inc/jquery.imagesloaded.js" %>
<script>
$(document).ready(function() {
@@ -1,3 +1,4 @@
<% # encoding: utf-8 %>
<tr id="<%= "bulletin_file_#{form_bulletin_file.id}" if !form_bulletin_file.new_record? %>" class='list_item'>
<td>
@@ -4,7 +4,7 @@
</table>
<div class="form-actions form-fixed pagination-right">
<%= link_to content_tag(:i, nil, :class => 'icon-plus icon-white') + t(:add), new_panel_announcement_back_end_bulletin_path, :class => 'btn btn-primary pull-right' %>
<%= link_to(content_tag(:i, nil, :class => 'icon-plus icon-white') + t(:add), new_panel_announcement_back_end_bulletin_path, :class => 'btn btn-primary pull-right' )if (is_manager? rescue nil)%>
<div id="bulletin_pagination" class="paginationFixed">
<%= paginate @bulletins, :params => {:direction => params[:direction], :sort => params[:sort], :filter => @filter, :new_filter => nil, :sort_options => params[:sort_options]} %>
</div>
@@ -4,6 +4,226 @@
<h1 class="h1"><%= @page.title rescue nil %></h1>
<% if !@item.frontend_field.blank? %>
<% if @frontend_style == '1' %>
<div class="news news1">
<table class="newstb" border="0" cellpadding="0" cellspacing="0" >
<thead>
<tr>
<% @item.frontend_field.each do |ff| %>
<th><span class="<%= ff[1] %>"><%= t("announcement.bulletin.#{ff[0]}") if !ff[0].blank? %></span></th>
<% end %>
</tr>
</thead>
<% @bulletins.each do |post| %>
<% @item.frontend_field.each do |ff| %>
<tr class="<%= cycle('odd', '')%>">
<td>
<span class="<%= ff[1] %>">
<% if ff[1] == 'title' %>
<%= link_to post.send("#{ff[0]}")[I18n.locale], panel_announcement_front_end_bulletin_path(post, :category_id => post.send("#{post.class.to_s.underscore}_category_id")) %>
<% elsif ff[1] == 'date' %>
<%= display_date(post.send(ff[0])) %>
<% elsif ff[1] == 'category' %>
<%= post.send("#{post.class.to_s.underscore}_#{ff[0]}").i18n_variable[I18n.locale] rescue nil %>
<% elsif ff[1] == 'img' %>
<div class="img app-pic"><%= image_tag(post.send(wf[0]).url) %></div>
<% elsif ff[1] == 'text' %>
<%#= post.send("#{ff[0]}[#{I18n.locale}]").html_safe %>
<%= post.send("#{ff[0]}")[I18n.locale].html_safe %>
<% elsif ff[1] == 'status' %>
<% if post.is_top? %>
<span class="top"><%= t(:top) %></span>
<% end %>
<% if post.is_hot? %>
<span class="hot"><%= t(:hot) %></span>
<% end %>
<% elsif ff[1] == 'link' %>
<% elsif ff[1] == 'file' %>
<% elsif ff[1] == 'tag' %>
<% elsif ff[1] == 'viewcount' %>
<%= dislpay_view_count(post) %>
<% elsif ff[1] == 'poster' %>
<%= User.from_id(post.update_user_id).name rescue ''%>
<% end %>
</span>
</td>
</tr>
<% end %>
<% end %>
</table>
</div>
<% elsif @frontend_style == '2' %>
<div class="news news2">
<ul class="newslist">
<% @bulletins.each do |post| %>
<li class="<%= cycle('odd', '')%>">
<div class="img app-pic"><%= image_tag(post.image.url) %></div>
<% @item.frontend_field.each do |ff| %>
<span class="<%= ff[1] %>">
<% if ff[1] == 'title' %>
<%= link_to post.title[I18n.locale], panel_announcement_front_end_bulletin_path(post, :category_id => post.bulletin_category_id) %>
<% elsif ff[1] == 'date' %>
<%= display_date(post.send(ff[0])) %>
<% elsif ff[1] == 'category' %>
<%= post.send("#{post.class.to_s.underscore}_#{ff[0]}").i18n_variable[I18n.locale] rescue nil %>
<% elsif ff[1] == 'text' %>
<%#= post.send("#{ff[0]}[#{I18n.locale}]").html_safe %>
<%= post.send("#{ff[0]}")[I18n.locale].html_safe %>
<% elsif ff[1] == 'status' %>
<% if post.is_top? %>
<span class="top"><%= t(:top) %></span>
<% end %>
<% if post.is_hot? %>
<span class="hot"><%= t(:hot) %></span>
<% end %>
<% elsif ff[1] == 'link' %>
<% elsif ff[1] == 'file' %>
<% elsif ff[1] == 'tag' %>
<% elsif ff[1] == 'viewcount' %>
<%= dislpay_view_count(post) %>
<% elsif ff[1] == 'poster' %>
<%= User.from_id(post.update_user_id).name rescue ''%>
<% end %>
</span>
<% end %>
</li>
<% end %>
</ul>
</div>
<% elsif @frontend_style == '3' %>
<div class="news news3">
<ul class="newslist">
<% @bulletins.each do |post| %>
<li class="<%= cycle('odd', '')%>">
<div class="img app-pic"><%= image_tag(post.image.url) %></div>
<div class="wrap">
<% @item.frontend_field.each do |ff| %>
<span class="<%= ff[1] %>">
<% if ff[1] == 'title' %>
<%= link_to post.send("#{ff[0]}")[I18n.locale], panel_announcement_front_end_bulletin_path(post, :category_id => post.send("#{post.class.to_s.underscore}_category_id")) %>
<% elsif ff[1] == 'date' %>
<%= display_date(post.send(ff[0])) %>
<% elsif ff[1] == 'category' %>
<%= post.send("#{post.class.to_s.underscore}_#{ff[0]}").i18n_variable[I18n.locale] rescue nil %>
<% elsif ff[1] == 'text' %>
<%#= post.send("#{ff[0]}[#{I18n.locale}]").html_safe %>
<%= post.send("#{ff[0]}")[I18n.locale].html_safe %>
<% elsif ff[1] == 'status' %>
<% if post.is_top? %>
<span class="top"><%= t(:top) %></span>
<% end %>
<% if post.is_hot? %>
<span class="hot"><%= t(:hot) %></span>
<% end %>
<% elsif ff[1] == 'link' %>
<% elsif ff[1] == 'file' %>
<% elsif ff[1] == 'tag' %>
<% elsif ff[1] == 'viewcount' %>
<%= dislpay_view_count(post) %>
<% elsif ff[1] == 'poster' %>
<%= User.from_id(post.update_user_id).name rescue ''%>
<% end %>
</span>
<% end %>
</div>
</li>
<% end %>
</ul>
</div>
<% elsif @frontend_style == '4' %>
<div class="news news4">
<ul class="newslist">
<% @bulletins.each do |post| %>
<li class="<%= cycle('odd', '')%>">
<div class="img app-pic"><%= image_tag(post.image.url) %></div>
<div class="wrap">
<% @item.frontend_field.each do |ff| %>
<span class="<%= ff[1] %>">
<% if ff[1] == 'title' %>
<%= link_to post.send("#{ff[0]}")[I18n.locale], panel_announcement_front_end_bulletin_path(post, :category_id => post.send("#{post.class.to_s.underscore}_category_id")) %>
<% elsif ff[1] == 'date' %>
<%= display_date(post.send(ff[0])) %>
<% elsif ff[1] == 'category' %>
<%= post.send("#{post.class.to_s.underscore}_#{ff[0]}").i18n_variable[I18n.locale] rescue nil %>
<% elsif ff[1] == 'text' %>
<%#= post.send("#{ff[0]}[#{I18n.locale}]").html_safe %>
<%= post.send("#{ff[0]}")[I18n.locale].html_safe %>
<% elsif ff[1] == 'status' %>
<% if post.is_top? %>
<span class="top"><%= t(:top) %></span>
<% end %>
<% if post.is_hot? %>
<span class="hot"><%= t(:hot) %></span>
<% end %>
<% elsif ff[1] == 'link' %>
<% elsif ff[1] == 'file' %>
<% elsif ff[1] == 'tag' %>
<% elsif ff[1] == 'viewcount' %>
<%= dislpay_view_count(post) %>
<% elsif ff[1] == 'poster' %>
<%= User.from_id(post.update_user_id).name rescue ''%>
<% end %>
</span>
<% end %>
</div>
</li>
<% end %>
</ul>
</div>
<% elsif @frontend_style == '5' %>
<div class="news news5">
<div class="img app-pic"><%= image_tag(@bulletins.first.image.url) %></div>
<ul class="newslist">
<% @bulletins.each do |post| %>
<li class="<%= cycle('odd', '')%>">
<% @item.frontend_field.each do |ff| %>
<span class="<%= ff[1] %>">
<% if ff[1] == 'title' %>
<%= link_to post.send("#{ff[0]}")[I18n.locale], panel_announcement_front_end_bulletin_path(post, :category_id => post.send("#{post.class.to_s.underscore}_category_id")) %>
<% elsif ff[1] == 'date' %>
<%= display_date(post.send(ff[0])) %>
<% elsif ff[1] == 'category' %>
<%= post.send("#{post.class.to_s.underscore}_#{ff[0]}").i18n_variable[I18n.locale] rescue nil %>
<% elsif ff[1] == 'text' %>
<%#= post.send("#{ff[0]}[#{I18n.locale}]").html_safe %>
<%= post.send("#{ff[0]}")[I18n.locale].html_safe %>
<% elsif ff[1] == 'status' %>
<% if post.is_top? %>
<span class="top"><%= t(:top) %></span>
<% end %>
<% if post.is_hot? %>
<span class="hot"><%= t(:hot) %></span>
<% end %>
<% elsif ff[1] == 'link' %>
<% elsif ff[1] == 'file' %>
<% elsif ff[1] == 'tag' %>
<% elsif ff[1] == 'viewcount' %>
<%= dislpay_view_count(post) %>
<% elsif ff[1] == 'poster' %>
<%= User.from_id(post.update_user_id).name rescue ''%>
<% end %>
</span>
<% end %>
</li>
<% end %>
</ul>
</div>
<table class="table table-bordered">
<tr>
@@ -36,8 +256,31 @@
</tr>
<% end %>
</table>
<% else %>
<table class="table table-bordered">
<tr>
<th><%= t('announcement.bulletin.category') %></th>
<th><%= t('announcement.bulletin.title') %></th>
<th><%= t('announcement.bulletin.postdate') %></th>
</tr>
<% @bulletins.each do |post| %>
<tr>
<td><%= post.bulletin_category.i18n_variable[I18n.locale] rescue nil %></td>
<td><%= link_to post.title[I18n.locale], panel_announcement_front_end_bulletin_path(post, :category_id => post.bulletin_category_id) %>
<%#= link_to post.title, panel_announcement_back_end_bulletin_path(post) %>
</td>
<td><%= display_date_time(post.postdate) %></td>
</tr>
<% end %>
</table>
<% end %>
<%= paginate @bulletins, :param_name => :page_main, :params => {:inner => 'false'} %>
@@ -0,0 +1 @@
Hello~ I am your plugin profile
@@ -1,23 +1,259 @@
<% # encoding: utf-8 %>
<% if @title %>
<h1 class="h1"><%= @title %></h1>
<% end %>
<% if !@widget_fields.blank? %>
<table class="table table-bordered">
<tr>
<th class="title"><%= t(:title) %></th>
<th class="date"><%= t(:postdate) %></th>
</tr>
<% if @widget_style == '1' %>
<% @bulletins.each do |post| %>
<tr>
<td class="title"><%= link_to post.title, panel_announcement_front_end_bulletin_path(post, :category_id => post.bulletin_category_id) %>
</td>
<td class="date"><%= display_date_time(post.postdate) %></td>
</tr>
<div class="news news1">
<table class="newstb" border="0" cellpadding="0" cellspacing="0" >
<thead>
<tr>
<% @widget_fields.each do |wf| %>
<th><span class="<%= wf[1] %>"><%= t("announcement.bulletin.#{wf[0]}") if !wf[0].blank? %></span></th>
<% end %>
</tr>
</thead>
<% @bulletins.each do |post| %>
<% @widget_fields.each do |wf| %>
<tr class="<%= cycle('odd', '')%>">
<td>
<span class="<%= wf[1] %>">
<% if wf[1] == 'title' %>
<%= link_to post.send("#{wf[0]}")[I18n.locale], panel_announcement_front_end_bulletin_path(post, :category_id => post.send("#{post.class.to_s.underscore}_category_id")) %>
<% elsif wf[1] == 'date' %>
<%= display_date(post.send(wf[0])) %>
<% elsif wf[1] == 'category' %>
<%= post.send("#{post.class.to_s.underscore}_#{wf[0]}").i18n_variable[I18n.locale] rescue nil %>
<% elsif wf[1] == 'img' %>
<div class="img app-pic"><%= image_tag(post.send(wf[0]).url) %></div>
<% elsif wf[1] == 'text' %>
<%#= post.send("#{wf[0]}[#{I18n.locale}]").html_safe %>
<%= post.send("#{wf[0]}")[I18n.locale].html_safe %>
<% elsif wf[1] == 'status' %>
<% if post.is_top? %>
<span class="top"><%= t(:top) %></span>
<% end %>
<% if post.is_hot? %>
<span class="hot"><%= t(:hot) %></span>
<% end %>
<% elsif wf[1] == 'link' %>
<% elsif wf[1] == 'file' %>
<% elsif wf[1] == 'tag' %>
<% elsif wf[1] == 'viewcount' %>
<%= dislpay_view_count(post) %>
<% elsif wf[1] == 'poster' %>
<%= User.from_id(post.update_user_id).name rescue ''%>
<% end %>
</span>
</td>
</tr>
<% end %>
<% end %>
</table>
<% if !@category_id.blank? %>
<div class="more"><%= link_to t('more'), panel_announcement_front_end_bulletins_path( :category_id => @category_id ) %></div>
<% else %>
<div class="more"><%= link_to t('more'), panel_announcement_front_end_bulletins_path() %></div>
<% end %>
</div>
<% elsif @widget_style == '2' %>
<div class="news news2">
<ul class="newslist">
<% @bulletins.each do |post| %>
<li class="<%= cycle('odd', '')%>">
<div class="img app-pic"><%= image_tag(post.image.url) %></div>
<% @widget_fields.each do |wf| %>
<span class="<%= wf[1] %>">
<% if wf[1] == 'title' %>
<%= link_to post.send("#{wf[0]}")[I18n.locale], panel_announcement_front_end_bulletin_path(post, :category_id => post.send("#{post.class.to_s.underscore}_category_id")) %>
<% elsif wf[1] == 'date' %>
<%= display_date(post.send(wf[0])) %>
<% elsif wf[1] == 'category' %>
<%= post.send("#{post.class.to_s.underscore}_#{wf[0]}").i18n_variable[I18n.locale] rescue nil %>
<% elsif wf[1] == 'text' %>
<%#= post.send("#{wf[0]}[#{I18n.locale}]").html_safe %>
<%= post.send("#{wf[0]}")[I18n.locale].html_safe %>
<% elsif wf[1] == 'status' %>
<% if post.is_top? %>
<span class="top"><%= t(:top) %></span>
<% end %>
<% if post.is_hot? %>
<span class="hot"><%= t(:hot) %></span>
<% end %>
<% elsif wf[1] == 'link' %>
<% elsif wf[1] == 'file' %>
<% elsif wf[1] == 'tag' %>
<% elsif wf[1] == 'viewcount' %>
<%= dislpay_view_count(post) %>
<% elsif wf[1] == 'poster' %>
<%= User.from_id(post.update_user_id).name rescue ''%>
<% end %>
</span>
<% end %>
</li>
<% end %>
</ul>
<% if !@category_id.blank? %>
<div class="more"><%= link_to t('more'), panel_announcement_front_end_bulletins_path( :category_id => @category_id ) %></div>
<% else %>
<div class="more"><%= link_to t('more'), panel_announcement_front_end_bulletins_path() %></div>
<% end %>
</div>
<% elsif @widget_style == '3' %>
<div class="news news3">
<ul class="newslist">
<% @bulletins.each do |post| %>
<li class="<%= cycle('odd', '')%>">
<div class="img app-pic"><%= image_tag(post.image.url) %></div>
<div class="wrap">
<% @widget_fields.each do |wf| %>
<span class="<%= wf[1] %>">
<% if wf[1] == 'title' %>
<%= link_to post.send("#{wf[0]}")[I18n.locale], panel_announcement_front_end_bulletin_path(post, :category_id => post.send("#{post.class.to_s.underscore}_category_id")) %>
<% elsif wf[1] == 'date' %>
<%= display_date(post.send(wf[0])) %>
<% elsif wf[1] == 'category' %>
<%= post.send("#{post.class.to_s.underscore}_#{wf[0]}").i18n_variable[I18n.locale] rescue nil %>
<% elsif wf[1] == 'text' %>
<%#= post.send("#{wf[0]}[#{I18n.locale}]").html_safe %>
<%= post.send("#{wf[0]}")[I18n.locale].html_safe %>
<% elsif wf[1] == 'status' %>
<% if post.is_top? %>
<span class="top"><%= t(:top) %></span>
<% end %>
<% if post.is_hot? %>
<span class="hot"><%= t(:hot) %></span>
<% end %>
<% elsif wf[1] == 'link' %>
<% elsif wf[1] == 'file' %>
<% elsif wf[1] == 'tag' %>
<% elsif wf[1] == 'viewcount' %>
<%= dislpay_view_count(post) %>
<% elsif wf[1] == 'poster' %>
<%= User.from_id(post.update_user_id).name rescue ''%>
<% end %>
</span>
<% end %>
</div>
</li>
<% end %>
</ul>
<% if !@category_id.blank? %>
<div class="more"><%= link_to t('more'), panel_announcement_front_end_bulletins_path( :category_id => @category_id ) %></div>
<% else %>
<div class="more"><%= link_to t('more'), panel_announcement_front_end_bulletins_path() %></div>
<% end %>
</div>
<% elsif @widget_style == '4' %>
<div class="news news4">
<ul class="newslist">
<% @bulletins.each do |post| %>
<li class="<%= cycle('odd', '')%>">
<div class="img app-pic"><%= image_tag(post.image.url) %></div>
<div class="wrap">
<% @widget_fields.each do |wf| %>
<span class="<%= wf[1] %>">
<% if wf[1] == 'title' %>
<%= link_to post.send("#{wf[0]}")[I18n.locale], panel_announcement_front_end_bulletin_path(post, :category_id => post.send("#{post.class.to_s.underscore}_category_id")) %>
<% elsif wf[1] == 'date' %>
<%= display_date(post.send(wf[0])) %>
<% elsif wf[1] == 'category' %>
<%= post.send("#{post.class.to_s.underscore}_#{wf[0]}").i18n_variable[I18n.locale] rescue nil %>
<% elsif wf[1] == 'text' %>
<%#= post.send("#{wf[0]}[#{I18n.locale}]").html_safe %>
<%= post.send("#{wf[0]}")[I18n.locale].html_safe %>
<% elsif wf[1] == 'status' %>
<% if post.is_top? %>
<span class="top"><%= t(:top) %></span>
<% end %>
<% if post.is_hot? %>
<span class="hot"><%= t(:hot) %></span>
<% end %>
<% elsif wf[1] == 'link' %>
<% elsif wf[1] == 'file' %>
<% elsif wf[1] == 'tag' %>
<% elsif wf[1] == 'viewcount' %>
<%= dislpay_view_count(post) %>
<% elsif wf[1] == 'poster' %>
<%= User.from_id(post.update_user_id).name rescue ''%>
<% end %>
</span>
<% end %>
</div>
</li>
<% end %>
</ul>
<% if !@category_id.blank? %>
<div class="more"><%= link_to t('more'), panel_announcement_front_end_bulletins_path( :category_id => @category_id ) %></div>
<% else %>
<div class="more"><%= link_to t('more'), panel_announcement_front_end_bulletins_path() %></div>
<% end %>
</div>
<% elsif @widget_style == '5' %>
<div class="news news5">
<div class="img app-pic"><%= image_tag(@bulletins.first.image.url) %></div>
<ul class="newslist">
<% @bulletins.each do |post| %>
<li class="<%= cycle('odd', '')%>">
<% @widget_fields.each do |wf| %>
<span class="<%= wf[1] %>">
<% if wf[1] == 'title' %>
<%= link_to post.send("#{wf[0]}")[I18n.locale], panel_announcement_front_end_bulletin_path(post, :category_id => post.send("#{post.class.to_s.underscore}_category_id")) %>
<% elsif wf[1] == 'date' %>
<%= display_date(post.send(wf[0])) %>
<% elsif wf[1] == 'category' %>
<%= post.send("#{post.class.to_s.underscore}_#{wf[0]}").i18n_variable[I18n.locale] rescue nil %>
<% elsif wf[1] == 'text' %>
<%#= post.send("#{wf[0]}[#{I18n.locale}]").html_safe %>
<%= post.send("#{wf[0]}")[I18n.locale].html_safe %>
<% elsif wf[1] == 'status' %>
<% if post.is_top? %>
<span class="top"><%= t(:top) %></span>
<% end %>
<% if post.is_hot? %>
<span class="hot"><%= t(:hot) %></span>
<% end %>
<% elsif wf[1] == 'link' %>
<% elsif wf[1] == 'file' %>
<% elsif wf[1] == 'tag' %>
<% elsif wf[1] == 'viewcount' %>
<%= dislpay_view_count(post) %>
<% elsif wf[1] == 'poster' %>
<%= User.from_id(post.update_user_id).name rescue ''%>
<% end %>
</span>
<% end %>
</li>
<% end %>
</ul>
<% if !@category_id.blank? %>
<div class="more"><%= link_to t('more'), panel_announcement_front_end_bulletins_path( :category_id => @category_id ) %></div>
<% else %>
<div class="more"><%= link_to t('more'), panel_announcement_front_end_bulletins_path() %></div>
<% end %>
</div>
<% end %>
</table>
<%= paginate @bulletins, :params => {:inner => 'true'}, :remote => true %>
<% end %>
@@ -1,3 +1,7 @@
<script type='text/javascript' src='/assets/jquery.mu.image.resize.js'></script>
<script type='text/javascript' src='/assets/jquery.mu.image.resize.degsin.js'></script>
<div id="bulletin_widget">
<%= render 'index' %>
</div>
+25
View File
@@ -0,0 +1,25 @@
module Announcement
OrbitApp.registration "Announcement",:type=> 'ModuleApp' do
base_url File.expand_path File.dirname(__FILE__)
personal_plugin :enable => true,:path=>"panel/announcement/plugin/profile"
end
end
# OrbitApp.backend_side_bar 'News' do
# block :available_for => [:admin,:guest,:manager,:sub_manager],
# :active_for_controllers=> ['news_bulletins', '/panel/news/back_end/tags', 'news_bulletin_categorys', 'news_approvals'],
# :active_for_ob_auths_object => ['NewsBulletinCategory'],
# :head_link => panel_news_back_end_news_bulletins_path ,
# :head_label=> I18n.t('admin.news')
# context_link :link=>new_panel_news_back_end_news_bulletin_path ,
# :priority=>1,:label=>I18n.t('announcement.add_new'),
# :active_for_action=>{:news_bulletins=>:new}
# end
@@ -1,4 +0,0 @@
require "announcement/engine"
module Announcement
end
@@ -0,0 +1,6 @@
.bundle/
log/*.log
pkg/
test/dummy/db/*.sqlite3
test/dummy/log/*.log
test/dummy/tmp/
+17
View File
@@ -0,0 +1,17 @@
source "http://rubygems.org"
# Declare your gem's dependencies in archive.gemspec.
# Bundler will treat runtime dependencies like base dependencies, and
# development dependencies will be added by default to the :development group.
gemspec
# jquery-rails is used by the dummy application
gem "jquery-rails"
# Declare any dependencies that are still in development here instead of in
# your gemspec. These might include edge Rails or gems from your path or
# Git. Remember to move these dependencies to your gemspec before releasing
# your gem to rubygems.org.
# To use debugger
# gem 'ruby-debug19', :require => 'ruby-debug'
+20
View File
@@ -0,0 +1,20 @@
Copyright 2012 YOURNAME
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+3
View File
@@ -0,0 +1,3 @@
= Archive
This project rocks and uses MIT-LICENSE.
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env rake
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end
begin
require 'rdoc/task'
rescue LoadError
require 'rdoc/rdoc'
require 'rake/rdoctask'
RDoc::Task = Rake::RDocTask
end
RDoc::Task.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'Archive'
rdoc.options << '--line-numbers'
rdoc.rdoc_files.include('README.rdoc')
rdoc.rdoc_files.include('lib/**/*.rb')
end
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
load 'rails/tasks/engine.rake'
Bundler::GemHelper.install_tasks
require 'rake/testtask'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = false
end
task :default => :test
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,23 @@
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :set_locale
# Set I18n.locale
def set_locale
# update session if passed
session[:locale] = params[:locale] if params[:locale]
# set locale based on session or default
begin
# check if locale is valid for non site pages
if !VALID_LOCALES.include?(session[:locale])
I18n.locale = I18n.default_locale
else
I18n.locale = session[:locale]
end
rescue
I18n.locale = I18n.default_locale
end
end
end
@@ -0,0 +1,97 @@
class Panel::Archive::BackEnd::ArchiveFileCategorysController < OrbitBackendController
def index
@archive_file_categorys = ArchiveFileCategory.all
@archive_file_category = ArchiveFileCategory.new(:display => 'List')
@url = panel_archive_back_end_archive_file_categorys_path
respond_to do |format|
format.html # index.html.erb
format.js
end
end
# GET /archive_files/1
# GET /archive_files/1.xml
def show
@archive_file_category = ArchiveFileCategory.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.js
end
end
# GET /archive_files/new
# GET /archive_files/new.xml
def new
@archive_file_category = ArchiveFileCategory.new(:display => 'List')
respond_to do |format|
format.html # new.html.erb
format.js
end
end
# GET /archive_files/1/edit
def edit
@archive_file_category = ArchiveFileCategory.find(params[:id])
@i18n_variable = @archive_file_category.i18n_variable
@url = panel_archive_back_end_archive_file_category_path(@archive_file_category)
respond_to do |format|
format.html
format.js
end
end
# POST /archive_files
# POST /archive_files.xml
def create
@archive_file_category = ArchiveFileCategory.new(params[:archive_file_category])
respond_to do |format|
if @archive_file_category.save
format.html { redirect_to(panel_archive_back_end_archive_file_categorys_url, :notice => t('archive_file_category.create_archive_file_category_success')) }
format.js
else
format.html { render :action => "new" }
format.js { render action: "new" }
end
end
end
# PUT /archive_files/1
# PUT /archive_files/1.xml
def update
@archive_file_category = ArchiveFileCategory.find(params[:id])
@url = panel_archive_back_end_archive_file_category_path(@archive_file_category)
respond_to do |format|
if @archive_file_category.update_attributes(params[:archive_file_category])
format.html { redirect_to(panel_archive_back_end_archive_file_categorys_url, :notice => t('archive_file_category.update_archive_file_category_success')) }
# format.xml { head :ok }
format.js
else
format.html { render :action => "edit" }
format.js { render :action => "edit" }
end
end
end
# DELETE /archive_files/1
# DELETE /archive_files/1.xml
def destroy
@archive_file_category = ArchiveFileCategory.find(params[:id])
@archive_file_category.destroy
respond_to do |format|
format.html { redirect_to(panel_archive_back_end_archive_file_categorys_url) }
# format.xml { head :ok }
format.js
end
end
end
@@ -0,0 +1,117 @@
class Panel::Archive::BackEnd::ArchiveFilesController < OrbitBackendController
before_filter :authenticate_user!
before_filter :is_admin?
def index
get_categorys(params[:archive_file_category_id])
@archive_files = ArchiveFile.all.page(params[:page]).per(10)
get_tags
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @archive_files }
end
end
# GET /archive_files/1
# GET /archive_files/1.xml
def show
@archive_file = ArchiveFile.find(params[:id])
# get_categorys
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @archive_file }
end
end
# GET /archive_files/new
# GET /archive_files/new.xml
def new
@archive_file = ArchiveFile.new
get_categorys
get_tags
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @archive_file }
end
end
# GET /archive_files/1/edit
def edit
@archive_file = ArchiveFile.find(params[:id])
get_categorys
get_tags
end
# POST /archive_files
# POST /archive_files.xml
def create
@archive_file = ArchiveFile.new(params[:archive_file])
@archive_file.create_user_id = current_user.id
@archive_file.update_user_id = current_user.id
respond_to do |format|
if @archive_file.save
format.html { redirect_to(panel_archive_back_end_archive_files_url) }
format.xml { render :xml => @archive_file, :status => :created, :location => @archive_file }
else
format.html { render :action => "new" }
format.xml { render :xml => @archive_file.errors, :status => :unprocessable_entity }
end
end
end
# PUT /archive_files/1
# PUT /archive_files/1.xml
def update
@archive_file = ArchiveFile.find(params[:id])
@archive_file.update_user_id = current_user.id
params[:archive_file][:tag_ids] ||=[]
respond_to do |format|
if @archive_file.update_attributes(params[:archive_file])
format.html { redirect_to(panel_archive_back_end_archive_files_url) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @archive_file.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /archive_files/1
# DELETE /archive_files/1.xml
def destroy
@archive_file = ArchiveFile.find(params[:id])
@archive_file.destroy
respond_to do |format|
format.html { redirect_to(panel_archive_back_end_archive_files_url) }
# format.xml { head :ok }
format.js
end
end
protected
def get_categorys(id = nil)
@archive_file_categorys = (id ? ArchiveFileCategory.find(id).to_a : ArchiveFileCategory.excludes('disabled' => true))
end
def get_tags
module_app = ModuleApp.first(:conditions => {:key => 'archive'})
@tags = Tag.all(:conditions => {:module_app_id => module_app.id})
end
end
@@ -0,0 +1,8 @@
class Panel::Archive::BackEnd::TagsController < Admin::TagsController
def initialize
super
@app_title = 'archive'
end
end
@@ -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
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,66 @@
# encoding: utf-8
class ArchiveFile
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::MultiParameterAttributes
PAYMENT_TYPES = @site_valid_locales
field :title, localize: true
has_and_belongs_to_many :tags, :class_name => "ArchiveTag"
field :create_user_id
field :update_user_id
field :is_top, :type => Boolean, :default => false
field :is_hot, :type => Boolean, :default => false
field :is_hidden, :type => Boolean, :default => false
scope :can_display,where(is_hidden: false)
belongs_to :archive_file_category
has_many :archive_file_multiples, :autosave => true, :dependent => :destroy
accepts_nested_attributes_for :archive_file_multiples, :allow_destroy => true
validates_presence_of :title
after_save :save_archive_file_multiples
def self.search( category_id = nil )
if category_id.to_s.size > 0
find(:all, :conditions => {archive_file_category_id: category_id}).desc( :is_top, :title )
else
find(:all).desc( :is_top, :title)
end
end
def self.widget_datas
where( :is_hidden => false ).desc(:is_top, :title)
end
def is_top?
self.is_top
end
def save_archive_file_multiples
self.archive_file_multiples.each do |t|
if t.should_destroy
t.destroy
end
end
end
end
@@ -0,0 +1,14 @@
# encoding: utf-8
class ArchiveFileCategory
include Mongoid::Document
include Mongoid::Timestamps
# include Mongoid::MultiParameterAttributes
field :key
has_one :i18n_variable, :as => :language_value, :autosave => true, :dependent => :destroy
has_many :archive_files
end
@@ -0,0 +1,26 @@
class ArchiveFileMultiple
include Mongoid::Document
include Mongoid::Timestamps
mount_uploader :file, AssetUploader
field :file_title, localize: true
# field :description
field :choose_lang, :type => Array, :default => nil
# has_one :i18n_variable, :as => :language_value, :autosave => true, :dependent => :destroy
field :should_destroy, :type => Boolean
def choose_lang_display(lang)
self.choose_lang.include?(lang)
end
belongs_to :archive_file
# has_many :archive_file_multiple_langs, :autosave => true, :dependent => :destroy
# accepts_nested_attributes_for :archive_file_multiple_langs, :allow_destroy => true
end
@@ -0,0 +1,10 @@
class ArchiveTag < Tag
has_and_belongs_to_many :archive_files
def get_visible_links(sort = :name)
self.archive_files.where(:is_hidden => false).desc(:is_top, sort)
end
end
Whitespace-only changes.
@@ -0,0 +1,16 @@
<tr id="<%= dom_id archive_file_category %>" class="with_action">
<td>
<%= archive_file_category.key %>
<div class="quick-edit">
<ul class="nav nav-pills hide">
<li><%= link_to t('archive_file_category.edit'), edit_panel_archive_back_end_archive_file_category_path(archive_file_category), :remote => true %></li>
<li><%= link_to t('archive_file_category.delete'), panel_archive_back_end_archive_file_category_path(archive_file_category), :confirm => t('announcement.sure?'), :method => :delete, :remote => true %></li>
</ul>
</div>
</td>
<% @site_valid_locales.each do |locale| %>
<td><%= archive_file_category.i18n_variable[locale] rescue nil %></td>
<% end %>
</tr>
@@ -0,0 +1,30 @@
<% # encoding: utf-8 %>
<%= form_for(@archive_file_category, :remote => true, :url => @url) do |f| %>
<h2><%= (@archive_file_category.new_record? ? 'Add' : 'Edit') %></h2>
<div id="widget-title">
<%= f.label :key %>
<%= f.text_field :key %>
</div>
<div id="widget-title">
<%= f.fields_for :i18n_variable, (@archive_file_category.new_record? ? @archive_file_category.build_i18n_variable : @archive_file_category.i18n_variable) do |f| %>
<% @site_valid_locales.each do |locale| %>
<div class="control-group">
<%= label_tag "name-#{locale}", "Name-#{I18nVariable.from_locale(locale)}", :class => 'control-label' %>
<div class="controls">
<%= f.text_field locale, :class => 'input-xxlarge' %>
</div>
</div>
<% end %>
<% end %>
</div>
<div class="form-actions">
<%= f.submit 'Submit/送出', :class=>'btn btn-primary' %>
</div>
<% end %>
@@ -0,0 +1,2 @@
$('<%= j render :partial => 'archive_file_category', :collection => [@archive_file_category] %>').appendTo('#archive_file_categorys').hide().fadeIn();
$("#new_archive_file_category")[0].reset();
@@ -0,0 +1 @@
$("#<%= dom_id @archive_file_category %>").remove();
@@ -0,0 +1 @@
$("#form > form").replaceWith("<%= j render "form" %>");
@@ -0,0 +1,23 @@
<%= flash_messages %>
<table id="archive_file_categorys" class="table main-list">
<thead>
<tr>
<th class="span1-2"><%= t('archive_file_category.key') %></th>
<% @site_valid_locales.each do |locale| %>
<th class="span1-2"><%= I18nVariable.first(:conditions => {:key => locale})[I18n.locale] %></th>
<% end %>
</tr>
</thead>
<tbody>
<%= render :partial => 'archive_file_category', :collection => @archive_file_categorys %>
</tbody>
</table>
<div id="form"><%= render :partial => "form" %></div>
@@ -0,0 +1 @@
$("#form > form").replaceWith("<%= j render "form" %>");
@@ -0,0 +1,4 @@
$("#<%= dom_id @archive_file_category %>").replaceWith("<%= j render :partial => 'link_category', :collection => [@archive_file_category] %>");
<% @archive_file_category = WebLinkCategory.new(:display => 'List') # reset for new form %>
$(".edit_archive_file_category").replaceWith("<%= j render "form" %>")
$(".new_archive_file_category")[0].reset();
@@ -0,0 +1,30 @@
<tr id="<%= dom_id post %>" class="with_action">
<td>
<% if post.is_top? %>
<span class="label label-success"><%= t(:top) %></span>
<% end %>
<% if post.is_hot? %>
<span class="label label-important"><%= t(:hot) %></span>
<% end %>
<% if post.is_hidden? %>
<span class="label"><%= t(:hidden) %></span>
<% end %>
<div class="quick-edit">
<ul class="nav nav-pills hide">
<li><%= link_to t('archive_file.edit'), edit_panel_archive_back_end_archive_file_path(post) %></li>
<li><%= link_to t('archive_file.delete'), panel_archive_back_end_archive_file_path(post), :confirm => t('sure?'), :method => :delete, :remote => true %></li>
</ul>
</div>
</td>
<td><%= post.archive_file_category.i18n_variable[I18n.locale] %></td>
<td>
<%= link_to post.title, panel_archive_front_end_archive_file_path(post) %>
</td>
<td>
<% post.tags.each do |tag| %>
<span class="label label-tags"><%= tag[I18n.locale] %></span>
<% end %>
</td>
</tr>
@@ -0,0 +1,149 @@
<% # encoding: utf-8 %>
<%= f.error_messages %>
<!--Widget start-->
<div id="sub-wiget">
<div id="widget-status" class="widget-box widget-size-300">
<div class="widget-action clear">
<a class="action"><i title="Setting the announcement state" class="icon-exclamation-sign icon-white tip"></i></a>
</div>
<h3 class="widget-title"><i class="icons-star-thin icons-white"></i>Status</h3>
<div class="widget-content clear">
<div class="controls">
<%= f.check_box :is_top %><%= t('top') %>
<%= f.check_box :is_hot %><%= t('hot') %>
<%= f.check_box :is_hidden %><%= t('hide') %>
</div>
</div>
</div>
<div id="widget-tags" class="widget-box widget-size-300">
<div class="widget-action clear">
<a class="action"><i title="Setting" class="icon-cog icon-white tip"></i></a>
</div>
<h3 class="widget-title"><i class="icons-tag icons-white"></i>Tags</h3>
<div class="widget-content clear form-horizontal">
<% @tags.each do |tag| %>
<%= check_box_tag 'archive_file[tag_ids][]', tag.id, @archive_file.tag_ids.include?(tag.id)%>
<%= tag[I18n.locale] %>
<% end %>
</div>
</div>
</div>
<!--Wiget End-->
<!--Post Start-->
<div id="post-body">
<div id="post-body-content" class="clear">
<%= f.label :category %>
<%= f.select :archive_file_category_id, @archive_file_categorys.collect {|t| [ t.i18n_variable[I18n.locale], t.id ]} %>
<ul class="nav nav-tabs">
<% @site_valid_locales.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>
<% end %>
</ul>
<div class="tab-content">
<% @site_valid_locales.each_with_index do |locale, i| %>
<div class="<%= locale %> fade tab-pane <%= ( i == 0 ) ? "in active" : '' %>">
<div class="title">
<%= f.label :title %>
<%= f.fields_for :title_translations do |f| %>
<%= I18nVariable.from_locale(locale) %>
<%= f.text_field locale, :class=>'post-title', :value => (@archive_file.title_translations[locale] rescue nil) %>
<% end %>
</div>
</div>
<% end %>
</div>
<div>
<div id='archive_file_multiples' class="archive_file_multiples_block">
<table class="table table-condensed">
<thead>
<tr>
<th>File</th>
<th>File Name</th>
<th class="span2"><%= t('呈現語系')%></th>
<th class="span1"></th>
</tr>
</thead>
<tfoot>
<tr>
<td style="text-align:center" colspan="4">
<div id='add_archive_file_multiple' class="info_input archive_file_multiples_block">
<%= hidden_field_tag 'archive_file_multiple_field_count', @archive_file.archive_file_multiples.count %>
<a class="add"><span class="btn btn-primary btn-small"><i class="icon-plus icon-white"></i> ADD/新增</span></a>
</div>
</td>
</tr>
</tfoot>
<tbody>
<% @archive_file.archive_file_multiples.each_with_index do |archive_file_multiple, i| %>
<%= f.fields_for :archive_file_multiples, archive_file_multiple do |f| %>
<%= render :partial => 'form_file', :object => archive_file_multiple, :locals => {:f => f, :i => i} %>
<% end %>
<% end %>
</tbody>
</table>
</div>
</div>
</div>
<!--Post End-->
<div class="form-actions">
<%= f.submit t('submit'), :class=>'btn btn-primary' %>
<%= link_to t('cancel'), get_go_back, :class=>"btn" %>
</div>
</div>
<% content_for :page_specific_javascript do %>
<%= javascript_include_tag "archive_form" %>
<script>
$('#add_archive_file_multiple a.add').live('click', function(){
var new_id = $(this).prev().attr('value');
var old_id = new RegExp("new_archive_file_multiples", "g");
$(this).prev().attr('value', parseInt(new_id) + 1);
$(this).parents('table').append(("<%= escape_javascript(add_attribute 'form_file', f, :archive_file_multiples) %>").replace(old_id, new_id));
});
$('.archive_file_multiples_block a.delete').live('click', function(){
$(this).parents('.list_item').remove();
});
$('.action a.remove_existing_record').live('click', function(){
$(this).next('.should_destroy').attr('value', 1);
$("tr#archive_file_" + $(this).prev().attr('value')).hide();
});
</script>
<% end %>
@@ -0,0 +1,57 @@
<% # encoding: utf-8 %>
<tr id="<%= "archive_file_multiple_#{form_file.id}" if !form_file.new_record? %>" class='list_item'>
<td>
<div class="control-group">
<div class="controls">
<%= 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>
</td>
<td>
<div class="tab-content">
<% @site_valid_locales.each_with_index do |locale, i| %>
<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 :file_title_translations do |f| %>
<div class="control-group">
<label for="link-<%= locale %>" class="control-label"><%= I18nVariable.from_locale(locale) %></label>
<div class="controls">
<%= f.text_field locale, :class=>'post-file_title', :value => (form_file.file_title_translations[locale] rescue nil) %>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
</td>
<td>
<% @site_valid_locales.each do |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) %>
<% end %>
<%= hidden_field_tag 'archive_file[archive_file_multiples_attributes][0][choose_lang][]', '' %>
</td>
<td>
<span class="action">
<% if form_file.new_record? %>
<a class="delete"><i class="icon-remove"></i></a>
<% else %>
<%= f.hidden_field :id %>
<a class="remove_existing_record"><i class="icon-remove"></i></a>
<%= f.hidden_field :should_destroy, :value => nil, :class => 'should_destroy' %>
<% end %>
</span>
</td>
</tr>
@@ -0,0 +1 @@
$("#<%= dom_id @archive_file %>").remove();
@@ -0,0 +1,5 @@
<h1><%= t('archive.editing_archive') %></h1>
<%= form_for @archive_file, :url => panel_archive_back_end_archive_file_path(@archive_file), :html => {:class => 'clear'} do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<% end %>
@@ -0,0 +1,23 @@
<%= flash_messages %>
<table class="table main-list">
<thead>
<tr>
<th class="span1-2"><%= t('archive_file.status') %></th>
<th class="span1-2"><%= t('archive_file.category') %></th>
<th class="span1-2"><%= t('archive_file.title') %></th>
<th class="span1-2"><%= t('archive_file.tags') %></th>
</tr>
</thead>
<tbody>
<% @archive_files.each do |post| %>
<%= render :partial => 'archive_files', :locals => {:post => post} %>
<% end %>
</tbody>
</table>
<%= paginate @archive_files %>
@@ -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('&nbsp;');
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());
}
}
});
}));
@@ -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"
}
};
@@ -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});
}
});
});
}
});
@@ -0,0 +1,9 @@
<%= flash_messages %>
<h1><%= t('archive_file.new_archive') %></h1>
<%= form_for @archive_file, :url => panel_archive_back_end_archive_files_path, :html => {:class => 'clear'} do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<% end %>
<%#= link_back %>
@@ -0,0 +1,57 @@
<% # encoding: utf-8 %>
<br />
<br />
<br />
<p id="notice"><%= flash_messages %></p>
<ul>
<li>
<b><%= t('announcement.category') %></b>
<%= @bulletin.bulletin_category.i18n_variable[I18n.locale] %>
</li>
<li>
<b><%= t('announcement.postdate') %></b>
<%= @bulletin.postdate %>
</li>
<li>
<b><%= t('announcement.title') %></b>
<%= @bulletin.title %>
</li>
<li>
<%#= image_tag(@bulletin.image.url, :size => "320x240") if @bulletin.image.file %>
<%= link_to image_tag(@bulletin.image.url, :size => "320x240"), @bulletin.image.url, {:target => '_blank', :title => @bulletin.image_identifier} if @bulletin.image.file %>
</li>
<li>
<b><%= t('announcement.subtitle') %></b>
<%= @bulletin.subtitle %>
</li>
<li>
<b><%= t('announcement.text') %></b>
<%= @bulletin.text %>
</li>
<li>
<li>
<b><%= t('announcement.link') %></b>
<% @bulletin.bulletin_links.each do | blink | %>
<%= link_to blink.name, blink.url, :target => '_blank' %>
<% end %>
</li>
<li>
<b><%= t('announcement.file') %></b>
<% @bulletin.bulletin_files.each do | bfile | %>
<%= link_to bfile.filetitle, bfile.file.url, {:target => '_blank', :title => bfile.description} if bfile.file.file %>
<% end %>
</li>
<li>
<b><%= t('announcement.張貼者') %></b>
<%= User.find(@bulletin.create_user_id).name %>
</li>
<li>
<b><%= t('announcement.最後修改時間') %></b>
<%= @bulletin.updated_at %>
</li>
<%= link_back %>
@@ -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 %>
@@ -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 %>
+23
View File
@@ -0,0 +1,23 @@
$:.push File.expand_path("../lib", __FILE__)
# Maintain your gem's version:
require "archive/version"
# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
s.name = "archive"
s.version = Archive::VERSION
s.authors = ["TODO: Your name"]
s.email = ["TODO: Your email"]
s.homepage = "TODO"
s.summary = "TODO: Summary of Archive."
s.description = "TODO: Description of Archive."
s.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.rdoc"]
s.test_files = Dir["test/**/*"]
s.add_dependency "rails", "~> 3.1.4"
# s.add_dependency "jquery-rails"
s.add_development_dependency "sqlite3"
end
+12
View File
@@ -0,0 +1,12 @@
{
"title": "archive",
"version": "0.1",
"organization": "Rulingcom",
"author": "RD dep",
"intro": "Archive",
"update_info": "Some info",
"create_date": "11-11-2011",
"app_pages": ["archive_files"],
"widgets": {"archive_files":[]},
"enable_frontend": true
}
+129
View File
@@ -0,0 +1,129 @@
# Sample localization file for English. Add more files in this directory for other locales.
# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
en:
_locale: English
add: Add
back: Back
create: Create
delete: Delete
disable: Disable
downloaded: Downloaded
download: Download
edit: Edit
enable: Enable
hide: Hide
homepage: Homepage
no_: "No"
nothing: Nothing
show: Show
sure?: Are you sure?
update: Update
yes_: "Yes"
announcement:
sure?: Sure?
# admin:
# action: Action
# add_language: Add language
# admin: Admin
# action: Action
# announcement: Announcement
# asset: Asset
# attributes: Attributes
# cant_delete_self: You can not delete yourself.
# cant_revoke_self_admin: You can not revoke your admin role yourself.
# class: Class
# content: Content
# create_error_link: Error when creating link.
# create_error_page: Error when creating page.
# create_success_home: Homepage was successfully created.
# create_success_layout: Layout was successfully created.
# create_success_link: Link was successfully created.
# create_success_page: Page was successfully created.
# create_success_snippet: Snippet was successfully created.
# create_success_user: User was successfully created.
# data: Data
# delete_language: Delete language
# description: Description
# design: Design
# disable_language: Disable language
# editing_home: Editing homepage
# editing_layout: Editing layout
# editing_link: Editing link
# editing_page: Editing page
# editing_snippet: Editing snippet
# editing_user_info: Editing user information
# editing_user_role: Editing user role
# email: Email
# enable_language: Enable language
# file_name: Filename
# file_size: File size
# format: Format
# home: Home
# id: ID
# info: Information
# is_published: Is published
# item: Item
# key: Key
# language: Language
# layout: Layout
# layout_name: Layout name
# list_assets: Assets list
# list_designs: Designs list
# list_items: Items list
# list_puchases: Purchases list
# list_snippets: Snippets list
# list_users: Users list
# list_user_infos: User information list
# list_user_roles: User roles list
# member: Member
# move_down: Move down
# move_up: Move up
# multilingual: Multilingual
# my_avatar: My Avatar
# no_home_page: You don't have a homepage
# no_layout: You don't have a layout
# name: Name
# new_asset: New asset
# new_component: New component
# new_home: New homepage
# new_layout: New layout
# new_link: New link
# new_page: New page
# new_snippet: New snippet
# new_user: New user
# new_user_info: New user information
# new_user_role: New user role
# non_multilingual: Non multilingual
# options: Options
# orig_upload_file: Original filename
# position: Position
# published?: Published?
# purchase: Purchase
# registered: Registered
# role: Role
# roles: Roles
# title: Title
# translation: Translation
# type: Type
# up_to_date: Up-to-date
# update_error_link: Error when updating link.
# update_error_page: Error when updating page.
# update_success_content: Content was successfully updated.
# update_success_home: Homepage was successfully updated.
# update_success_layout: Layout was successfully updated.
# update_success_link: Link was successfully updated.
# update_success_page: Page was successfully updated.
# update_success_snippet: Snippet was successfully updated.
# update_success_user: User was successfully updated.
# url: URL
# user: User
# user_info: User information
# user_panel: User panel
# user_role: User role
panel:
+330
View File
@@ -0,0 +1,330 @@
zh_tw:
_locale: 中文
add: 新增
back: 回去
create: 創造
delete: 刪除
disable: 禁用
edit: 編輯
enable: 啟用
hide: 隱藏
homepage: 首頁
no_: "No"
nothing: 無
show: 顯示
sure?: 您肯定嗎?
update: 更新
yes_: "Yes"
admin:
action: 行動
add_language: 新增語言
admin: 管理
action: 行動
announcement: 公告
asset: 資產
attributes: 屬性
cant_delete_self: 您不可以刪除自己。
cant_revoke_self_admin: 您不可以撤銷自己的管理作用。
class: 階級
content: 內容
create_error_link: 創建連接時出錯。
create_error_page: 創建頁面時出錯。
create_success_home: 首頁已成功創建。
create_success_layout: 樣板已成功創建。
create_success_link: 連結已成功創建。
create_success_page: 頁面已成功創建。
create_success_snippet: 片段已成功創建
create_success_user: 用戶已成功創建。。
data: 數據
delete_language: 刪除語言
description: 描述
disable_language: 禁用語言
editing_home: 編輯首頁
editing_layout: 編輯樣板
editing_link: 編輯連結
editing_page: 編輯頁面
editing_snippet: 編輯片段
editing_user_info: 編輯用戶資料
editing_user_role: 編輯用戶角色
email: Email
enable_language: 啟用語言
file_name: 檔名
file_size: 檔案大小
format: 格式
home: 首頁
id: ID
info: 資料
is_published: 被出版
item: 項目
key: 關鍵
language: 語言
layout: 佈局
layout_name: 佈局名字
list_assets: 資產清單
list_items: 項目清單
list_layouts: 佈局清單
list_snippets: 斷片清單
list_users: 使用清單
list_user_infos: 用戶資料清單
list_user_roles: 用戶角色清單
member: 會員
move_down: 往下移
move_up: 往上移
multilingual: 多種語言
my_avatar: 我的頭像
no_home_page: 您沒有首頁
no_layout: 您沒有佈局
name: 名稱
new_asset: 新增資產
new_component: 新增元件
new_home: 新增首頁
new_layout: 新增樣板
new_link: 新增連結
new_page: 新增頁面
new_snippet: 新增片段
new_user: 新增使用
new_user_info: 新增用戶資料
new_user_role: 新增用戶角色
non_multilingual: 非多種語言
options: 選項
orig_upload_file: 原上傳檔名
position: 位置
published?: 發布?
role: 角色
roles: 角色。
title: 標題
translation: 翻譯
type: 類型
update_error_link: 更新鏈接時出現錯誤。
update_error_page: 更新頁面時出現錯誤。
update_success_content: 內容已成功更新。
update_success_home: 首頁已成功更新。
update_success_layout: 樣板已成功更新。
update_success_link: 連結已成功更新。
update_success_page: 頁面已成功更新。
update_success_snippet: 片段已成功更新。
update_success_user: 用戶已成功更新
url: URL
user: 用戶
user_info: 用戶資料
user_panel: 用戶面板
user_role: 用戶角色
panel:
# Chinese (Taiwan) translations for Ruby on Rails
# by tsechingho (http://github.com/tsechingho)
date:
formats:
default: "%Y-%m-%d"
short: "%b%d日"
long: "%Y年%b%d日"
day_names: [星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六]
abbr_day_names: [日, 一, 二, 三, 四, 五, 六]
month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月]
abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月]
order: [ :year, :month, :day ]
time:
formats:
default: "%Y年%b%d日 %A %H:%M:%S %Z"
short: "%b%d日 %H:%M"
long: "%Y年%b%d日 %H:%M"
am: "上午"
pm: "下午"
datetime:
distance_in_words:
half_a_minute: "半分鐘"
less_than_x_seconds:
one: "不到一秒"
other: "不到 %{count} 秒"
x_seconds:
one: "一秒"
other: "%{count} 秒"
less_than_x_minutes:
one: "不到一分鐘"
other: "不到 %{count} 分鐘"
x_minutes:
one: "一分鐘"
other: "%{count} 分鐘"
about_x_hours:
one: "大約一小時"
other: "大約 %{count} 小時"
x_days:
one: "一天"
other: "%{count} 天"
about_x_months:
one: "大約一個月"
other: "大約 %{count} 個月"
x_months:
one: "一個月"
other: "%{count} 個月"
about_x_years:
one: "大約一年"
other: "大約 %{count} 年"
over_x_years:
one: "一年多"
other: "%{count} 年多"
almost_x_years:
one: "接近一年"
other: "接近 %{count} 年"
prompts:
year: "年"
month: "月"
day: "日"
hour: "時"
minute: "分"
second: "秒"
number:
format:
separator: "."
delimiter: ","
precision: 3
significant: false
strip_insignificant_zeros: false
currency:
format:
format: "%u %n"
unit: "NT$"
separator: "."
delimiter: ","
precision: 2
significant: false
strip_insignificant_zeros: false
percentage:
format:
delimiter: ""
precision:
format:
delimiter: ""
human:
format:
delimiter: ""
precision: 1
significant: false
strip_insignificant_zeros: false
storage_units:
format: "%n %u"
units:
byte:
one: "Byte"
other: "Bytes"
kb: "KB"
mb: "MB"
gb: "GB"
tb: "TB"
decimal_units:
format: "%n %u"
units:
# 10^-21 zepto, 10^-24 yocto
atto: "渺" # 10^-18
femto: "飛" # 10^-15 毫微微
pico: "漠" # 10^-12 微微
nano: "奈" # 10^-9 毫微
micro: "微" # 10^-6
mili: "毫" # 10^-3 milli
centi: "厘" # 10^-2
deci: "分" # 10^-1
unit: ""
ten:
one: "十"
other: "十" # 10^1
hundred: "百" # 10^2
thousand: "千" # 10^3 kilo
million: "百萬" # 10^6 mega
billion: "十億" # 10^9 giga
trillion: "兆" # 10^12 tera
quadrillion: "千兆" # 10^15 peta
# 10^18 exa, 10^21 zetta, 10^24 yotta
support:
array:
words_connector: ", "
two_words_connector: " 和 "
last_word_connector: ", 和 "
select:
prompt: "請選擇"
activerecord:
errors:
template: # ~ 2.3.5 backward compatible
header:
one: "有 1 個錯誤發生使得「%{model}」無法被儲存。"
other: "有 %{count} 個錯誤發生使得「%{model}」無法被儲存。"
body: "以下欄位發生問題:"
full_messages:
format: "%{attribute} %{message}"
messages:
inclusion: "沒有包含在列表中"
exclusion: "是被保留的關鍵字"
invalid: "是無效的"
confirmation: "不符合確認值"
accepted: "必須是可被接受的"
empty: "不能留空"
blank: "不能是空白字元"
too_long: "過長(最長是 %{count} 個字)"
too_short: "過短(最短是 %{count} 個字)"
wrong_length: "字數錯誤(必須是 %{count} 個字)"
not_a_number: "不是數字"
not_an_integer: "必須是整數"
greater_than: "必須大於 %{count}"
greater_than_or_equal_to: "必須大於或等於 %{count}"
equal_to: "必須等於 %{count}"
less_than: "必須小於 %{count}"
less_than_or_equal_to: "必須小於或等於 %{count}"
odd: "必須是奇數"
even: "必須是偶數"
taken: "已經被使用"
record_invalid: "校驗失敗: %{errors}"
activemodel:
errors:
template:
header:
one: "有 1 個錯誤發生使得「%{model}」無法被儲存。"
other: "有 %{count} 個錯誤發生使得「%{model}」無法被儲存。"
body: "以下欄位發生問題:"
errors:
format: "%{attribute} %{message}"
messages:
inclusion: "沒有包含在列表中"
exclusion: "是被保留的關鍵字"
invalid: "是無效的"
confirmation: "不符合確認值"
accepted: "必須是可被接受的"
empty: "不能留空"
blank: "不能是空白字元"
too_long: "過長(最長是 %{count} 個字)"
too_short: "過短(最短是 %{count} 個字)"
wrong_length: "字數錯誤(必須是 %{count} 個字)"
not_a_number: "不是數字"
not_an_integer: "必須是整數"
greater_than: "必須大於 %{count}"
greater_than_or_equal_to: "必須大於或等於 %{count}"
equal_to: "必須等於 %{count}"
less_than: "必須小於 %{count}"
less_than_or_equal_to: "必須小於或等於 %{count}"
odd: "必須是奇數"
even: "必須是偶數"
template:
header:
one: "有 1 個錯誤發生使得「%{model}」無法被儲存。"
other: "有 %{count} 個錯誤發生使得「%{model}」無法被儲存。"
body: "以下欄位發生問題:"
helpers:
select:
prompt: "請選擇"
submit:
create: "新增%{model}"
update: "更新%{model}"
submit: "儲存%{model}"
+22
View File
@@ -0,0 +1,22 @@
Rails.application.routes.draw do
namespace :panel do
namespace :archive do
namespace :back_end do
root :to => "archive_files#index"
resources :archive_files
resources :archive_file_categorys
resources :tags
end
namespace :front_end do
root :to => "archive_files#index"
resources :archive_files
end
namespace :widget do
match "archive_files" => "archive_files#index"
match "reload_archive_files" => "archive_files#reload_archive_files"
end
end
end
match "/appfront/*path" => redirect("/panel/*path")
end
+4
View File
@@ -0,0 +1,4 @@
require "archive/engine"
module Archive
end
@@ -1,4 +1,4 @@
module Announcement
module Archive
class Engine < Rails::Engine
end
end
@@ -1,3 +1,3 @@
module Announcement
module Archive
VERSION = "0.0.1"
end
@@ -0,0 +1,4 @@
# desc "Explaining what the task does"
# task :archive do
# # Task goes here
# end
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env ruby.exe
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
ENGINE_PATH = File.expand_path('../..', __FILE__)
load File.expand_path('../../test/dummy/script/rails', __FILE__)
+7
View File
@@ -0,0 +1,7 @@
require 'test_helper'
class ArchiveTest < ActiveSupport::TestCase
test "truth" do
assert_kind_of Module, Archive
end
end
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env rake
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
Dummy::Application.load_tasks
@@ -0,0 +1,9 @@
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require_tree .
@@ -0,0 +1,7 @@
/*
* This is a manifest file that'll automatically include all the stylesheets available in this directory
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
* the top of the compiled file, but it's generally better to create a new file per style scope.
*= require_self
*= require_tree .
*/
@@ -0,0 +1,3 @@
class ApplicationController < ActionController::Base
protect_from_forgery
end
@@ -0,0 +1,2 @@
module ApplicationHelper
end
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title>Dummy</title>
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
+4
View File
@@ -0,0 +1,4 @@
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
run Dummy::Application
@@ -0,0 +1,45 @@
require File.expand_path('../boot', __FILE__)
require 'rails/all'
Bundler.require
require "archive"
module Dummy
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# Activate observers that should always be running.
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]
# Enable the asset pipeline
config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
end
end
@@ -0,0 +1,10 @@
require 'rubygems'
gemfile = File.expand_path('../../../../Gemfile', __FILE__)
if File.exist?(gemfile)
ENV['BUNDLE_GEMFILE'] = gemfile
require 'bundler'
Bundler.setup
end
$:.unshift File.expand_path('../../../../lib', __FILE__)
@@ -0,0 +1,25 @@
# SQLite version 3.x
# gem install sqlite3
#
# Ensure the SQLite 3 gem is defined in your Gemfile
# gem 'sqlite3'
development:
adapter: sqlite3
database: db/development.sqlite3
pool: 5
timeout: 5000
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
adapter: sqlite3
database: db/test.sqlite3
pool: 5
timeout: 5000
production:
adapter: sqlite3
database: db/production.sqlite3
pool: 5
timeout: 5000
@@ -0,0 +1,5 @@
# Load the rails application
require File.expand_path('../application', __FILE__)
# Initialize the rails application
Dummy::Application.initialize!
@@ -0,0 +1,30 @@
Dummy::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false
# Print deprecation notices to the Rails logger
config.active_support.deprecation = :log
# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin
# Do not compress assets
config.assets.compress = false
# Expands the lines which load the assets
config.assets.debug = true
end
@@ -0,0 +1,60 @@
Dummy::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
# Code is not reloaded between requests
config.cache_classes = true
# Full error reports are disabled and caching is turned on
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Disable Rails's static asset server (Apache or nginx will already do this)
config.serve_static_assets = false
# Compress JavaScripts and CSS
config.assets.compress = true
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false
# Generate digests for assets URLs
config.assets.digest = true
# Defaults to Rails.root.join("public/assets")
# config.assets.manifest = YOUR_PATH
# Specifies the header that your server uses for sending files
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
# See everything in the log (default is :info)
# config.log_level = :debug
# Use a different logger for distributed setups
# config.logger = SyslogLogger.new
# Use a different cache store in production
# config.cache_store = :mem_cache_store
# Enable serving of images, stylesheets, and JavaScripts from an asset server
# config.action_controller.asset_host = "http://assets.example.com"
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
# config.assets.precompile += %w( search.js )
# Disable delivery errors, bad email addresses will be ignored
# config.action_mailer.raise_delivery_errors = false
# Enable threaded mode
# config.threadsafe!
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation can not be found)
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners
config.active_support.deprecation = :notify
end
@@ -0,0 +1,39 @@
Dummy::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Configure static asset server for tests with Cache-Control for performance
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
# Log error messages when you accidentally call methods on nil
config.whiny_nils = true
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Raise exceptions instead of rendering exception templates
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment
config.action_controller.allow_forgery_protection = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Use SQL instead of Active Record's schema dumper when creating the test database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types
# config.active_record.schema_format = :sql
# Print deprecation notices to the stderr
config.active_support.deprecation = :stderr
end
@@ -0,0 +1,7 @@
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!
@@ -0,0 +1,10 @@
# Be sure to restart your server when you modify this file.
# Add new inflection rules using the following format
# (all these examples are active by default):
# ActiveSupport::Inflector.inflections do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
@@ -0,0 +1,5 @@
# Be sure to restart your server when you modify this file.
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf
# Mime::Type.register_alias "text/html", :iphone
@@ -0,0 +1,7 @@
# Be sure to restart your server when you modify this file.
# Your secret key for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
Dummy::Application.config.secret_token = 'aec42790c63fdc0784df1572e74631a6f9c9d16729b813ecbd5f086eaab251cdf0bcba044a78b706d1f45d43c4ec5af5df5cc5ffd2ff7ca64953a5806ce49618'
@@ -0,0 +1,8 @@
# Be sure to restart your server when you modify this file.
Dummy::Application.config.session_store :cookie_store, key: '_dummy_session'
# Use the database for sessions instead of the cookie-based default,
# which shouldn't be used to store highly confidential information
# (create the session table with "rails generate session_migration")
# Dummy::Application.config.session_store :active_record_store
@@ -0,0 +1,14 @@
# Be sure to restart your server when you modify this file.
#
# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json]
end
# Disable root element in JSON by default.
ActiveSupport.on_load(:active_record) do
self.include_root_in_json = false
end
@@ -0,0 +1,5 @@
# Sample localization file for English. Add more files in this directory for other locales.
# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
en:
hello: "Hello world"
@@ -0,0 +1,58 @@
Dummy::Application.routes.draw do
# The priority is based upon order of creation:
# first created -> highest priority.
# Sample of regular route:
# match 'products/:id' => 'catalog#view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
# This route can be invoked with purchase_url(:id => product.id)
# Sample resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Sample resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Sample resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Sample resource route with more complex sub-resources
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', :on => :collection
# end
# end
# Sample resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
# root :to => 'welcome#index'
# See how all your routes lay out with "rake routes"
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
# match ':controller(/:action(/:id(.:format)))'
end
Loaded 100 of 2087 files, more files were not shown because too many files have changed in this diff. Show more