diff --git a/Gemfile.lock b/Gemfile.lock index e52990e2a..d30eb7bc4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -19,6 +19,7 @@ PATH rails GEM + remote: https://rubygems.org/ remote: https://rubygems.org/ specs: actionmailer (3.2.13) @@ -61,6 +62,10 @@ GEM xpath (~> 1.0.0) childprocess (0.5.3) ffi (~> 1.0, >= 1.0.11) + climate_control (0.0.3) + activesupport (>= 3.0) + cocaine (0.5.4) + climate_control (>= 0.0.3, < 1.0) coderay (1.0.9) coffee-rails (3.2.2) coffee-script (>= 2.2.0) @@ -74,12 +79,16 @@ GEM fastercsv (1.5.0) ffi (1.9.3-x86-mingw32) hike (1.2.3) + htmlentities (4.3.2) i18n (0.6.1) journey (1.0.4) jquery-rails (2.0.3) railties (>= 3.1.0, < 5.0) thor (~> 0.14) json (1.8.0) + kaminari (0.16.1) + actionpack (>= 3.0.0) + activesupport (>= 3.0.0) mail (2.5.4) mime-types (~> 1.16) treetop (~> 1.4.8) @@ -91,6 +100,11 @@ GEM mysql2 (0.3.11-x86-mingw32) net-ldap (0.3.1) nokogiri (1.5.11-x86-mingw32) + paperclip (3.5.4) + activemodel (>= 3.0.0) + activesupport (>= 3.0.0) + cocaine (~> 0.5.3) + mime-types polyglot (0.3.3) rack (1.4.5) rack-cache (1.2) @@ -98,6 +112,8 @@ GEM rack-openid (1.3.1) rack (>= 1.1.0) ruby-openid (>= 2.1.8) + rack-raw-upload (1.1.1) + multi_json rack-ssl (1.3.3) rack rack-test (0.6.2) @@ -120,6 +136,14 @@ GEM rake (10.3.2) rdoc (3.12.2) json (~> 1.4) + rich (1.4.6) + jquery-rails + kaminari + mime-types + paperclip + rack-raw-upload + rails (>= 3.2.0) + sass-rails rmagick (2.13.2) ruby-openid (2.1.8) rubyzip (1.1.4) @@ -170,15 +194,19 @@ DEPENDENCIES coderay (~> 1.0.6) coffee-rails (~> 3.2.1) fastercsv (~> 1.5.0) + htmlentities i18n (~> 0.6.0) jquery-rails (~> 2.0.2) + kaminari mocha (~> 0.13.3) mysql2 (= 0.3.11) net-ldap (~> 0.3.1) nokogiri (< 1.6.0) + paperclip (~> 3.5.4) rack-mini-profiler! rack-openid rails (= 3.2.13) + rich (= 1.4.6) rmagick (>= 2.0.0) ruby-openid (~> 2.1.4) sass-rails (~> 3.2.3) diff --git a/ReadMe.txt b/ReadMe.txt index 0fcba47c0..129b99216 100644 --- a/ReadMe.txt +++ b/ReadMe.txt @@ -50,4 +50,19 @@ app\controller\welcome_controller.rb 0606:新坑 user_scores表结构有问题,需要运行 bundle exec rake db:migrate:down VERSION=20140410021724 -bundle exec rake db:migrate:up VERSION=20140410021724 \ No newline at end of file +bundle exec rake db:migrate:up VERSION=20140410021724 +=============================================================================== +0708:CKEditor插件加载方法 +1.把插件文件夹拷入plugins文件夹,确保文件夹名为redmine_ckeditor +2.运行 bundle install --without development test +3.运行 rake redmine:plugins:migrate RAILS_ENV=production +4.启动服务器 +5.把文本格式 (Administration > Settings > General > Text formatting)改为CKEditor +6.配置CKEditor插件(Administration > Plugins > Configure) + +某些情况数据库未插入插件配置值解决方案: +1 复制plugins +2 启动rails +3 运行migrate +3 打开admin配置插件(http://127.0.0.1:3000/settings/plugin/redmine_ckeditor) +4 点击“查询”(就是确定的功能) \ No newline at end of file diff --git a/app/controllers/applied_project_controller.rb b/app/controllers/applied_project_controller.rb index fdb45b030..3d061ef74 100644 --- a/app/controllers/applied_project_controller.rb +++ b/app/controllers/applied_project_controller.rb @@ -6,7 +6,8 @@ class AppliedProjectController < ApplicationController @project = Project.find(params[:project_id]) @applieds = AppliedProject.where("user_id = ? and project_id = ?", params[:user_id],params[:project_id]) if @applieds.count == 0 - AppliedProject.create(:user_id => params[:user_id], :project_id => params[:project_id]) + appliedproject = AppliedProject.create(:user_id => params[:user_id], :project_id => params[:project_id]) + Mailer.applied_project(appliedproject).deliver end #redirect_to project_path(params[:project_id]) diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index 0b2ae02b3..b283b4792 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -23,6 +23,7 @@ class AttachmentsController < ApplicationController before_filter :login_without_softapplication, only: [:download] accept_api_auth :show, :download, :upload + require 'iconv' def show respond_to do |format| @@ -49,15 +50,36 @@ class AttachmentsController < ApplicationController end def download - if true || @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project) + # modify by nwb + # 下载添加权限设置 + candown = false + if @attachment.container.has_attribute?(:project) && @attachment.container.project + project = @attachment.container.project + candown= User.current.member_of?(project) + elsif @attachment.container.is_a?(Project) + project = @attachment.container + candown= User.current.member_of?(project) + elsif @attachment.container.has_attribute?(:course) && @attachment.container.course + course = @attachment.container.course + candown= User.current.member_of_course?(course) + elsif @attachment.container.is_a?(Course) + course = @attachment.container + candown= User.current.member_of_course?(course) + elsif @attachment.container.class.to_s=="HomeworkAttach" && @attachment.container.bid.reward_type == 3 + candown = true + end + if candown || User.current.admin? @attachment.increment_download + else + render_403 :message => :notice_not_authorized end + if stale?(:etag => @attachment.digest) # images are sent inline send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename), - :type => detect_content_type(@attachment), - :disposition => (@attachment.image? ? 'inline' : 'attachment') + :type => detect_content_type(@attachment), + :disposition => (@attachment.image? ? 'inline' : 'attachment') end rescue => e redirect_to "http://" + (Setting.host_name.to_s) +"/file_not_found.html" @@ -75,6 +97,25 @@ class AttachmentsController < ApplicationController end end + # 更新文件密级 + def updateFileDense + @attachment = Attachment.find(params[:attachmentid]) + if @attachment != nil + filedense = params[:newtype].to_s + # d = Iconv.conv("unicodebig","utf-8",filedense) + if filedense == "%E5%85%AC%E5%BC%80" #l(:field_is_public) + @attachment.is_public = 1 + else + @attachment.is_public = 0 + end + @attachment.save + @newfiledense = filedense + end + respond_to do |format| + format.js + end + end + def thumbnail if @attachment.thumbnailable? && thumbnail = @attachment.thumbnail(:size => params[:size]) if stale?(:etag => thumbnail) @@ -89,6 +130,7 @@ class AttachmentsController < ApplicationController end end + def upload # Make sure that API users get used to set this content type # as it won't trigger Rails' automatic parsing of the request body for parameters diff --git a/app/controllers/forums_controller.rb b/app/controllers/forums_controller.rb index f3ebfad88..3b8b4b928 100644 --- a/app/controllers/forums_controller.rb +++ b/app/controllers/forums_controller.rb @@ -166,10 +166,10 @@ class ForumsController < ApplicationController def search_forum # @forums = paginateHelper Forum.where("name LIKE '%#{params[:name]}%'") - name = params[:name] - (redirect_to forums_path, :notice => l(:label_sumbit_empty);return) if name.blank? + q = "%#{params[:name].strip}%" + (redirect_to forums_path, :notice => l(:label_sumbit_empty);return) if params[:name].blank? @offset, @limit = api_offset_and_limit({:limit => 10}) - @forums_all = Forum.where("name LIKE '%#{params[:name]}%'") + @forums_all = Forum.where("name LIKE ?", q) @forums_count = @forums_all.count @forums_pages = Paginator.new @forums_count, @limit, params['page'] @@ -185,11 +185,13 @@ class ForumsController < ApplicationController end def search_memo + q = "%#{params[:name].strip}%" + limit = PageLimit @memo = Memo.new @offset, @limit = api_offset_and_limit({:limit => limit}) @forum = Forum.find(params[:id]) - @memos_all = @forum.topics.where("subject LIKE '%#{params[:name]}%'") + @memos_all = @forum.topics.where("subject LIKE ?", q) @topic_count = @memos_all.count @topic_pages = Paginator.new @topic_count, @limit, params['page'] diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 62b736294..a840ee934 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -746,7 +746,7 @@ class ProjectsController < ApplicationController #Added by young # @course_tag = params[:course] # if @course_tag == '1' - @course = Course.find_by_extra(@project.identifier) + #@course = Course.find_by_extra(@project.identifier) # if @project.project_type == 1 # render :layout => 'base_courses' # else diff --git a/app/controllers/school_controller.rb b/app/controllers/school_controller.rb index c8b495fe2..8b3692449 100644 --- a/app/controllers/school_controller.rb +++ b/app/controllers/school_controller.rb @@ -98,16 +98,18 @@ class SchoolController < ApplicationController end def search_school - if params[:province].nil? or params[:province] == "0" - @school = School.where("name LIKE '%"+params[:key_word]+"%'"); - else - @school = School.where("province = ? AND name LIKE '%"+params[:key_word]+"%'", params[:province]); - end + q = "%#{params[:key_word].strip}%" + + @school = School.where("name LIKE ?", q) + @school = @school.where("province = ?", params[:province]) if (params[:province] != '0' ) + options = "" @school.each do |s| options << "
  • #{s.name}
  • " end - - render :text => options + + options = "
    #{l(:label_school_not_fount)}
    " if options.blank? + + render :text => options end end diff --git a/app/controllers/stores_controller.rb b/app/controllers/stores_controller.rb index fd0d3cf53..f34e72402 100644 --- a/app/controllers/stores_controller.rb +++ b/app/controllers/stores_controller.rb @@ -5,10 +5,10 @@ class StoresController < ApplicationController layout 'base_stores' def search - name = params[:name] ||= '' - (redirect_to stores_path, :notice => l(:label_sumbit_empty);return) if name.blank? + q = "%#{params[:name].strip}%" + (redirect_to stores_path, :notice => l(:label_sumbit_empty);return) if params[:name].blank? - result = find_public_attache name + result = find_public_attache q @searched_attach = paginateHelper result @result_all_count = result.count; end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 1c2db7f79..a3d512b5d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -255,112 +255,63 @@ class UsersController < ApplicationController #end def index - - @project_type = params[:project_type] - role = params[:role] - + @status = params[:status] || 1 sort_init 'login', 'asc' sort_update %w(login firstname lastname mail admin created_on last_login_on) + # Deprecation + @project_type = params[:project_type] + case params[:format] when 'xml', 'json' @offset, @limit = api_offset_and_limit({:limit => 15}) else - @limit = 15#per_page_option + @limit = 15 end - @status = params[:status] || 1 - has = { - "show_changesets" => true - } - # @count = Redmine::Activity::Fetcher.new(User.current, :author => @user).scope_select {|t| !has["show_#{t}"].nil?}.events(nil, nil).count - + # retrieve all users scope = UserStatus.visible - case role + + # if role has something, change scope. + case params[:role] when 'teacher' scope = UserStatus.teacher when 'student' scope = UserStatus.student else - end + # unknow scope = scope.in_group(params[:group_id]) if params[:group_id].present? - # scope.each do |user| - # UserStatus.create(:changesets_count => user.changesets.count, :watchers_count => user.watcher_users.count, :user_id => user.id) - # end + + # pagination @user_count = scope.count @user_pages = Paginator.new @user_count, @limit, params['page'] - #@offset ||= @user_pages.offset - #@users = scope.order(sort_clause).limit(@limit).offset(@offset).all - @user_base_tag = params[:id] ? 'base_users':'base' - if params[:user_sort_type].present? - case params[:user_sort_type] - when '0' - @offset ||= @user_pages.reverse_offset - unless @offset == 0 - @users_statuses = scope.offset(@offset).limit(@limit).all.reverse - else - limit = @user_count % @limit - if limit == 0 - limit = @limit - end - @users_statuses = scope.offset(@offset).limit(limit).all.reverse - end - @s_type = 0 - # @projects = @projects.sort {|x,y| y.created_on <=> x.created_on } - # @projects = @projects[@offset, @limit] - when '1' - @offset ||= @user_pages.reverse_offset - unless @offset == 0 - @users_statuses = scope.reorder('grade').offset(@offset).limit(@limit).all.reverse - else - limit = @user_count % @limit - if limit == 0 - limit = @limit - end - @users_statuses = scope.reorder('grade').offset(@offset).limit(limit).all.reverse - end - @s_type = 1 - #sort {|x,y| y.user_status.changesets_count <=> x.user_status.changesets_count} - #@users = @users[@offset, @limit] - when '2' - @offset ||= @user_pages.reverse_offset - unless @offset == 0 - @users_statuses = scope.reorder('watchers_count').offset(@offset).limit(@limit).all.reverse - else - limit = @user_count % @limit - if limit == 0 - limit = @limit - end - @users_statuses = scope.reorder('watchers_count').offset(@offset).limit(limit).all.reverse - end - @s_type = 2 - #@users = @users[@offset, @limit] - end + # users classify + case params[:user_sort_type] + when '0' + @s_type = 0 + @us_ordered = scope. + joins("LEFT JOIN users ON user_statuses.user_id = users.id"). + reorder('users.created_on DESC') + when '1' + @s_type = 1 + @us_ordered = scope.reorder('user_statuses.grade DESC') + when '2' + @s_type = 2 + @us_ordered = scope.reorder('user_statuses.watchers_count DESC') else - @offset ||= @user_pages.reverse_offset - unless @offset == 0 - @users_statuses = scope.reorder('grade').offset(@offset).limit(@limit).all.reverse - else - limit = @user_count % @limit - if limit == 0 - limit = @limit - end - @users_statuses = scope.reorder('grade').offset(@offset).limit(limit).all.reverse - end - @s_type = 1 - # @projects = @projects.sort {|x,y| y.created_on <=> x.created_on } - # @projects = @projects[@offset, @limit] - end - - @users = [] - @users_statuses.each do |obj| - @users << User.find_by_id("#{obj.user_id}") + @s_type = 1 + @us_ordered = scope.reorder('user_statuses.grade DESC') end - + + # limit and offset + @users_statuses = @us_ordered.offset(@user_pages.offset).limit(@user_pages.per_page) + # get users ActiveRecord + @users = @users_statuses.includes(:user).map(&:user) + @user_base_tag = params[:id] ? 'base_users':'base' respond_to do |format| format.html { @groups = Group.all.sort diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index b63381903..daaebe3ca 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1401,7 +1401,7 @@ module ApplicationHelper # Returns the javascript tags that are included in the html layout head def javascript_heads - tags = javascript_include_tag('jquery-1.8.3-ui-1.9.2-ujs-2.0.3', 'application') + tags = javascript_include_tag('jquery-1.8.3-ui-1.9.2-ujs-2.0.3', 'application', 'jquery.colorbox-min') unless User.current.pref.warn_on_leaving_unsaved == '0' tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });") end diff --git a/app/helpers/attachments_helper.rb b/app/helpers/attachments_helper.rb index 14105bf88..b43eb22f1 100644 --- a/app/helpers/attachments_helper.rb +++ b/app/helpers/attachments_helper.rb @@ -109,7 +109,7 @@ module AttachmentsHelper domain = project.nil? ? attachAll : nobelong_attach # 搜索到的资源 - searched_attach = domain.where("filename LIKE :like ", like:"%#{filename_condition}%").limit(limit).order('created_on desc') + searched_attach = domain.where("is_public=1 and filename LIKE :like ", like:"%#{filename_condition}%").limit(limit).order('created_on desc') #searched_attach = private_filter searched_attach searched_attach = paginateHelper(searched_attach, 10) @@ -148,7 +148,7 @@ module AttachmentsHelper domain = course.nil? ? attachAll : nobelong_attach # 搜索到的资源 - searched_attach = domain.where("filename LIKE :like ", like:"%#{filename_condition}%").limit(limit).order('created_on desc') + searched_attach = domain.where("is_public=1 and filename LIKE :like ", like:"%#{filename_condition}%").limit(limit).order('created_on desc') #searched_attach = private_filter searched_attach searched_attach = paginateHelper(searched_attach, 10) diff --git a/app/helpers/courses_helper.rb b/app/helpers/courses_helper.rb index 4b6a84b57..b4b89bb0f 100644 --- a/app/helpers/courses_helper.rb +++ b/app/helpers/courses_helper.rb @@ -343,6 +343,9 @@ module CoursesHelper #获取作业的互评得分 def student_score_for_homework homework member = searchTeacherAndAssistant(homework.bid.courses.first).first#searchPeopleByRoles(homework.bid.courses.first,TeacherRoles).first + if member.nil? + return "0.00" + end student_stars = homework.rates(:quality).where("rater_id <> #{member.user_id}").select("stars") student_stars_count = 0 student_stars.each do |star| @@ -354,6 +357,9 @@ module CoursesHelper #获取作业的教师评分 def teacher_score_for_homework homework member = searchTeacherAndAssistant(homework.bid.courses.first).first#searchPeopleByRoles(homework.bid.courses.first,TeacherRoles).first + if member.nil? + return "0.00" + end teacher_stars = homework.rates(:quality).where("rater_id = #{member.user_id}").select("stars").first return format("%.2f",teacher_stars == nil ? 0 : teacher_stars.stars) end diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 116e2de9a..0eb3e7666 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -196,6 +196,21 @@ class Attachment < ActiveRecord::Base suffix end + # 文件密级的字符描述 + def file_dense_str + if self.is_public == 1 + dense = l(:field_is_public) + else + dense = l(:field_is_private) + end + dense + end + + # 文件可设置的密级列表 + def file_dense_list + denselist = [l(:field_is_public),l(:field_is_private)] + end + def suffixArr @@SuffixArr end diff --git a/app/models/course.rb b/app/models/course.rb index 5034ab0d8..b6974eed0 100644 --- a/app/models/course.rb +++ b/app/models/course.rb @@ -90,6 +90,18 @@ class Course < ActiveRecord::Base false end + # Returns the mail adresses of users that should be always notified on project events + def recipients + notified_users.collect {|user| user.mail} + end + + # Returns the users that should be notified on project events + def notified_users + # TODO: User part should be extracted to User#notify_about? + members.select {|m| m.principal.present? && (m.mail_notification? || m.principal.mail_notification == 'all')}.collect {|m| m.principal} + end + + # 课程的短描述信息 def short_description(length = 255) description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description @@ -112,6 +124,7 @@ class Course < ActiveRecord::Base @attachmenttypes = Attachmentstype.find(:all, :conditions => ["#{Attachmentstype.table_name}.typeId= ?",self.attachmenttype ]) end + # 获取资源后缀名列表 def contenttypes attachmenttypes diff --git a/app/models/mailer.rb b/app/models/mailer.rb index ef4996eac..131c72c8c 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -141,6 +141,19 @@ class Mailer < ActionMailer::Base :subject => s end + # 用户申请加入项目邮件通知 + def applied_project(applied) + @project =applied.project + redmine_headers 'Project' => @project, + 'User' => applied.user + @user = applied.user + recipients = @project.manager_recipients + s = l(:text_applied_project, :id => "##{@user.show_name}", :project => @project.name) + @applied_url = url_for(:controller => 'projects', :action => 'settings', :id => @project.id,:tab=>'members') + mail :to => recipients, + :subject => s + end + def reminder(user, issues, days) set_language_if_valid user.language @issues = issues @@ -177,25 +190,45 @@ class Mailer < ActionMailer::Base added_to_url = '' @author = attachments.first.author case container.class.name - when 'Project' - added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container) - added_to = "#{l(:label_project)}: #{container}" - recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail} - when 'Version' - added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project) - added_to = "#{l(:label_version)}: #{container.name}" - recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail} - when 'Document' - added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id) - added_to = "#{l(:label_document)}: #{container.title}" - recipients = container.recipients + when 'Project' + added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container) + added_to = "#{l(:label_project)}: #{container}" + recipients = container.notified_users.select { |user| user.allowed_to?(:view_files, container) }.collect { |u| u.mail } + when 'Course' + added_to_url = url_for(:controller => 'files', :action => 'index', :course_id => container) + added_to = "#{l(:label_course)}: #{container}" + recipients = container.notified_users.select { |user| user.allowed_to?(:view_files, container) }.collect { |u| u.mail } + when 'Version' + added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project) + added_to = "#{l(:label_version)}: #{container.name}" + recipients = container.project.notified_users.select { |user| user.allowed_to?(:view_files, container.project) }.collect { |u| u.mail } + when 'Document' + added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id) + added_to = "#{l(:label_document)}: #{container.title}" + recipients = container.recipients + end + if container.class.name == 'Course' + redmine_headers 'Course' => container.id + @attachments = attachments + @added_to = added_to + @added_to_url = added_to_url + mail :to => recipients, + :subject => "[#{container.name}] #{l(:label_attachment_new)}" + elsif container.class.name == 'Project' + redmine_headers 'Project' => container.id + @attachments = attachments + @added_to = added_to + @added_to_url = added_to_url + mail :to => recipients, + :subject => "[#{container.name}] #{l(:label_attachment_new)}" + else + redmine_headers 'Project' => container.project.identifier + @attachments = attachments + @added_to = added_to + @added_to_url = added_to_url + mail :to => recipients, + :subject => "[#{container.project.name}] #{l(:label_attachment_new)}" end - redmine_headers 'Project' => container.project.identifier - @attachments = attachments - @added_to = added_to - @added_to_url = added_to_url - mail :to => recipients, - :subject => "[#{container.project.name}] #{l(:label_attachment_new)}" end # Builds a Mail::Message object used to email recipients of a news' project when a news item is added. diff --git a/app/models/project.rb b/app/models/project.rb index 5efaf10ab..37ca8f20b 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -207,6 +207,12 @@ class Project < ActiveRecord::Base end # end + # 管理员的邮件列表 + def manager_recipients + notified = project.project_infos.collect(&:user) + notified.collect(&:mail) + end + def initialize(attributes=nil, *args) super diff --git a/app/models/user_status.rb b/app/models/user_status.rb index f6dd0c8b6..3b4d38373 100644 --- a/app/models/user_status.rb +++ b/app/models/user_status.rb @@ -1,6 +1,6 @@ class UserStatus < ActiveRecord::Base attr_accessible :changesets_count, :user_id, :watchers_count - belongs_to :users + belongs_to :user belongs_to :watchers belongs_to :changesets validates_presence_of :user_id diff --git a/app/views/attachments/_form.html.erb b/app/views/attachments/_form.html.erb index d568dd63c..7f1887b23 100644 --- a/app/views/attachments/_form.html.erb +++ b/app/views/attachments/_form.html.erb @@ -3,10 +3,10 @@ <% container.attachments.each_with_index do |attachment, i| %> <%= text_field_tag("attachments[p#{i}][filename]", attachment.filename, :class => 'filename readonly', :readonly=>'readonly')%> - <%= text_field_tag("attachments[p#{i}][description]", attachment.description, :maxlength => 255, :placeholder => l(:label_optional_description), :class => 'description', :style=>"display: inline-block;") + link_to(' '.html_safe, attachment_path(attachment, :attachment_id => "p#{i}", :format => 'js'), :method => 'delete', :remote => true, :class => 'remove-upload') %> <%#= render :partial => 'tags/tag', :locals => {:obj => attachment, :object_flag => "6"} %> + <%= check_box_tag("attachments[p#{i}][is_public_checkbox]", attachment.is_public, :class => 'is_public')%> <%= hidden_field_tag "attachments[p#{i}][token]", "#{attachment.token}" %> <% end %> diff --git a/app/views/attachments/updateFileDense.js.erb b/app/views/attachments/updateFileDense.js.erb new file mode 100644 index 000000000..86fa36d4c --- /dev/null +++ b/app/views/attachments/updateFileDense.js.erb @@ -0,0 +1,15 @@ +$('#edit-file-dense-form-<%= @attachment.id.to_s%>').hide(); +$('#field_file_dense_id_label<%= @attachment.id.to_s%>').show(); +$('#edit_box_dense<%= @attachment.id.to_s%>').show(); +<%if @attachment.is_public == 1%> +$('#field_file_dense_id_label<%= @attachment.id.to_s%>').html('公开'); +<%else%> +$('#field_file_dense_id_label<%= @attachment.id.to_s%>').html('私有'); +<%end%> +// 下面2种写法都没起作用,暂时使用上面的非本地化模式 +// <%if @attachment.is_public == 1%> +// $('#field_file_dense_id_label<%= @attachment.id.to_s%>').html('<%l(:field_is_public)%>'); +// <%else%> +// $('#field_file_dense_id_label<%= @attachment.id.to_s%>').html('<%l(:field_is_private)%>'); +// <%end%> +// $('#field_file_dense_id_label<%= @attachment.id.to_s%>').html(<%=@newfiledense%>); diff --git a/app/views/courses/_course_form.html.erb b/app/views/courses/_course_form.html.erb index 77a3fde1b..79db56aab 100644 --- a/app/views/courses/_course_form.html.erb +++ b/app/views/courses/_course_form.html.erb @@ -1,19 +1,19 @@ - - + + <% object = [] %> @@ -23,68 +23,68 @@ <% unless @course.new_record? %> -

    <%= render :partial=>"avatar/avatar_form",:locals=> {source:@course} %>

    +

    <%= render :partial=>"avatar/avatar_form",:locals=> {source:@course} %>

    <% end %> - +

    - + - - - <%= f.fields_for @course do |m| %> + +<%= f.fields_for @course do |m| %> - - - + - <% unless @course.nil?%> -

    <%= l(:label_class_period) %> *   - <%= text_field_tag :class_period, @course.class_period, :placeholder => "在此输入课时" %>  <%= l(:label_class_hour)%> + <%# end %> + + <%# unless @course.nil?%> +

    <%#= l(:label_endup_time) %> *   + <%#= text_field_tag :endup_time, @course.endup_time, :placeholder => "在此选择结课日期" %> + <%#= calendar_for('endup_time')%>

    - <% else %> -

    <%= l(:label_class_period) %> *   - <%= text_field_tag :class_period, nil, :placeholder => "在此输入课时" %><%= l(:label_class_hour)%> + <%# else %> +

    <%#= l(:label_endup_time) %> *   + <%#= text_field_tag :endup_time, nil, :placeholder => "在此选择结课日期" %> + <%#= calendar_for('endup_time')%>

    - <% end %> - - - - -

    - - <% unless @course.nil? %> - <% if @course.time == 2008 %> -

    -
    <%= l(:label_term) %> *   - <%= select_tag 'time', " + <%# end %> + --> + <% unless @course.nil?%> +

    <%= l(:label_class_period) %> *   + <%= text_field_tag :class_period, @course.class_period, :placeholder => "在此输入课时" %>  <%= l(:label_class_hour)%> +

    + <% else %> +

    <%= l(:label_class_period) %> *   + <%= text_field_tag :class_period, nil, :placeholder => "在此输入课时" %><%= l(:label_class_hour)%> +

    + <% end %> + + + + +

    + + <% unless @course.nil? %> + <% if @course.time == 2008 %> +

    +
    <%= l(:label_term) %> *   + <%= select_tag 'time', " @@ -94,12 +94,12 @@ ".html_safe %>
    -

    - - <% elsif @course.time == 2009 %> -

    -
    <%= l(:label_term) %> *   - <%= select_tag 'time', " +

    + + <% elsif @course.time == 2009 %> +

    +
    <%= l(:label_term) %> *   + <%= select_tag 'time', " @@ -109,11 +109,11 @@ ".html_safe %>

    - - <% elsif @course.time == 2010 %> -

    -
    <%= l(:label_term) %> *   - <%= select_tag 'time', " + + <% elsif @course.time == 2010 %> +

    +
    <%= l(:label_term) %> *   + <%= select_tag 'time', " @@ -123,11 +123,11 @@ ".html_safe %>

    - - <% elsif @course.time == 2011 %> -

    -
    <%= l(:label_term) %> *   - <%= select_tag 'time', " + + <% elsif @course.time == 2011 %> +

    +
    <%= l(:label_term) %> *   + <%= select_tag 'time', " @@ -137,12 +137,12 @@ ".html_safe %>

    - - - <% elsif @course.time == 2012 %> -

    -
    <%= l(:label_term) %> *   - <%= select_tag 'time', " + + + <% elsif @course.time == 2012 %> +

    +
    <%= l(:label_term) %> *   + <%= select_tag 'time', " @@ -152,11 +152,11 @@ ".html_safe %>

    - - <% elsif @course.time == 2013 %> -

    -
    <%= l(:label_term) %> *   - <%= select_tag 'time', " + + <% elsif @course.time == 2013 %> +

    +
    <%= l(:label_term) %> *   + <%= select_tag 'time', " @@ -166,11 +166,11 @@ ".html_safe %>

    - - <% elsif @course.time == 2014 %> -

    -
    <%= l(:label_term) %> *   - <%= select_tag 'time', " + + <% elsif @course.time == 2014 %> +

    +
    <%= l(:label_term) %> *   + <%= select_tag 'time', " @@ -180,11 +180,11 @@ ".html_safe %>

    - - <% elsif @course.time == 2015 %> -

    -
    <%= l(:label_term) %> *   - <%= select_tag 'time', " + + <% elsif @course.time == 2015 %> +

    +
    <%= l(:label_term) %> *   + <%= select_tag 'time', " @@ -194,11 +194,11 @@ ".html_safe %>

    - - <% elsif @course.time == 2016 %> -

    -
    <%= l(:label_term) %> *   - <%= select_tag 'time', " + + <% elsif @course.time == 2016 %> +

    +
    <%= l(:label_term) %> *   + <%= select_tag 'time', " @@ -208,11 +208,11 @@ ".html_safe %>

    - - <% elsif @course.time == 2017 %> -

    -
    <%= l(:label_term) %> *   - <%= select_tag 'time', " + + <% elsif @course.time == 2017 %> +

    +
    <%= l(:label_term) %> *   + <%= select_tag 'time', " @@ -222,10 +222,10 @@ ".html_safe %>

    - <% else %> -

    - -
    <%= l(:label_term) %> *   - <%= select_tag 'time', " + <% else %> +

    +
    <%= l(:label_term) %> *   + <%= select_tag 'time', " @@ -235,72 +235,81 @@ ".html_safe %>

    - - <% end %> - <% end %> -
    - <% unless @course.nil? %> - <% if @course.term == l(:label_spring) %> -

    - +
    - <%= select_tag 'term', " + + <% end %> + <% end %> + + <% unless @course.nil? %> + <% if @course.term == l(:label_spring) %> +

    +
    + <%= select_tag 'term', " ".html_safe %>

    - - <% elsif @course.term == l(:label_summer)%> -

    -
    - <%= select_tag 'term', " + + <% elsif @course.term == l(:label_summer)%> +

    +
    + <%= select_tag 'term', " ".html_safe %>

    - - <% elsif @course.term == l(:label_autumn)%> -

    - <% end -%> <% container.attachments.each do |file| %> + <%if file.is_public == 0 && !User.current.member_of?(@project)%> + <%next%> + <%end%> "> @@ -45,6 +49,14 @@ + <% end -%> <% container.attachments.each do |file| %> + <%if file.is_public == 0 && !User.current.member_of?(@project)%> + <%next%> + <%end%> "> @@ -45,6 +49,14 @@ +
    - <%= select_tag 'term', " + + <% elsif @course.term == l(:label_autumn)%> +

    +
    + <%= select_tag 'term', " ".html_safe %>

    - - <% elsif @course.term == l(:label_winter)%> -

    -
    - <%= select_tag 'term', " + + <% elsif @course.term == l(:label_winter)%> +

    +
    + <%= select_tag 'term', " ".html_safe %>

    - - <% else %> -

    -
    - <%= select_tag 'term', " + + <% else %> +

    +
    + <%= select_tag 'term', " ".html_safe %>

    - - <% end %> - - <% end %>
    -

    - - - - - - - - - - - - - - - -

    - <%= l(:text_command) %> - <% end %> - + + <% end %> + + <% end %>
    +

    + + + + + + + + + + + + + + + +

    + <%= l(:text_command) %> +<% end %> + -

    +

    + + + + +

    <%= f.check_box :is_public, :style => "margin-left:10px;" %><%= l(:label_course_public_info) %>

    @@ -310,7 +319,7 @@ <%= wikitoolbar_for 'course_description' %> <% @course.custom_field_values.each do |value| %> -

    <%= custom_field_tag_with_label :course, value %>

    +

    <%= custom_field_tag_with_label :course, value %>

    <% end %> <%= call_hook(:view_courses_form, :course => @course, :form => f) %> @@ -319,8 +328,8 @@ <% unless @course.extra_frozen? %> - <% content_for :header_tags do %> - <%= javascript_include_tag 'course_identifier' %> - <% end %> + <% content_for :header_tags do %> + <%= javascript_include_tag 'course_identifier' %> + <% end %> <% end %> diff --git a/app/views/files/_course_file_dense_edit.html.erb b/app/views/files/_course_file_dense_edit.html.erb new file mode 100644 index 000000000..53041ef14 --- /dev/null +++ b/app/views/files/_course_file_dense_edit.html.erb @@ -0,0 +1,13 @@ +<% edit_allowed = User.current.allowed_to?(:manage_files, @course) %> +<% if file_dense_list.any? %> + + <%= link_to(image_tag('edit/edit.png'), 'javascript:void(0);',:style=>"white-space:nowrap;", :id=>"edit_box_dense"+attachment.id.to_s , + :onclick =>"$('#edit-file-dense-form-" +attachment.id.to_s+ "').show(); + $('#field_file_dense_id_label" +attachment.id.to_s+ "').hide(); + $('#edit_box_dense" +attachment.id.to_s+ "').hide();") if edit_allowed %> + +<% end %> + diff --git a/app/views/files/_course_show_all_attachment.html.erb b/app/views/files/_course_show_all_attachment.html.erb index 1a8a8ca65..a6da426c6 100644 --- a/app/views/files/_course_show_all_attachment.html.erb +++ b/app/views/files/_course_show_all_attachment.html.erb @@ -18,6 +18,7 @@ <%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc', :scope => "col", :id => "vzebra-children") %> <%= sort_header_tag('attach_type', :caption => l(:attachment_browse), :default_order => 'desc', :scope => "col", :id => "vzebra-attachmenttype") %> <%= sort_header_tag('content_type', :caption => l(:attachment_sufix_browse), :default_order => 'desc', :scope => "col", :id => "vzebra-contenttype") %> + <%= sort_header_tag('field_file_dense', :caption => l(:field_file_dense), :default_order => 'desc', :scope => "col", :id => "vzebra-field_file_dense") %> <%= sort_header_tag('downloads', :caption => l(:field_downloads), :default_order => 'desc', :scope => "col", :id => "vzebra-action") %> <%= sort_header_tag('operation', :caption => "", :scope => "col", :id => "vzebra-children") %> @@ -34,6 +35,9 @@
    <%= link_to_attachment file, :download => true, :title => file.filename+"\n"+file.description.to_s, :style => "width: 230px; overflow: hidden; white-space: nowrap;text-overflow: ellipsis;" %> <%= file.show_suffix_type %> + <%= file.file_dense_str %> +   + + <%= render :partial => 'course_file_dense_edit', :locals => {:file_dense_list => file.file_dense_list, + :attachment => file} %> + + <%= file.downloads %> diff --git a/app/views/files/_course_sort_by_attachtypel.html.erb b/app/views/files/_course_sort_by_attachtypel.html.erb index f73cac072..cda832493 100644 --- a/app/views/files/_course_sort_by_attachtypel.html.erb +++ b/app/views/files/_course_sort_by_attachtypel.html.erb @@ -5,66 +5,78 @@ <% edit_allowed = User.current.allowed_to?(:manage_files, @course) %> - - - - - - - + + + + + + + <%= sort_header_tag('filename', :caption => l(:field_filename), :scope => "col", :id => "vzebra-adventure") %> <%#= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc', :scope => "col", :id => "vzebra-comedy") %> <%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc', :scope => "col", :id => "vzebra-children") %> <%= sort_header_tag('attach_type', :caption => l(:attachment_browse), :default_order => 'desc', :scope => "col", :id => "vzebra-attachmenttype") %> - <%= sort_header_tag('content_type', :caption => l(:attachment_sufix_browse), :default_order => 'desc', :scope =>"col", :id=> "vzebra-contenttype")%> + <%= sort_header_tag('content_type', :caption => l(:attachment_sufix_browse), :default_order => 'desc', :scope => "col", :id => "vzebra-contenttype") %> + <%= sort_header_tag('field_file_dense', :caption => l(:field_file_dense), :default_order => 'desc', :scope => "col", :id => "vzebra-field_file_dense") %> <%= sort_header_tag('downloads', :caption => l(:field_downloads), :default_order => 'desc', :scope => "col", :id => "vzebra-action") %> <%= sort_header_tag('operation', :caption => "", :scope => "col", :id => "vzebra-children") %> - - + + <% @containers.each do |container| %> - <% next if container.attachments.empty? -%> - <% container.attachments.each do |file| %> - <% if isTypeOk(file,selAttachType,selContentType) %> - "> - - - - "> + + + + - - - - - - - - - <% end -%> - <% end -%> - <% reset_cycle %> - <% end -%> - - + + + + + + + + + + + <% end -%> + <% end -%> + <% reset_cycle %> + <% end -%> + +
    <%= link_to_attachment file, :download => true, :title => file.filename+"\n"+file.description.to_s, :style => "width: 230px; overflow: hidden; white-space: nowrap;text-overflow: ellipsis;" %><%= number_to_human_size(file.filesize) %> - <%= file.attachmentstype.typeName %> -   + <% next if container.attachments.empty? -%> + <% container.attachments.each do |file| %> + <% if file.is_public == 0 && !User.current.member_of?(@project) %> + <% next %> + <% end %> + <% if isTypeOk(file, selAttachType, selContentType) %> +
    <%= link_to_attachment file, :download => true, :title => file.filename+"\n"+file.description.to_s, :style => "width: 230px; overflow: hidden; white-space: nowrap;text-overflow: ellipsis;" %><%= number_to_human_size(file.filesize) %> + <%= file.attachmentstype.typeName %> +   <%= render :partial => 'attachments/course_type_edit', :locals => {:attachmenttypes => attachmenttypes, - :attachment => file,:contentype=>selContentType} %> + :attachment => file, :contentype => selContentType} %> - <%= file.show_suffix_type %><%= file.downloads %> - <%= link_to(image_tag('delete.png'), attachment_path(file), - :data => {:confirm => l(:text_are_you_sure)}, :method => :delete) if delete_allowed %> -
    -
    - <%# @preTags = %w|预设A 预设B 预设C 预设D 预设E 预设Z | %> - <%= render :partial => 'tags/tag', :locals => {:obj => file, :object_flag => "6"} %> -
    -
    - -
    <%= file.show_suffix_type %> + <%= file.file_dense_str %> +   + + <%= render :partial => 'course_file_dense_edit', :locals => {:file_dense_list => file.file_dense_list, + :attachment => file} %> + + <%= file.downloads %> + <%= link_to(image_tag('delete.png'), attachment_path(file), + :data => {:confirm => l(:text_are_you_sure)}, :method => :delete) if delete_allowed %> +
    +
    + <%# @preTags = %w|预设A 预设B 预设C 预设D 预设E 预设Z | %> + <%= render :partial => 'tags/tag', :locals => {:obj => file, :object_flag => "6"} %> +
    +
    + +
    diff --git a/app/views/files/_project_file_dense_edit.html.erb b/app/views/files/_project_file_dense_edit.html.erb new file mode 100644 index 000000000..daa4b927d --- /dev/null +++ b/app/views/files/_project_file_dense_edit.html.erb @@ -0,0 +1,13 @@ +<% edit_allowed = User.current.allowed_to?(:manage_files, @project) %> +<% if file_dense_list.any? %> + + <%= link_to(image_tag('edit/edit.png'), 'javascript:void(0);',:style=>"white-space:nowrap;", :id=>"edit_box_dense"+attachment.id.to_s , + :onclick =>"$('#edit-file-dense-form-" +attachment.id.to_s+ "').show(); + $('#field_file_dense_id_label" +attachment.id.to_s+ "').hide(); + $('#edit_box_dense" +attachment.id.to_s+ "').hide();") if edit_allowed %> + +<% end %> + diff --git a/app/views/files/_show_all_attachment.html.erb b/app/views/files/_show_all_attachment.html.erb index 07dc6a27f..8c624d176 100644 --- a/app/views/files/_show_all_attachment.html.erb +++ b/app/views/files/_show_all_attachment.html.erb @@ -18,6 +18,7 @@ <%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc', :scope => "col", :id => "vzebra-children") %> <%= sort_header_tag('attach_type', :caption => l(:attachment_browse), :default_order => 'desc', :scope => "col", :id => "vzebra-attachmenttype") %> <%= sort_header_tag('content_type', :caption => l(:attachment_sufix_browse), :default_order => 'desc', :scope => "col", :id => "vzebra-contenttype") %> + <%= sort_header_tag('field_file_dense', :caption => l(:field_file_dense), :default_order => 'desc', :scope => "col", :id => "vzebra-field_file_dense") %> <%= sort_header_tag('downloads', :caption => l(:field_downloads), :default_order => 'desc', :scope => "col", :id => "vzebra-action") %> <%= sort_header_tag('operation', :caption => "", :scope => "col", :id => "vzebra-children") %> @@ -34,6 +35,9 @@
    <%= link_to_attachment file, :download => true, :title => file.filename+"\n"+file.description.to_s, :style => "width: 230px; overflow: hidden; white-space: nowrap;text-overflow: ellipsis;" %> <%= file.show_suffix_type %> + <%= file.file_dense_str %> +   + + <%= render :partial => 'project_file_dense_edit', :locals => {:file_dense_list => file.file_dense_list, + :attachment => file} %> + + <%= file.downloads %> diff --git a/app/views/files/_sort_by_attachtypel.html.erb b/app/views/files/_sort_by_attachtypel.html.erb index 01c57c490..d3723c340 100644 --- a/app/views/files/_sort_by_attachtypel.html.erb +++ b/app/views/files/_sort_by_attachtypel.html.erb @@ -5,66 +5,78 @@ <% edit_allowed = User.current.allowed_to?(:manage_files, @project) %> - - - - - - - + + + + + + + <%= sort_header_tag('filename', :caption => l(:field_filename), :scope => "col", :id => "vzebra-adventure") %> <%#= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc', :scope => "col", :id => "vzebra-comedy") %> <%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc', :scope => "col", :id => "vzebra-children") %> <%= sort_header_tag('attach_type', :caption => l(:attachment_browse), :default_order => 'desc', :scope => "col", :id => "vzebra-attachmenttype") %> - <%= sort_header_tag('content_type', :caption => l(:attachment_sufix_browse), :default_order => 'desc', :scope =>"col", :id=> "vzebra-contenttype")%> + <%= sort_header_tag('content_type', :caption => l(:attachment_sufix_browse), :default_order => 'desc', :scope => "col", :id => "vzebra-contenttype") %> + <%= sort_header_tag('field_file_dense', :caption => l(:field_file_dense), :default_order => 'desc', :scope => "col", :id => "vzebra-field_file_dense") %> <%= sort_header_tag('downloads', :caption => l(:field_downloads), :default_order => 'desc', :scope => "col", :id => "vzebra-action") %> <%= sort_header_tag('operation', :caption => "", :scope => "col", :id => "vzebra-children") %> - - + + <% @containers.each do |container| %> - <% next if container.attachments.empty? -%> - <% container.attachments.each do |file| %> - <% if isTypeOk(file,selAttachType,selContentType) %> - "> - - - - "> + + + + - - - - - - - - - <% end -%> - <% end -%> - <% reset_cycle %> - <% end -%> - - + + + + + + + + + + + <% end -%> + <% end -%> + <% reset_cycle %> + <% end -%> + +
    <%= link_to_attachment file, :download => true, :title => file.filename+"\n"+file.description.to_s, :style => "width: 230px; overflow: hidden; white-space: nowrap;text-overflow: ellipsis;" %><%= number_to_human_size(file.filesize) %> - <%= file.attachmentstype.typeName %> -   + <% next if container.attachments.empty? -%> + <% container.attachments.each do |file| %> + <% if file.is_public == 0 && !User.current.member_of?(@project) %> + <% next %> + <% end %> + <% if isTypeOk(file, selAttachType, selContentType) %> +
    <%= link_to_attachment file, :download => true, :title => file.filename+"\n"+file.description.to_s, :style => "width: 230px; overflow: hidden; white-space: nowrap;text-overflow: ellipsis;" %><%= number_to_human_size(file.filesize) %> + <%= file.attachmentstype.typeName %> +   <%= render :partial => 'attachments/type_edit', :locals => {:attachmenttypes => attachmenttypes, - :attachment => file,:contentype=>selContentType} %> + :attachment => file, :contentype => selContentType} %> - <%= file.show_suffix_type %><%= file.downloads %> - <%= link_to(image_tag('delete.png'), attachment_path(file), - :data => {:confirm => l(:text_are_you_sure)}, :method => :delete) if delete_allowed %> -
    -
    - <%# @preTags = %w|预设A 预设B 预设C 预设D 预设E 预设Z | %> - <%= render :partial => 'tags/tag', :locals => {:obj => file, :object_flag => "6"} %> -
    -
    - -
    <%= file.show_suffix_type %> + <%= file.file_dense_str %> +   + + <%= render :partial => 'project_file_dense_edit', :locals => {:file_dense_list => file.file_dense_list, + :attachment => file} %> + + <%= file.downloads %> + <%= link_to(image_tag('delete.png'), attachment_path(file), + :data => {:confirm => l(:text_are_you_sure)}, :method => :delete) if delete_allowed %> +
    +
    + <%# @preTags = %w|预设A 预设B 预设C 预设D 预设E 预设Z | %> + <%= render :partial => 'tags/tag', :locals => {:obj => file, :object_flag => "6"} %> +
    +
    + +
    diff --git a/app/views/files/index.html.erb b/app/views/files/index.html.erb index b086b90db..69b41fc28 100644 --- a/app/views/files/index.html.erb +++ b/app/views/files/index.html.erb @@ -207,6 +207,23 @@ <%end%> } + + // 编辑文件密级 + function file_dense_edit(id, type) { + $.ajax({ + url: '<%=updateFileDense_attachments_path%>', + type: "POST", + remote:"true", + data: { + attachmentid: encodeURIComponent(id), + newtype: encodeURIComponent(type) + } + + }).complete(function (xhr, textStatus) { + }); + + } + diff --git a/app/views/issues/_form.html.erb b/app/views/issues/_form.html.erb index 8f9554107..86b6742d6 100644 --- a/app/views/issues/_form.html.erb +++ b/app/views/issues/_form.html.erb @@ -28,7 +28,7 @@ <% end %> <% if @issue.safe_attribute? 'description' %> -

    +

    <%= f.label_for_field :description, :required => @issue.required_attribute?('description') %> <%= link_to_function image_tag('edit.png'), '$(this).hide(); $("#issue_description_and_toolbar").show()' unless @issue.new_record? %> <%= content_tag 'span', :id => "issue_description_and_toolbar", :style => (@issue.new_record? ? nil : 'display:none') do %> diff --git a/app/views/mailer/applied_project.html.erb b/app/views/mailer/applied_project.html.erb new file mode 100644 index 000000000..4f266e6ce --- /dev/null +++ b/app/views/mailer/applied_project.html.erb @@ -0,0 +1,5 @@ +<%= l(:text_applied_project, :id => "##{@user.show_name}", :project => @project.name) %> +


    + +

    <%= link_to(h(@project.name), @applied_url) %>

    + diff --git a/app/views/mailer/applied_project.text.erb b/app/views/mailer/applied_project.text.erb new file mode 100644 index 000000000..7af8c2018 --- /dev/null +++ b/app/views/mailer/applied_project.text.erb @@ -0,0 +1,4 @@ +<%= l(:text_applied_project, :id => "##{@user.show_name}", :project => @project.name) %> + +

    <%= link_to(h(@project.name), @applied_url) %>

    + diff --git a/app/views/news/_course_form.html.erb b/app/views/news/_course_form.html.erb index 6e3060c3c..1f2198a3b 100644 --- a/app/views/news/_course_form.html.erb +++ b/app/views/news/_course_form.html.erb @@ -10,4 +10,4 @@

    <%= render :partial => 'attachments/form', :locals => {:container => @news} %>

    -<%= wikitoolbar_for 'news_description' %> +<%= wikitoolbar_for 'news_description'%> diff --git a/app/views/projects/_form.html.erb b/app/views/projects/_form.html.erb index ec0bf7fbf..420cc5100 100644 --- a/app/views/projects/_form.html.erb +++ b/app/views/projects/_form.html.erb @@ -5,14 +5,14 @@ <% end %>

    <%= f.text_field :name, :required => true, :size => 60, :style => "width:490px;" %>

    -

    +

    <%= f.text_area :description, :rows => 8, :class => 'wiki-edit', :style => "font-size:small;width:490px;margin-left:10px;" %>

    <%= f.text_field :identifier, :required => true, :size => 60, :style => "width:488px;", :disabled => @project.identifier_frozen?, :maxlength => Project::IDENTIFIER_MAX_LENGTH %> <% unless @project.identifier_frozen? %> <%= l(:text_length_between, :min => 1, :max => Project::IDENTIFIER_MAX_LENGTH) %> <%= l(:text_project_identifier_info).html_safe %> <% end %>

    - +

    <%= f.check_box :is_public, :style => "margin-left:10px;" %>

    <%= f.check_box :hidden_repo, :style => "margin-left:10px;" %>

    <%= f.text_field :project_type, :value => 0 %>

    diff --git a/app/views/stores/search.html.erb b/app/views/stores/search.html.erb index f65f04648..b75656f18 100644 --- a/app/views/stores/search.html.erb +++ b/app/views/stores/search.html.erb @@ -79,7 +79,7 @@ } } $(document).ready(function($) { - $('.cb span').highlight('<%=params[:name]%>'); + $('.cb span').highlight('<%="#{params[:name].strip}"%>'); $('.a_download_icon').each(function(){ $(this).mouseenter(function(event) { diff --git a/config/locales/en.yml b/config/locales/en.yml index 4c177b58e..6566564c9 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -233,6 +233,7 @@ en: field_mail: Email field_job_category: Job category # added by bai field_filename: File + field_file_dense: File Dense field_filesize: Size field_downloads: Downloads field_author: Author @@ -1079,6 +1080,7 @@ en: text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." text_project_closed: This project is closed and read-only. text_turning_multiple_off: "If you disable multiple values, multiple values will be removed in order to preserve only one value per item." + text_applied_project: "User %{id} Apply Join Project %{project}" default_role_manager: Manager default_role_developer: Developer @@ -1469,6 +1471,7 @@ en: label_teacher: Teacher label_student: Student label_school_all: Schools + label_school_not_fount: Not found by your input query condition. label_other: Other label_gender: Gender label_gender_male: male diff --git a/config/locales/zh.yml b/config/locales/zh.yml index 69af5cd2a..d3377fca9 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -251,6 +251,7 @@ zh: field_lastname_eg: '(例:张三丰,请填写[张])' field_mail: 邮件地址 field_filename: 文件 + field_file_dense: 文件密级 field_filesize: 大小 field_downloads: 下载次数 field_author: 作者 @@ -1127,6 +1128,7 @@ zh: text_own_membership_delete_confirmation: 你正在删除你现有的某些或全部权限,如果这样做了你可能将会再也无法编辑该项目了。你确定要继续吗? text_zoom_in: 放大 text_zoom_out: 缩小 + text_applied_project: "用户 %{id} 申请加入项目 %{project}" default_role_manager: 管理人员 default_role_developer: 开发人员 @@ -1866,6 +1868,7 @@ zh: #added by Wen label_school_all: 中国高校 + label_school_not_fount: 没有符合的高校信息 label_project_grade: 项目得分 diff --git a/config/routes.rb b/config/routes.rb index f6b391108..dfb8d503b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -515,6 +515,7 @@ RedmineApp::Application.routes.draw do resources :attachments, :only => [:show, :destroy] do collection do match "updateType" , via: [:get, :post] + match "updateFileDense" , via: [:get, :post] match "renderTag" , via: [:get, :post] end end diff --git a/config/settings.yml b/config/settings.yml index 8c9f55ae0..cffbaa5fa 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -251,3 +251,15 @@ course_domain: default: course.trustie.net repository_domain: default: repository.trustie.net +plugin_redmine_ckeditor: + serialized: true + default: --- !ruby/hash:ActiveSupport::HashWithIndifferentAccess + skin: moono + ui_color: ! '#f4f4f4' + width: '' + height: '400' + enter_mode: '1' + show_blocks: '1' + toolbar_can_collapse: '0' + toolbar_location: top + toolbar: Source,ShowBlocks,--,Undo,Redo,-,Find,Replace,--,Bold,Italic,Underline,Strike,-,Subscript,Superscript,-,NumberedList,BulletedList,-,Outdent,Indent,Blockquote,-,JustifyLeft,JustifyCenter,JustifyRight,JustifyBlock,-,Link,Unlink,-,richImage,Table,HorizontalRule,/,Styles,Format,Font,FontSize,-,TextColor,BGColor diff --git a/db/migrate/20140710024054_add_is_public_to_attachment.rb b/db/migrate/20140710024054_add_is_public_to_attachment.rb new file mode 100644 index 000000000..2276304c8 --- /dev/null +++ b/db/migrate/20140710024054_add_is_public_to_attachment.rb @@ -0,0 +1,5 @@ +class AddIsPublicToAttachment < ActiveRecord::Migration + def change + add_column :attachments, :is_public, :integer,:default => 1 + end +end diff --git a/db/migrate/20140710030426_update_attachment_public_attr.rb b/db/migrate/20140710030426_update_attachment_public_attr.rb new file mode 100644 index 000000000..339c52543 --- /dev/null +++ b/db/migrate/20140710030426_update_attachment_public_attr.rb @@ -0,0 +1,22 @@ +class UpdateAttachmentPublicAttr < ActiveRecord::Migration + def up + # 更新资源文件的is_public属性 + Attachment.all.each do |res| + if res.is_public + if(res.container.nil? || + (res.container.class.to_s=="Project" && res.container.is_public == false) || + (res.container.has_attribute?(:project) && res.container.project && res.container.project.is_public == false) || + (res.container.class.to_s=="HomeworkAttach" && res.container.bid.reward_type == 3) || + (res.container.class.to_s=="Course" && res.container.is_public == false) || + (res.container.has_attribute?(:course) && res.container.course && res.container.course.is_public == false) + ) + res.is_public = false + res.save + end + end + end + end + + def down + end +end diff --git a/db/schema.rb b/db/schema.rb index 8123e15de..9e21541c2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -12,6 +12,7 @@ # It's strongly recommended to check this file into your version control system. ActiveRecord::Schema.define(:version => 20140711012924) do +>>>>>>> 056f86caad29ca95632d9da9e1e616cd00e2349a create_table "activities", :force => true do |t| t.integer "act_id", :null => false @@ -51,6 +52,7 @@ ActiveRecord::Schema.define(:version => 20140711012924) do t.string "description" t.string "disk_directory" t.integer "attachtype", :default => 1 + t.integer "is_public", :default => 1 end add_index "attachments", ["author_id"], :name => "index_attachments_on_author_id" @@ -803,7 +805,7 @@ ActiveRecord::Schema.define(:version => 20140711012924) do end create_table "relative_memos", :force => true do |t| - t.integer "osp_id" + t.integer "osp_id", :null => false t.integer "parent_id" t.string "subject", :null => false t.text "content", :null => false @@ -840,6 +842,19 @@ ActiveRecord::Schema.define(:version => 20140711012924) do add_index "repositories", ["project_id"], :name => "index_repositories_on_project_id" + create_table "rich_rich_files", :force => true do |t| + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "rich_file_file_name" + t.string "rich_file_content_type" + t.integer "rich_file_file_size" + t.datetime "rich_file_updated_at" + t.string "owner_type" + t.integer "owner_id" + t.text "uri_cache" + t.string "simplified_type", :default => "file" + end + create_table "roles", :force => true do |t| t.string "name", :limit => 30, :default => "", :null => false t.integer "position", :default => 1 diff --git a/lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb b/lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb index 30bbaedda..1318f8afa 100644 --- a/lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb +++ b/lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb @@ -60,11 +60,28 @@ module Redmine @unsaved_attachments ||= [] end + # 设置资源文件的公开属性 + # add by nwb + def set_attachment_public(res) + # 公开的资源判断他的父级的公开属性 + if res.is_public + if( (self.class.to_s=="Project" && self.is_public == false) || + (self.has_attribute?(:project) && self.project && self.project.is_public == false) || + (self.class.to_s=="HomeworkAttach" && self.bid.reward_type == 3) || + (self.class.to_s=="Course" && self.is_public == false) || + (self.has_attribute?(:course) && self.course && self.course.is_public == false) + ) + res.is_public = false + end + end + end + def save_attachmentsex(attachments, author=User.current,attachment_type) @curattachment_type = attachment_type result = save_attachments(attachments,author) result end + def save_attachments(attachments, author=User.current) if attachments.is_a?(Hash) attachments = attachments.stringify_keys @@ -94,6 +111,10 @@ module Redmine a.filename = attachment['filename'] unless attachment['filename'].blank? a.content_type = attachment['content_type'] end + if !attachment[:is_public] + a.is_public = false + end + set_attachment_public(a) next unless a a.description = attachment['description'].to_s.strip a.attachtype = @curattachment_type; diff --git a/lib/redmine/views/labelled_form_builder.rb b/lib/redmine/views/labelled_form_builder.rb index 2bba17faf..22be40efe 100644 --- a/lib/redmine/views/labelled_form_builder.rb +++ b/lib/redmine/views/labelled_form_builder.rb @@ -43,7 +43,7 @@ class Redmine::Views::LabelledFormBuilder < ActionView::Helpers::FormBuilder return ''.html_safe if options.delete(:no_label) text = options[:label].is_a?(Symbol) ? l(options[:label]) : options[:label] text ||= l(("field_" + field.to_s.gsub(/\_id$/, "")).to_sym) - text += @template.content_tag("span", " *", :class => "required") if options.delete(:required) + text += @template.content_tag("span", "#{options.delete(:required) ? ' *' : '  '}".html_safe, :class => "required") @template.content_tag("label", text.html_safe, :class => (@object && @object.errors[field].present? ? "error" : nil), :for => (@object_name.to_s + "_" + field.to_s)) diff --git a/plugins/redmine_ckeditor/.gitmodules b/plugins/redmine_ckeditor/.gitmodules new file mode 100644 index 000000000..de30e7590 --- /dev/null +++ b/plugins/redmine_ckeditor/.gitmodules @@ -0,0 +1,3 @@ +[submodule "app/assets/javascripts/ckeditor-releases"] + path = app/assets/javascripts/ckeditor-releases + url = git://github.com/ckeditor/ckeditor-releases.git diff --git a/plugins/redmine_ckeditor/Gemfile b/plugins/redmine_ckeditor/Gemfile new file mode 100644 index 000000000..5071abd08 --- /dev/null +++ b/plugins/redmine_ckeditor/Gemfile @@ -0,0 +1,6 @@ +source 'https://rubygems.org' + +gem 'rich', '1.4.6' +gem 'kaminari' +gem 'htmlentities' +gem 'paperclip', '~> 3.5.4' diff --git a/plugins/redmine_ckeditor/README.rdoc b/plugins/redmine_ckeditor/README.rdoc new file mode 100644 index 000000000..9a05ed31f --- /dev/null +++ b/plugins/redmine_ckeditor/README.rdoc @@ -0,0 +1,69 @@ += Redmine CKEditor plugin + +This plugin adds the text formatting for using CKEditor to Redmine. + +Since version 1.0.0, it includes {Rich}[https://github.com/bastiaanterhorst/rich] and supports image uploads. + +== What is CKEditor? + +CKEditor is a WYSIWYG text editor. +See {the official site}[http://ckeditor.com/] for more details. + +== Requirements + +* Redmine 2.3.x, Ruby 1.9.2 or higher, {ImageMagick}[http://www.imagemagick.org/] (version {1.0.16}[https://github.com/a-ono/redmine_ckeditor]) + # Ubuntu + apt-get install imagemagick + # Mac OS X + brew install imagemagick + +* Redmine 2.3.x (version {0.4.0}[https://github.com/a-ono/redmine_ckeditor/tree/0.4.0]) + +* Redmine 2.2.x (version {0.3.0}[https://github.com/a-ono/redmine_ckeditor/tree/0.3.0]) + +* Redmine 2.1.x (version {0.2.1}[https://github.com/a-ono/redmine_ckeditor/tree/0.2.1]) + +* Redmine 2.0.x (version {0.1.1}[https://github.com/a-ono/redmine_ckeditor/tree/0.1.1]) + +* Redmine 1.1.0 - 1.4.2 (version {0.0.6}[https://github.com/a-ono/redmine_ckeditor/tree/0.0.6]) + +== Plugin installation and setup + +1. Copy the plugin directory into the plugins directory (make sure the name is redmine_ckeditor) +2. Install the required gems (in the Redmine root directory) + bundle install --without development test +3. Execute migration + rake redmine:plugins:migrate RAILS_ENV=production +4. Start Redmine +5. Change text formatting (Administration > Settings > General > Text formatting) to CKEditor +6. Configure the plugin (Administration > Plugins > Configure) + +=== Upgrade + +1. Replace the plugin directory (plugins/redmine_ckeditor) +2. Install the required gems + bundle install --without development test +3. Execute migration + rake redmine:plugins:migrate RAILS_ENV=production +4. Delete old assets + rm -r /public/plugin_assets/redmine_ckeditor +5. Restart Redmine + +== CKEditor customization + +=== Plugins + +You can download plugins from {Add-ons Repository}[http://ckeditor.com/addons/plugins/all]. +To activate the plugin you have to copy the plugin directory into assets/ckeditor-contrib/plugins and restart Redmine, then configure toolbar settings. + +=== Skins + +You can select third-party skins placed in assets/ckeditor-contrib/skins directory. + +== Migration notes + +This plugin stores contents in HTML format and renders as is. +If you have old contents, these look weird. + +You can use {redmine_per_project_formatting}[https://github.com/a-ono/redmine_per_project_formatting] plugin for backward compatibility or execute redmine_ckeditor:migrate task for migrating old text to HTML. + rake redmine_ckeditor:migrate RAILS_ENV=production [PROJECT=project_identifier1,project_identifier2] [FORMAT=textile] diff --git a/plugins/redmine_ckeditor/app/assets/javascripts/application.js b/plugins/redmine_ckeditor/app/assets/javascripts/application.js new file mode 100644 index 000000000..8a7148b3c --- /dev/null +++ b/plugins/redmine_ckeditor/app/assets/javascripts/application.js @@ -0,0 +1,5 @@ +// +//= require rich/editor/ckeditor_path +//= require ckeditor-releases/ckeditor +//= require rich/editor/rich_editor +//= require rich/editor/rich_picker diff --git a/plugins/redmine_ckeditor/app/assets/javascripts/browser.js b/plugins/redmine_ckeditor/app/assets/javascripts/browser.js new file mode 100644 index 000000000..29fa85da8 --- /dev/null +++ b/plugins/redmine_ckeditor/app/assets/javascripts/browser.js @@ -0,0 +1,4 @@ +//= require fileuploader +//= require rich/browser/extensions +//= require rich/browser/uploader +//= require rich/browser/filebrowser diff --git a/plugins/redmine_ckeditor/app/models/redmine_ckeditor_setting.rb b/plugins/redmine_ckeditor/app/models/redmine_ckeditor_setting.rb new file mode 100644 index 000000000..1472a874a --- /dev/null +++ b/plugins/redmine_ckeditor/app/models/redmine_ckeditor_setting.rb @@ -0,0 +1,69 @@ +class RedmineCkeditorSetting + def self.setting + Setting[:plugin_redmine_ckeditor] || {} + end + + def self.default + ["1", true].include?(setting[:default]) + end + + def self.toolbar_string + setting[:toolbar] || RedmineCkeditor.default_toolbar + end + + def self.toolbar + bars = [] + bar = [] + toolbar_string.split(",").each {|item| + case item + when '/' + bars.push(bar, item) + bar = [] + when '--' + bars.push(bar) + bar = [] + else + bar.push(item) + end + } + + bars.push(bar) unless bar.empty? + bars + end + + def self.skin + setting[:skin] || "moono" + end + + def self.ui_color + setting[:ui_color] || "#f4f4f4" + end + + def self.enter_mode + (setting[:enter_mode] || 1).to_i + end + + def self.shift_enter_mode + enter_mode == 2 ? 1 : 2 + end + + def self.show_blocks + (setting[:show_blocks] || 1).to_i == 1 + end + + def self.toolbar_can_collapse + setting[:toolbar_can_collapse].to_i == 1 + end + + def self.toolbar_location + setting[:toolbar_location] || "top" + end + + def self.width + setting[:width] + end + + def self.height + setting[:height] || 400 + end +end diff --git a/plugins/redmine_ckeditor/app/views/issues/update_form.js.erb b/plugins/redmine_ckeditor/app/views/issues/update_form.js.erb new file mode 100644 index 000000000..e7d3e2ad2 --- /dev/null +++ b/plugins/redmine_ckeditor/app/views/issues/update_form.js.erb @@ -0,0 +1,11 @@ +<% if RedmineCkeditor.enabled? %> + destroyEditor("issue_description"); +<% end %> + +$('#all_attributes').html('<%= escape_javascript(render :partial => 'form') %>'); + +<% if User.current.allowed_to?(:log_time, @issue.project) %> + $('#log_time').show(); +<% else %> + $('#log_time').hide(); +<% end %> diff --git a/plugins/redmine_ckeditor/app/views/journals/new_with_ckeditor.js.erb b/plugins/redmine_ckeditor/app/views/journals/new_with_ckeditor.js.erb new file mode 100644 index 000000000..592f9d1d7 --- /dev/null +++ b/plugins/redmine_ckeditor/app/views/journals/new_with_ckeditor.js.erb @@ -0,0 +1,9 @@ +<% + # when quoting a private journal, check the private checkbox + if @journal && @journal.private_notes? +%> +$('#issue_private_notes').attr('checked', true); +<% end %> + +CKEDITOR.instances['issue_notes'].setData(<%= @content.inspect.html_safe %>); +showAndScrollTo("update", "issue_notes"); diff --git a/plugins/redmine_ckeditor/app/views/layouts/rich/application.html.erb b/plugins/redmine_ckeditor/app/views/layouts/rich/application.html.erb new file mode 100644 index 000000000..16401252c --- /dev/null +++ b/plugins/redmine_ckeditor/app/views/layouts/rich/application.html.erb @@ -0,0 +1,16 @@ + + + + Rich Browser + <%= javascript_heads %> + <%= stylesheet_link_tag "application", :plugin => "redmine_ckeditor" %> + <%= ckeditor_javascripts %> + <%= javascript_include_tag "browser", :plugin => "redmine_ckeditor" %> + <%= csrf_meta_tags %> + + + +<%= yield %> + + + diff --git a/plugins/redmine_ckeditor/app/views/messages/quote_with_ckeditor.js.erb b/plugins/redmine_ckeditor/app/views/messages/quote_with_ckeditor.js.erb new file mode 100644 index 000000000..78c9a64e9 --- /dev/null +++ b/plugins/redmine_ckeditor/app/views/messages/quote_with_ckeditor.js.erb @@ -0,0 +1,2 @@ +<%= render :file => "messages/quote" %> +CKEDITOR.instances['message_content'].setData($('#message_content').val()); diff --git a/plugins/redmine_ckeditor/app/views/rich/files/_file.html.erb b/plugins/redmine_ckeditor/app/views/rich/files/_file.html.erb new file mode 100644 index 000000000..0bdd7372c --- /dev/null +++ b/plugins/redmine_ckeditor/app/views/rich/files/_file.html.erb @@ -0,0 +1,12 @@ +
  • + +

    <%= file.rich_file_file_name %>

    + <%= link_to "delete", file.id.to_s, :method => :delete, :remote => true, :confirm => t(:delete_confirm), :class => "delete", :title => t(:delete) %> +
  • diff --git a/plugins/redmine_ckeditor/app/views/settings/_ckeditor.html.erb b/plugins/redmine_ckeditor/app/views/settings/_ckeditor.html.erb new file mode 100644 index 000000000..fefe8212c --- /dev/null +++ b/plugins/redmine_ckeditor/app/views/settings/_ckeditor.html.erb @@ -0,0 +1,142 @@ +<%= ckeditor_javascripts %> +<%= stylesheet_link_tag 'editor', :plugin => 'redmine_ckeditor'%> +<%= stylesheet_link_tag 'selector', :plugin => 'redmine_ckeditor'%> +

    + <%= content_tag :label, l(:ckeditor_skin) %> + <%= select_tag "settings[skin]", RedmineCkeditor.skin_options %> +

    +

    + <%= content_tag :label, l(:ckeditor_ui_color) %> + <%= text_field_tag "settings[ui_color]", RedmineCkeditorSetting.ui_color %> +

    +

    + <%= content_tag :label, l(:ckeditor_width) %> + <%= text_field_tag "settings[width]", RedmineCkeditorSetting.width %> +

    +

    + <%= content_tag :label, l(:ckeditor_height) %> + <%= text_field_tag "settings[height]", RedmineCkeditorSetting.height %> +

    +

    + <%= content_tag :label, l(:ckeditor_enter_mode) %> + <%= select_tag "settings[enter_mode]", RedmineCkeditor.enter_mode_options %> +

    +

    + <%= content_tag :label, l(:ckeditor_startup_show_blocks) %> + <%= hidden_field_tag "settings[show_blocks]", 0 %> + <%= check_box_tag "settings[show_blocks]", 1, RedmineCkeditorSetting.show_blocks %> +

    +

    + <%= content_tag :label, l(:ckeditor_toolbar_can_collapse) %> + <%= hidden_field_tag "settings[toolbar_can_collapse]", 0 %> + <%= check_box_tag "settings[toolbar_can_collapse]", 1, RedmineCkeditorSetting.toolbar_can_collapse %> +

    +

    + <%= content_tag :label, l(:ckeditor_toolbar_location) %> + <%= select_tag "settings[toolbar_location]", RedmineCkeditor.toolbar_location_options %> +

    +

    + <%= content_tag :label, l(:ckeditor_toolbar_buttons) %> +

    + +
    + <%= hidden_field_tag "settings[toolbar]", RedmineCkeditorSetting.toolbar_string %> + + + +
    +
    +

    +
    +
    + +
    + + + +
    +
    +
    + +<%= javascript_tag do %> + function moveItem(from, to) { + from = $("#" + from); + to = $("#" + to); + var selected = to.find("option:selected").first(); + from.find("option:selected").remove().each(function() { + if (this.value == '-' || this.value == '--' || this.value == '/') return; + selected.size() ? selected.before(this) : to.append(this); + }); + to.prop("selectedIndex", -1); + changeHandler(); + } + + function addItem(item) { + var option = $("