Merge branch 'szzh' of http://repository.trustie.net/xianbo/trustie2 into szzh
Conflicts: app/controllers/repositories_controller.rb db/schema.rb
This commit is contained in:
commit
9b3ffc90ba
28
Gemfile.lock
28
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)
|
||||
|
|
17
ReadMe.txt
17
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
|
||||
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 点击“查询”(就是确定的功能)
|
|
@ -62,6 +62,7 @@ class AttachmentsController < ApplicationController
|
|||
end
|
||||
rescue => e
|
||||
redirect_to "http://" + (Setting.host_name.to_s) +"/file_not_found.html"
|
||||
return
|
||||
end
|
||||
|
||||
#更新资源文件类型
|
||||
|
|
|
@ -15,7 +15,7 @@ class BidsController < ApplicationController
|
|||
# end
|
||||
before_filter :require_login,:only => [:set_reward, :destroy, :add, :new, ]
|
||||
|
||||
before_filter :memberAccess, only: :show_project
|
||||
#before_filter :memberAccess, only: :show_project
|
||||
|
||||
helper :watchers
|
||||
helper :attachments
|
||||
|
@ -378,11 +378,6 @@ class BidsController < ApplicationController
|
|||
if membership.user.allowed_to?(:quote_project,membership.project)
|
||||
@option << membership.project
|
||||
end
|
||||
#membership.member_roles.each{|role|
|
||||
# if(role.role_id == 3)
|
||||
# @option << membership.project
|
||||
# end
|
||||
#}
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -457,14 +452,6 @@ class BidsController < ApplicationController
|
|||
if (User.current.logged? && User.current.member_of_course?(@bid.courses.first))
|
||||
# flash[:notice] = ""
|
||||
@membership = User.current.coursememberships.all(:conditions => Course.visible_condition(User.current))
|
||||
#@option = []
|
||||
#@membership.each do |membership|
|
||||
# membership.member_roles.each{|role|
|
||||
# if(role.role_id == 3)
|
||||
# @option << membership.course
|
||||
# end
|
||||
# }
|
||||
#end
|
||||
|
||||
@user = @bid.author
|
||||
@bidding_project = @bid.biding_projects.all
|
||||
|
|
|
@ -232,12 +232,7 @@ class ContestsController < ApplicationController
|
|||
# @contesting_project_pages = Paginator.new @contesting_project_count, per_page_option, params['page']
|
||||
@membership.each do |membership|
|
||||
unless(membership.project.project_type==1)
|
||||
#membership.member_roles.each{|role|
|
||||
# if(role.role_id == 3)
|
||||
# @option << membership.project
|
||||
# end
|
||||
#}
|
||||
if User.current.allowed_to?({:controller => "projects", :action => "edit"}, membership.project, :global => false)
|
||||
if User.current.allowed_to?(:quote_project, membership.project)
|
||||
@option << membership.project
|
||||
end
|
||||
end
|
||||
|
@ -326,13 +321,8 @@ class ContestsController < ApplicationController
|
|||
# @contesting_project_pages = Paginator.new @contesting_project_count, per_page_option, params['page']
|
||||
@membership.each do |membership|
|
||||
unless(membership.project.project_type==1)
|
||||
#membership.member_roles.each{|role|
|
||||
#if(role.role_id == 3)
|
||||
#@option << membership.project
|
||||
#end
|
||||
#}
|
||||
#拥有编辑项目权限的可将该项目参赛
|
||||
if User.current.allowed_to?({:controller => "projects", :action => "edit"}, membership.project, :global => false)
|
||||
if User.current.allowed_to?(:quote_project, membership.project)
|
||||
@option << membership.project
|
||||
end
|
||||
end
|
||||
|
|
|
@ -172,7 +172,7 @@ class CoursesController < ApplicationController
|
|||
## 有角色参数的才是课程,没有的就是项目
|
||||
@render_file = 'member_list'
|
||||
@teachers= searchTeacherAndAssistant(@course)
|
||||
@canShowCode = isCourseTeacher(User.current.id)
|
||||
@canShowCode = isCourseTeacher(User.current.id,@course)
|
||||
case params[:role]
|
||||
when '1'
|
||||
@subPage_title = l :label_teacher_list
|
||||
|
@ -643,7 +643,7 @@ class CoursesController < ApplicationController
|
|||
@sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category'
|
||||
#
|
||||
@teachers= searchTeacherAndAssistant(@course)
|
||||
@canShowRealName = isCourseTeacher(User.current.id)
|
||||
@canShowRealName = isCourseTeacher(User.current.id,@course)
|
||||
|
||||
if(User.find_by_id(CourseInfos.find_by_course_id(@course.id).try(:user_id)))
|
||||
@user = User.find_by_id(CourseInfos.find_by_course_id(@course.id).user_id)
|
||||
|
@ -656,9 +656,10 @@ class CoursesController < ApplicationController
|
|||
end
|
||||
|
||||
#判断指定用户是否为课程教师
|
||||
def isCourseTeacher(id)
|
||||
def isCourseTeacher(id,course)
|
||||
result = false
|
||||
if @teachers && @teachers.find_by_user_id(id) != nil
|
||||
user = User.find(id)
|
||||
if user.nil? && user.allowed_to?(:as_teacher,course)#@teachers && @teachers.count != 0 && @teachers.find_by_user_id(id) != nil
|
||||
result = true
|
||||
end
|
||||
result
|
||||
|
|
|
@ -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']
|
||||
|
||||
|
|
|
@ -169,7 +169,15 @@ class HomeworkAttachController < ApplicationController
|
|||
#users:该作业所有成员
|
||||
#q:模糊匹配的用户的昵称
|
||||
def members_for_homework homework,users,q
|
||||
homework.bid.courses.first.members.joins(:member_roles).where("member_roles.role_id IN (:role_id) and user_id not in (:users)", {:role_id => [5, 10],:users => users}).joins(:user).where("users.login like '%#{q}%'")
|
||||
#homework.bid.courses.first.members.joins(:member_roles).where("member_roles.role_id IN (:role_id) and user_id not in (:users)", {:role_id => [5, 10],:users => users}).joins(:user).where("users.login like '%#{q}%'")
|
||||
unpartin_users = homework.bid.courses.first.members.where("user_id not in (:users)", {:users => users}).joins(:user).where("users.login like '%#{q}%'")
|
||||
canpartin_users = []
|
||||
unpartin_users.each do |m|
|
||||
if m.user.allowed_to?(:paret_in_homework,homework.bid.courses.first)
|
||||
canpartin_users << m
|
||||
end
|
||||
end
|
||||
canpartin_users
|
||||
end
|
||||
|
||||
def edit
|
||||
|
|
|
@ -76,8 +76,10 @@ class MembersController < ApplicationController
|
|||
members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => user_id)
|
||||
user_grades << UserGrade.new(:user_id => user_id, :project_id => @project.id)
|
||||
## added by nie
|
||||
if (params[:membership][:role_ids] && params[:membership][:role_ids][0] == "3")
|
||||
project_info << ProjectInfo.new(:user_id => user_id, :project_id => @project.id)
|
||||
|
||||
if (params[:membership][:role_ids])
|
||||
role = Role.find(params[:membership][:role_ids][0])
|
||||
project_info << ProjectInfo.new(:user_id => user_id, :project_id => @project.id) if role.allowed_to?(:is_manager)
|
||||
# ProjectInfo.create(:name => "test", :user_id => 123)
|
||||
end
|
||||
## end
|
||||
|
@ -86,8 +88,9 @@ class MembersController < ApplicationController
|
|||
members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => params[:membership][:user_id])
|
||||
user_grades << UserGrade.new(:user_id => params[:membership][:user_id], :project_id => @project.id)
|
||||
## added by nie
|
||||
if (params[:membership][:role_ids] && params[:membership][:role_ids][0] == "3")
|
||||
project_info << ProjectInfo.new(:project_id => @project.id, :user_id => params[:membership][:user_id])
|
||||
if (params[:membership][:role_ids])
|
||||
role = Role.find(params[:membership][:role_ids][0])
|
||||
project_info << ProjectInfo.new(:project_id => @project.id, :user_id => params[:membership][:user_id]) if role.allowed_to?(:is_manager)
|
||||
end
|
||||
## end
|
||||
end
|
||||
|
@ -123,14 +126,16 @@ class MembersController < ApplicationController
|
|||
user_ids.each do |user_id|
|
||||
members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => user_id)
|
||||
#user_grades << UserGrade.new(:user_id => user_id, :course_id => @course.id)
|
||||
if (params[:membership][:role_ids] && params[:membership][:role_ids][0] == "3")
|
||||
course_info << CourseInfo.new(:user_id => user_id, :course_id => @course.id)
|
||||
if (params[:membership][:role_ids])
|
||||
role = Role.find(params[:membership][:role_ids][0])
|
||||
course_info << CourseInfo.new(:user_id => user_id, :course_id => @course.id) if role.allowed_to?(:is_manager)
|
||||
end
|
||||
end
|
||||
else
|
||||
members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => params[:membership][:user_id])
|
||||
if (params[:membership][:role_ids] && params[:membership][:role_ids][0] == "3")
|
||||
course_info << CourseInfo.new(:course_id => @course.id, :user_id => params[:membership][:user_id])
|
||||
if (params[:membership][:role_ids])
|
||||
role = Role.find(params[:membership][:role_ids][0])
|
||||
course_info << CourseInfo.new(:course_id => @course.id, :user_id => params[:membership][:user_id]) if role.allowed_to?(:is_manager)
|
||||
end
|
||||
end
|
||||
@course.members << members
|
||||
|
@ -162,14 +167,17 @@ class MembersController < ApplicationController
|
|||
@member.role_ids = params[:membership][:role_ids]
|
||||
|
||||
#added by nie
|
||||
if (params[:membership][:role_ids] && params[:membership][:role_ids][0] == "3")
|
||||
@projectInfo = ProjectInfo.new(:user_id => @member.user_id, :project_id => @project.id)
|
||||
@projectInfo.save
|
||||
else
|
||||
user_admin = ProjectInfo.where("user_id = ? and project_id = ?", @member.user_id, @project.id)
|
||||
if user_admin.size > 0
|
||||
user_admin.each do |user|
|
||||
user.destroy
|
||||
if (params[:membership][:role_ids])
|
||||
role = Role.find(params[:membership][:role_ids][0])
|
||||
if role.allowed_to?(:is_manager)
|
||||
@projectInfo = ProjectInfo.new(:user_id => @member.user_id, :project_id => @project.id)
|
||||
@projectInfo.save
|
||||
else
|
||||
user_admin = ProjectInfo.where("user_id = ? and project_id = ?", @member.user_id, @project.id)
|
||||
if user_admin.size > 0
|
||||
user_admin.each do |user|
|
||||
user.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -191,14 +199,17 @@ class MembersController < ApplicationController
|
|||
if params[:membership]
|
||||
@member.role_ids = params[:membership][:role_ids]
|
||||
|
||||
if (params[:membership][:role_ids] && params[:membership][:role_ids][0] == "3")
|
||||
@courseInfo = CourseInfos.new(:user_id => @member.user_id, :course_id => @course.id)
|
||||
@courseInfo.save
|
||||
else
|
||||
user_admin = CourseInfos.where("user_id = ? and course_id = ?", @member.user_id, @course.id)
|
||||
if user_admin.size > 0
|
||||
user_admin.each do |user|
|
||||
user.destroy
|
||||
if (params[:membership][:role_ids])
|
||||
role = Role.find(params[:membership][:role_ids][0])
|
||||
if role.allowed_to?(:is_manager)
|
||||
@courseInfo = CourseInfos.new(:user_id => @member.user_id, :course_id => @course.id)
|
||||
@courseInfo.save
|
||||
else
|
||||
user_admin = CourseInfos.where("user_id = ? and course_id = ?", @member.user_id, @course.id)
|
||||
if user_admin.size > 0
|
||||
user_admin.each do |user|
|
||||
user.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,11 +16,10 @@
|
|||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class PreviewsController < ApplicationController
|
||||
before_filter :find_project, :find_attachments, :find_contest, except: [:contestnotification]
|
||||
before_filter :find_project, :find_attachments, except: :contestnotification
|
||||
|
||||
def issue
|
||||
@issue = @project.issues.find_by_id(params[:id]) unless params[:id].blank?
|
||||
@issue = @contest.issues.find_by_id(params[:id]) unless params[:id].blank?
|
||||
if @issue
|
||||
@description = params[:issue] && params[:issue][:description]
|
||||
if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n")
|
||||
|
@ -65,12 +64,4 @@ class PreviewsController < ApplicationController
|
|||
render :partial => 'common/preview'
|
||||
end
|
||||
|
||||
private
|
||||
def find_contest
|
||||
contest_id = (params[:issue] && params[:issue][:contest_id]) || params[:contest_id]
|
||||
@contest = Contest.find(contest_id)
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render_404
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -729,8 +729,8 @@ class ProjectsController < ApplicationController
|
|||
@canShowRealName = isCourseTeacher(User.current.id)
|
||||
end
|
||||
|
||||
#勿删 real_name action为虚拟的该方法并不存在,用来辅助判断真名权限
|
||||
#勿删 @canShowRealName = User.current.allowed_to?({:controller => "projects", :action => "real_name"}, @project || @projects, :global => false)
|
||||
# real_name action为虚拟的该方法并不存在,用来辅助判断真名权限
|
||||
# @canShowRealName = User.current.allowed_to?({:controller => "projects", :action => "real_name"}, @project || @projects, :global => false)
|
||||
respond_to do |format|
|
||||
format.html{render :layout => 'base_courses' if @base_courses_tag==1}
|
||||
format.api
|
||||
|
|
|
@ -239,8 +239,8 @@ class RepositoriesController < ApplicationController
|
|||
@repositories = @project.repositories
|
||||
@course_tag = params[:course]
|
||||
project_path_cut = RepositoriesHelper::PROJECT_PATH_CUT
|
||||
ip = RepositoriesHelper::REPO_IP_ADDRESS
|
||||
@repos_url = "http://"+@repository.login.to_s+"_"+@repository.identifier.to_s+"@"+ip+
|
||||
ip = RepositoriesHelper::REPO_IP_ADDRESS
|
||||
@repos_url = "http://"+@repository.login.to_s+"_"+@repository.identifier.to_s+"@"+ip.to_s+
|
||||
@repository.url.slice(project_path_cut, @repository.url.length).to_s
|
||||
if @course_tag == 1
|
||||
render :action => 'show', :layout => 'base_courses'
|
||||
|
|
|
@ -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 << "<li style = 'width: 33%; float: left'> <a id=#{s.id} onclick='test(this.id)'>#{s.name}</a></li>"
|
||||
end
|
||||
|
||||
render :text => options
|
||||
|
||||
options = "<div class='flash error' id='flash_error'>#{l(:label_school_not_fount)}</div>" if options.blank?
|
||||
|
||||
render :text => options
|
||||
end
|
||||
end
|
||||
|
|
|
@ -108,14 +108,8 @@ class SoftapplicationsController < ApplicationController
|
|||
# @contesting_project_pages = Paginator.new @contesting_project_count, per_page_option, params['page']
|
||||
@membership.each do |membership|
|
||||
unless(membership.project.project_type==1)
|
||||
#membership.member_roles.each{|role|
|
||||
# if(role.role_id == 3)
|
||||
# @option << membership.project
|
||||
# end
|
||||
#}
|
||||
|
||||
#拥有编辑项目权限的可操作该项目
|
||||
if User.current.allowed_to?({:controller => "projects", :action => "edit"}, membership.project, :global => false)
|
||||
if User.current.allowed_to?(:quote_project,membership.project)
|
||||
@option << membership.project
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -26,7 +26,7 @@ class TestController < ApplicationController
|
|||
end
|
||||
|
||||
def courselist
|
||||
@courses = Project.course_entities
|
||||
@courses = paginateHelper Course.includes(:homeworks).all, 10
|
||||
end
|
||||
|
||||
def ziping files_path
|
||||
|
|
|
@ -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]
|
||||
@s_type = 1
|
||||
@us_ordered = scope.reorder('user_statuses.grade DESC')
|
||||
end
|
||||
|
||||
@users = []
|
||||
@users_statuses.each do |obj|
|
||||
@users << User.find_by_id("#{obj.user_id}")
|
||||
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
|
||||
|
|
|
@ -1396,7 +1396,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
|
||||
|
|
|
@ -7,26 +7,27 @@ module CoursesHelper
|
|||
3. define search by roles
|
||||
4. define search member function
|
||||
=end
|
||||
TeacherRoles = [3, 4, 7, 9]
|
||||
StudentRoles = [5, 10]
|
||||
AllPeople = StudentRoles+TeacherRoles
|
||||
#TeacherRoles = [3, 4, 7, 9]
|
||||
#StudentRoles = [5, 10]
|
||||
#AllPeople = StudentRoles+TeacherRoles
|
||||
## return people count
|
||||
|
||||
# 返回x项目成员数量,即roles表中定义的所有成员
|
||||
def projectCount project
|
||||
searchCountByRoles project, AllPeople
|
||||
#searchCountByRoles project, AllPeople
|
||||
project.members.count
|
||||
end
|
||||
|
||||
# 返回教师数量,即roles表中定义的Manager
|
||||
def teacherCount project
|
||||
searchCountByRoles project, TeacherRoles
|
||||
searchTeacherAndAssistant(project).count
|
||||
# or
|
||||
# searchTeacherAndAssistant(project).count
|
||||
end
|
||||
|
||||
# 返回学生数量,即roles表中定义的Reporter
|
||||
def studentCount project
|
||||
searchCountByRoles project,StudentRoles
|
||||
searchStudent(project).count
|
||||
# or
|
||||
# searchStudent(project).count
|
||||
end
|
||||
|
@ -133,29 +134,39 @@ module CoursesHelper
|
|||
# =====================================================================================
|
||||
# return people list
|
||||
def searchTeacherAndAssistant project
|
||||
searchPeopleByRoles(project, TeacherRoles)
|
||||
end
|
||||
|
||||
def searchStudent project
|
||||
searchPeopleByRoles(project, StudentRoles)
|
||||
end
|
||||
# =====================================================================================
|
||||
|
||||
def searchCountByRoles project, roles_id
|
||||
members = searchPeopleByRoles project, roles_id
|
||||
members.count
|
||||
end
|
||||
|
||||
def searchPeopleByRoles project, roles_id
|
||||
#searchPeopleByRoles(project, TeacherRoles)
|
||||
members = []
|
||||
begin
|
||||
members = project.members.joins(:member_roles).where("member_roles.role_id IN (:role_id)", {:role_id => roles_id})
|
||||
rescue Exception => e
|
||||
logger.error "[CoursesHelper] ===> #{e}"
|
||||
project.members.each do |m|
|
||||
members << m if m && m.user && m.user.allowed_to?(:as_teacher,project)
|
||||
end
|
||||
members
|
||||
end
|
||||
|
||||
def searchStudent project
|
||||
#searchPeopleByRoles(project, StudentRoles)
|
||||
members = []
|
||||
project.members.each do |m|
|
||||
members << m if m && m.user && m.user.allowed_to?(:as_student,project)
|
||||
end
|
||||
members
|
||||
end
|
||||
# =====================================================================================
|
||||
|
||||
#def searchCountByRoles project, roles_id
|
||||
# members = searchPeopleByRoles project, roles_id
|
||||
# members.count
|
||||
#end
|
||||
|
||||
#def searchPeopleByRoles project, roles_id
|
||||
# members = []
|
||||
# begin
|
||||
# members = project.members.joins(:member_roles).where("member_roles.role_id IN (:role_id)", {:role_id => roles_id})
|
||||
# rescue Exception => e
|
||||
# logger.error "[CoursesHelper] ===> #{e}"
|
||||
# end
|
||||
# members
|
||||
#end
|
||||
|
||||
def sort_courses(state)
|
||||
content = ''.html_safe
|
||||
case state
|
||||
|
@ -186,15 +197,15 @@ module CoursesHelper
|
|||
end
|
||||
|
||||
#useless
|
||||
def searchMembersByRole project, role_id
|
||||
members = []
|
||||
begin
|
||||
members = project.members.joins(:member_roles).where("member_roles.role_id = :role_id", {:role_id => role_id })
|
||||
rescue Exception => e
|
||||
logger.error "[CoursesHelper] ===> #{e}"
|
||||
end
|
||||
members
|
||||
end
|
||||
#def searchMembersByRole project, role_id
|
||||
# members = []
|
||||
# begin
|
||||
# members = project.members.joins(:member_roles).where("member_roles.role_id = :role_id", {:role_id => role_id })
|
||||
# rescue Exception => e
|
||||
# logger.error "[CoursesHelper] ===> #{e}"
|
||||
# end
|
||||
# members
|
||||
#end
|
||||
|
||||
def sort_course(state, school_id)
|
||||
content = ''.html_safe
|
||||
|
@ -270,9 +281,10 @@ module CoursesHelper
|
|||
def find_by_extra_from_project extra
|
||||
Course.find_by_extra(try(extra))
|
||||
end
|
||||
#判断制定用户是不是当前课程的老师
|
||||
#判断指定用户是不是当前课程的老师
|
||||
def is_course_teacher (user,course)
|
||||
course.members.joins(:member_roles).where("member_roles.role_id IN (:role_id) and members.user_id = #{user.id}", {:role_id => TeacherRoles}).count != 0
|
||||
#course.members.joins(:member_roles).where("member_roles.role_id IN (:role_id) and members.user_id = #{user.id}", {:role_id => TeacherRoles}).count != 0
|
||||
user.allowed_to?(:as_teacher,course)
|
||||
#修改为根据用户是否有发布任务的权限来判断用户是否是课程的老师
|
||||
#is_teacher = false
|
||||
#@membership = user.memberships.all(:conditions => Project.visible_condition(User.current))
|
||||
|
@ -287,7 +299,8 @@ module CoursesHelper
|
|||
end
|
||||
#当前用户是不是指定课程的学生
|
||||
def is_cur_course_student course
|
||||
course.members.joins(:member_roles).where("member_roles.role_id IN (:role_id) and members.user_id = #{User.current.id}", {:role_id => StudentRoles}).count != 0
|
||||
#course.members.joins(:member_roles).where("member_roles.role_id IN (:role_id) and members.user_id = #{User.current.id}", {:role_id => StudentRoles}).count != 0
|
||||
!(User.current.allowed_to?(:as_teacher,course))
|
||||
#修改:能新建占位且不能新建任务的角色判定为学生
|
||||
#is_student = false
|
||||
#@membership = User.current.memberships.all(:conditions => Project.visible_condition(User.current))
|
||||
|
@ -329,7 +342,10 @@ module CoursesHelper
|
|||
|
||||
#获取作业的互评得分
|
||||
def student_score_for_homework homework
|
||||
member = searchPeopleByRoles(homework.bid.courses.first,TeacherRoles).first
|
||||
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|
|
||||
|
@ -340,7 +356,10 @@ module CoursesHelper
|
|||
|
||||
#获取作业的教师评分
|
||||
def teacher_score_for_homework homework
|
||||
member = searchPeopleByRoles(homework.bid.courses.first,TeacherRoles).first
|
||||
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
|
||||
|
|
|
@ -4,13 +4,8 @@ def options_from_select_project(user)
|
|||
@option = []
|
||||
@membership.each do |membership|
|
||||
unless(membership.project.project_type==1)
|
||||
#membership.member_roles.each{|role|
|
||||
# if(role.role_id == 3)
|
||||
# @option << membership.project
|
||||
# end
|
||||
#}
|
||||
#拥有编辑项目权限的可操作该项目
|
||||
if user.allowed_to?({:controller => "projects", :action => "edit"}, membership.project, :global => false)
|
||||
#可被用户引用的项目
|
||||
if user.allowed_to?(:quote_project, membership.project)
|
||||
@option << membership.project
|
||||
end
|
||||
end
|
||||
|
|
|
@ -228,16 +228,10 @@ module UserScoreHelper
|
|||
isManager = 0
|
||||
members = Member.where('user_id = ?', user.id)
|
||||
members.each do |m|
|
||||
#roles = m.member_roles
|
||||
#roles.each do |r|
|
||||
# if r.role_id == 3
|
||||
# isManager = 1
|
||||
# end
|
||||
#end
|
||||
@membership = m.memberships.all(:conditions => Project.visible_condition(User.current))
|
||||
@membership.each do |membership|
|
||||
#拥有编辑项目权限的可操作该项目
|
||||
if m.allowed_to?({:controller => "projects", :action => "edit"}, membership.project, :global => false)
|
||||
if m.allowed_to?(:is_manager, membership.project, :global => false)
|
||||
isManager = 1
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<script type="text/javascript">
|
||||
function get_options(value){
|
||||
$.ajax({
|
||||
type :"POST",
|
||||
url :'/school/get_options/'+encodeURIComponent(value),
|
||||
data :'text',
|
||||
success: function(data){
|
||||
$("#occupation").html(data);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function get_options(value){
|
||||
$.ajax({
|
||||
type :"POST",
|
||||
url :'/school/get_options/'+encodeURIComponent(value),
|
||||
data :'text',
|
||||
success: function(data){
|
||||
$("#occupation").html(data);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<% object = [] %>
|
||||
|
@ -23,68 +23,68 @@
|
|||
|
||||
<!--[form:course]-->
|
||||
<% unless @course.new_record? %>
|
||||
<p><%= render :partial=>"avatar/avatar_form",:locals=> {source:@course} %></p>
|
||||
<p><%= render :partial=>"avatar/avatar_form",:locals=> {source:@course} %></p>
|
||||
<% end %>
|
||||
<!-- <p><%= f.text_field :name, :required => true, :size => 60, :style => "width:490px;" %></p> -->
|
||||
<!-- <p><%#= f.text_field :name, :required => true, :size => 60, :style => "width:490px;" %></p> -->
|
||||
<p><label for="course_name" style="font-size: 13px;" ><%=l(:label_tags_course_name)%><span class="required" > * </span></label><input id="course_name" type="text" value="<%=@course.name%>" style="width:490px;" size="60" name="course[name]"></p>
|
||||
|
||||
<!-- <p><%= f.text_field :extra, :required => true, :size => 60, :style => "width:488px;", :disabled => @course.extra_frozen?, :maxlength => Project::IDENTIFIER_MAX_LENGTH %>
|
||||
<% unless @course.extra_frozen? %>
|
||||
<em class="info"><%= l(:text_length_between, :min => 1, :max => Project::IDENTIFIER_MAX_LENGTH) %> <%= l(:text_course_identifier_info).html_safe %></em>
|
||||
<% end %></p> -->
|
||||
<!-- <p><%#= f.text_field :extra, :required => true, :size => 60, :style => "width:488px;", :disabled => @course.extra_frozen?, :maxlength => Project::IDENTIFIER_MAX_LENGTH %>
|
||||
<%# unless @course.extra_frozen? %>
|
||||
<em class="info"><%#= l(:text_length_between, :min => 1, :max => Project::IDENTIFIER_MAX_LENGTH) %> <%#= l(:text_course_identifier_info).html_safe %></em>
|
||||
<%# end %></p> -->
|
||||
|
||||
<!-- added by bai 新增开课时间、结课时间、课时 -->
|
||||
|
||||
<%= f.fields_for @course do |m| %>
|
||||
<!-- added by bai 新增开课时间、结课时间、课时 -->
|
||||
|
||||
<%= f.fields_for @course do |m| %>
|
||||
|
||||
|
||||
|
||||
<!-- added by bai 新增开课时间、结课时间、课时 -->
|
||||
<!--
|
||||
<% unless @course.nil?%>
|
||||
<p><table><tr><td><span class="info" align="right" style="width: 90px; font-weight: bold ;margin-left:20px"><%= l(:label_setup_time) %><span class="required"> * </span></span>
|
||||
<span class="info" style="width: 10px"><%= text_field_tag :setup_time, @course.setup_time, :placeholder => "在此选择开课日期" %></span>
|
||||
<span><%= calendar_for('setup_time')%></span>
|
||||
|
||||
<!-- added by bai 新增开课时间、结课时间、课时 -->
|
||||
<!--
|
||||
<%# unless @course.nil?%>
|
||||
<p><table><tr><td><span class="info" align="right" style="width: 90px; font-weight: bold ;margin-left:20px"><%#= l(:label_setup_time) %><span class="required"> * </span></span>
|
||||
<span class="info" style="width: 10px"><%#= text_field_tag :setup_time, @course.setup_time, :placeholder => "在此选择开课日期" %></span>
|
||||
<span><%#= calendar_for('setup_time')%></span>
|
||||
</td></tr></table></p>
|
||||
<% else %>
|
||||
<p><table><tr><td><span class="info" align="right" style="width: 90px; font-weight: bold ;margin-left:20px"><%= l(:label_setup_time) %><span class="required"> * </span></span>
|
||||
<span class="info" style="width: 10px"><%= text_field_tag :setup_time, nil, :placeholder => "在此选择开课日期" %></span>
|
||||
<span><%= calendar_for('setup_time')%></span>
|
||||
<%# else %>
|
||||
<p><table><tr><td><span class="info" align="right" style="width: 90px; font-weight: bold ;margin-left:20px"><%#= l(:label_setup_time) %><span class="required"> * </span></span>
|
||||
<span class="info" style="width: 10px"><%#= text_field_tag :setup_time, nil, :placeholder => "在此选择开课日期" %></span>
|
||||
<span><%#= calendar_for('setup_time')%></span>
|
||||
</td></tr></table></p>
|
||||
<% end %>
|
||||
|
||||
<% unless @course.nil?%>
|
||||
<p><table><tr><td><span class="info" align="right" style="width: 90px; font-weight: bold ;margin-left:20px"><%= l(:label_endup_time) %><span class="required"> * </span></span>
|
||||
<span class="info" style="width: 10px"><%= text_field_tag :endup_time, @course.endup_time, :placeholder => "在此选择结课日期" %></span>
|
||||
<span><%= calendar_for('endup_time')%></span>
|
||||
<%# end %>
|
||||
|
||||
<%# unless @course.nil?%>
|
||||
<p><table><tr><td><span class="info" align="right" style="width: 90px; font-weight: bold ;margin-left:20px"><%#= l(:label_endup_time) %><span class="required"> * </span></span>
|
||||
<span class="info" style="width: 10px"><%#= text_field_tag :endup_time, @course.endup_time, :placeholder => "在此选择结课日期" %></span>
|
||||
<span><%#= calendar_for('endup_time')%></span>
|
||||
</td></tr></table></p>
|
||||
<% else %>
|
||||
<p><table><tr><td><span class="info" align="right" style="width: 90px; font-weight: bold ;margin-left:20px"><%= l(:label_endup_time) %><span class="required"> * </span></span>
|
||||
<span class="info" style="width: 10px"><%= text_field_tag :endup_time, nil, :placeholder => "在此选择结课日期" %></span>
|
||||
<span><%= calendar_for('endup_time')%></span>
|
||||
<%# else %>
|
||||
<p><table><tr><td><span class="info" align="right" style="width: 90px; font-weight: bold ;margin-left:20px"><%#= l(:label_endup_time) %><span class="required"> * </span></span>
|
||||
<span class="info" style="width: 10px"><%#= text_field_tag :endup_time, nil, :placeholder => "在此选择结课日期" %></span>
|
||||
<span><%#= calendar_for('endup_time')%></span>
|
||||
</td></tr></table></p>
|
||||
<% end %>
|
||||
-->
|
||||
<% unless @course.nil?%>
|
||||
<p><table><tr><td><span class="info" align="right" style="width: 90px; font-weight: bold ;margin-left:22px"><%= l(:label_class_period) %><span class="required"> * </span></span>
|
||||
<span class="info" style="width: 10px"><%= text_field_tag :class_period, @course.class_period, :placeholder => "在此输入课时" %></span> <span> <strong><%= l(:label_class_hour)%></strong></span>
|
||||
</td></tr></table></p>
|
||||
<% else %>
|
||||
<p><table><tr><td><span class="info" align="right" style="width: 90px; font-weight: bold ;margin-left:22px"><%= l(:label_class_period) %><span class="required"> * </span></span>
|
||||
<span class="info" style="width: 10px"><%= text_field_tag :class_period, nil, :placeholder => "在此输入课时" %></span><strong><%= l(:label_class_hour)%></strong>
|
||||
</td></tr></table></p>
|
||||
<% end %>
|
||||
|
||||
<!-- end -->
|
||||
|
||||
<!-- added by bai 增加了“年度”和“学期” -->
|
||||
<p><table><tr><td>
|
||||
|
||||
<% unless @course.nil? %>
|
||||
<% if @course.time == 2008 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px; margin-left:20px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008' selected='selected'>2008</option>
|
||||
<%# end %>
|
||||
-->
|
||||
<% unless @course.nil?%>
|
||||
<p><table><tr><td><span class="info" align="right" style="width: 90px; font-weight: bold ;margin-left:22px"><%= l(:label_class_period) %><span class="required"> * </span></span>
|
||||
<span class="info" style="width: 10px"><%= text_field_tag :class_period, @course.class_period, :placeholder => "在此输入课时" %></span> <span> <strong><%= l(:label_class_hour)%></strong></span>
|
||||
</td></tr></table></p>
|
||||
<% else %>
|
||||
<p><table><tr><td><span class="info" align="right" style="width: 90px; font-weight: bold ;margin-left:22px"><%= l(:label_class_period) %><span class="required"> * </span></span>
|
||||
<span class="info" style="width: 10px"><%= text_field_tag :class_period, nil, :placeholder => "在此输入课时" %></span><strong><%= l(:label_class_hour)%></strong>
|
||||
</td></tr></table></p>
|
||||
<% end %>
|
||||
|
||||
<!-- end -->
|
||||
|
||||
<!-- added by bai 增加了“年度”和“学期” -->
|
||||
<p><table><tr><td>
|
||||
|
||||
<% unless @course.nil? %>
|
||||
<% if @course.time == 2008 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px; margin-left:20px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008' selected='selected'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
|
@ -94,12 +94,12 @@
|
|||
<option value = '2015'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table>
|
||||
</p>
|
||||
|
||||
<% elsif @course.time == 2009 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
</p>
|
||||
|
||||
<% elsif @course.time == 2009 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009' selected='selected'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
|
@ -109,11 +109,11 @@
|
|||
<option value = '2015'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.time == 2010 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
|
||||
<% elsif @course.time == 2010 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010' selected='selected'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
|
@ -123,11 +123,11 @@
|
|||
<option value = '2015'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.time == 2011 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
|
||||
<% elsif @course.time == 2011 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011' selected='selected'>2011</option>
|
||||
|
@ -137,12 +137,12 @@
|
|||
<option value = '2015'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
|
||||
<% elsif @course.time == 2012 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
|
||||
|
||||
<% elsif @course.time == 2012 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
|
@ -152,11 +152,11 @@
|
|||
<option value = '2015'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.time == 2013 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
|
||||
<% elsif @course.time == 2013 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
|
@ -165,67 +165,12 @@
|
|||
<option value = '2014'>2014</option>
|
||||
<option value = '2015'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.time == 2014 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
<option value = '2012'>2012</option>
|
||||
<option value = '2013'>2013</option>
|
||||
<option value = '2014' selected='selected'>2014</option>
|
||||
<option value = '2015'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.time == 2015 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
<option value = '2012'>2012</option>
|
||||
<option value = '2013'>2013</option>
|
||||
<option value = '2014'>2014</option>
|
||||
<option value = '2015' selected='selected'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.time == 2016 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
<option value = '2012'>2012</option>
|
||||
<option value = '2013'>2013</option>
|
||||
<option value = '2014'>2014</option>
|
||||
<option value = '2015'>2015</option>
|
||||
<option value = '2016' selected='selected'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.time == 2017 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
<option value = '2012'>2012</option>
|
||||
<option value = '2013'>2013</option>
|
||||
<option value = '2014'>2014</option>
|
||||
<option value = '2015'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017' selected='selected'>2017</option>".html_safe %></td></tr></table></p>
|
||||
<% else %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.time == 2014 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
|
@ -235,72 +180,136 @@
|
|||
<option value = '2015'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
<% end %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<% unless @course.nil? %>
|
||||
<% if @course.term == l(:label_spring) %>
|
||||
<p><table><tr>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'term', "<option value = '#{l(:label_spring)}' selected='selected'>#{l(:label_spring)}</option>
|
||||
|
||||
<% elsif @course.time == 2015 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
<option value = '2012'>2012</option>
|
||||
<option value = '2013'>2013</option>
|
||||
<option value = '2014'>2014</option>
|
||||
<option value = '2015' selected='selected'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.time == 2016 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
<option value = '2012'>2012</option>
|
||||
<option value = '2013'>2013</option>
|
||||
<option value = '2014'>2014</option>
|
||||
<option value = '2015'>2015</option>
|
||||
<option value = '2016' selected='selected'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.time == 2017 %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
<option value = '2012'>2012</option>
|
||||
<option value = '2013'>2013</option>
|
||||
<option value = '2014'>2014</option>
|
||||
<option value = '2015'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017' selected='selected'>2017</option>".html_safe %></td></tr></table></p>
|
||||
<% else %>
|
||||
<p><table><tr><td class="info" align="right" style="width: 86px"><strong><%= l(:label_term) %><span class="required"> * </span></strong></td>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'time', "<option value = '2008'>2008</option>
|
||||
<option value = '2009'>2009</option>
|
||||
<option value = '2010'>2010</option>
|
||||
<option value = '2011'>2011</option>
|
||||
<option value = '2012'>2012</option>
|
||||
<option value = '2013'>2013</option>
|
||||
<option value = '2014' selected='selected'>2014</option>
|
||||
<option value = '2015'>2015</option>
|
||||
<option value = '2016'>2016</option>
|
||||
<option value = '2017'>2017</option>".html_safe %></td></tr></table></p>
|
||||
|
||||
<% end %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<% unless @course.nil? %>
|
||||
<% if @course.term == l(:label_spring) %>
|
||||
<p><table><tr>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'term', "<option value = '#{l(:label_spring)}' selected='selected'>#{l(:label_spring)}</option>
|
||||
<option value = '#{l(:label_autumn)}'>#{l(:label_autumn)}</option>
|
||||
".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.term == l(:label_summer)%>
|
||||
<p><table><tr>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'term', "<option value = '#{l(:label_spring)}'>#{l(:label_spring)}</option>
|
||||
|
||||
<% elsif @course.term == l(:label_summer)%>
|
||||
<p><table><tr>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'term', "<option value = '#{l(:label_spring)}'>#{l(:label_spring)}</option>
|
||||
<option value = '#{l(:label_autumn)}'>#{l(:label_autumn)}</option>
|
||||
".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.term == l(:label_autumn)%>
|
||||
<p><table><tr>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'term', "<option value = '#{l(:label_spring)}'>#{l(:label_spring)}</option>
|
||||
|
||||
<% elsif @course.term == l(:label_autumn)%>
|
||||
<p><table><tr>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'term', "<option value = '#{l(:label_spring)}'>#{l(:label_spring)}</option>
|
||||
<option value = '#{l(:label_autumn)}' selected='selected'>#{l(:label_autumn)}</option>
|
||||
".html_safe %></td></tr></table></p>
|
||||
|
||||
<% elsif @course.term == l(:label_winter)%>
|
||||
<p><table><tr>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'term', "<option value = '#{l(:label_spring)}'>#{l(:label_spring)}</option>
|
||||
<option value = '#{l(:label_autumn)}'>#{l(:label_autumn)}</option>
|
||||
".html_safe %></td></tr></table></p>
|
||||
|
||||
<% else %>
|
||||
<p><table><tr>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'term', "<option value = '#{l(:label_spring)}'>#{l(:label_spring)}</option>
|
||||
<option value = '#{l(:label_autumn)}'>#{l(:label_autumn)}</option>
|
||||
".html_safe %></td></tr></table></p>
|
||||
|
||||
<% end %>
|
||||
|
||||
<% end %></td></tr></table>
|
||||
</p>
|
||||
<!-- end -->
|
||||
|
||||
|
||||
|
||||
|
||||
<!--added by Wen -->
|
||||
|
||||
|
||||
<!-- end -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- <p style="margin-left:-10px;"><%#= m.text_field :password, :required => true, :size => 60, :style => "width:488px;margin-left: 10px;" %></p> -->
|
||||
<p style="margin-left:-10px;"><label for="course[course]_password" style="font-size: 13px;" ><%=l(:label_new_course_password)%><span class="required"> *</span></label><input id="course_course_password" type="text" style="width:488px;margin-left: 10px;" value="<%=@course.password %>" size="60" name="course[password]"></p>
|
||||
<em class="info" style="margin-left:95px;"><%= l(:text_command) %></em>
|
||||
<% end %>
|
||||
|
||||
<% elsif @course.term == l(:label_winter)%>
|
||||
<p><table><tr>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'term', "<option value = '#{l(:label_spring)}'>#{l(:label_spring)}</option>
|
||||
<option value = '#{l(:label_autumn)}'>#{l(:label_autumn)}</option>
|
||||
".html_safe %></td></tr></table></p>
|
||||
|
||||
<% else %>
|
||||
<p><table><tr>
|
||||
<td class="info" style="width: 10px">
|
||||
<%= select_tag 'term', "<option value = '#{l(:label_spring)}'>#{l(:label_spring)}</option>
|
||||
<option value = '#{l(:label_autumn)}'>#{l(:label_autumn)}</option>
|
||||
".html_safe %></td></tr></table></p>
|
||||
|
||||
<% end %>
|
||||
|
||||
<% end %></td></tr></table>
|
||||
</p>
|
||||
<!-- end -->
|
||||
|
||||
|
||||
|
||||
|
||||
<!--added by Wen -->
|
||||
|
||||
|
||||
<!-- end -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- <p style="margin-left:-10px;"><%#= m.text_field :password, :required => true, :size => 60, :style => "width:488px;margin-left: 10px;" %></p> -->
|
||||
<p style="margin-left:-10px;"><label for="course[course]_password" style="font-size: 13px;" ><%=l(:label_new_course_password)%><span class="required"> *</span></label><input id="course_course_password" type="text" style="width:488px;margin-left: 10px;" value="<%=@course.password %>" size="60" name="course[password]"></p>
|
||||
<em class="info" style="margin-left:95px;"><%= l(:text_command) %></em>
|
||||
<% end %>
|
||||
|
||||
<!-- <p style="margin-left:-10px;padding-right: 20px;"><%#= f.text_area :description, :rows => 8, :class => 'wiki-edit', :style => "font-size:small;width:490px;margin-left:10px;" %></p> -->
|
||||
<p style="margin-left:-20px;padding-right: 20px;"><label for="course_description" style="font-size: 13px;"><%=l(:label_new_course_description)%></label><span class="jstEditor"><textarea id="course_description" class="wiki-edit" style="font-size:small;width:490px;margin-left:10px;" rows="8" name="course[description]" cols="40" ><%=@course.description%></textarea></span></p>
|
||||
<p style="padding-right: 20px;">
|
||||
<label for="course_description" style="font-size: 13px;">
|
||||
<%=l(:label_new_course_description)%>
|
||||
</label>
|
||||
<span class="jstEditor">
|
||||
<textarea id="course_description" class="wiki-edit" style="font-size:small;width:490px;margin-left:10px;" rows="8" name="course[description]" cols="40" >
|
||||
<%=@course.description%>
|
||||
</textarea>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
|
||||
<p style="margin-left:-10px;"><em style ="color: #888888;display: block;font-size: 90%;font-style: normal;"><%= f.check_box :is_public, :style => "margin-left:10px;" %><%= l(:label_course_public_info) %></em></p><!-- modified by bai -->
|
||||
|
@ -310,7 +319,7 @@
|
|||
<%= wikitoolbar_for 'course_description' %>
|
||||
|
||||
<% @course.custom_field_values.each do |value| %>
|
||||
<p><%= custom_field_tag_with_label :course, value %></p>
|
||||
<p><%= custom_field_tag_with_label :course, value %></p>
|
||||
<% end %>
|
||||
<%= call_hook(:view_courses_form, :course => @course, :form => f) %>
|
||||
|
||||
|
@ -319,8 +328,8 @@
|
|||
<!--[eoform:course]-->
|
||||
|
||||
<% 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 %>
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
<% end %>
|
||||
|
||||
<% if @issue.safe_attribute? 'description' %>
|
||||
<p style="margin-left:-10px;">
|
||||
<p>
|
||||
<%= 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 %>
|
||||
|
|
|
@ -32,8 +32,6 @@
|
|||
<div class="debug">
|
||||
<%= debug(params) if Rails.env.development? %>
|
||||
<div class="hidden">
|
||||
|
||||
<script src="http://s4.cnzz.com/z_stat.php?id=1000482288&web_id=1000482288" language="JavaScript"></script>
|
||||
<script>
|
||||
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<div class="container">
|
||||
<%= render_flash_messages %>
|
||||
<%= yield %>
|
||||
<%= render :partial => 'layouts/bootstrap_base_footer' %>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -29,6 +30,5 @@
|
|||
|
||||
<div id="ajax-indicator" style="display:none;"><span><%= l(:label_loading) %></span></div>
|
||||
<div id="ajax-modal" style="display:none;"></div>
|
||||
<%= render :partial => 'layouts/bootstrap_base_footer' %>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -10,4 +10,4 @@
|
|||
<p id="attachments_form" style="margin-left:-10px;"><label style="padding-right: 15px;"><%= l(:label_attachment_plural) %></label><%= render :partial => 'attachments/form', :locals => {:container => @news} %></p>
|
||||
</div>
|
||||
|
||||
<%= wikitoolbar_for 'news_description' %>
|
||||
<%= wikitoolbar_for 'news_description'%>
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
<% end %>
|
||||
<p><%= f.text_field :name, :required => true, :size => 60, :style => "width:490px;" %></p>
|
||||
|
||||
<p style="margin-left:-10px;padding-right: 20px;">
|
||||
<p style="padding-right: 20px;">
|
||||
<%= f.text_area :description, :rows => 8, :class => 'wiki-edit', :style => "font-size:small;width:490px;margin-left:10px;" %>
|
||||
</p><!--by young-->
|
||||
<p><%= f.text_field :identifier, :required => true, :size => 60, :style => "width:488px;", :disabled => @project.identifier_frozen?, :maxlength => Project::IDENTIFIER_MAX_LENGTH %>
|
||||
<% unless @project.identifier_frozen? %>
|
||||
<em class="info"><%= l(:text_length_between, :min => 1, :max => Project::IDENTIFIER_MAX_LENGTH) %> <%= l(:text_project_identifier_info).html_safe %></em>
|
||||
<% end %></p>
|
||||
<!-- <p style="margin-left:-10px;"><%= f.text_field :homepage, :size => 60, :style => "width:488px;margin-left: 10px;" %></p> --> <!-- by huang -->
|
||||
<!-- <p style="margin-left:-10px;"><%#= f.text_field :homepage, :size => 60, :style => "width:488px;margin-left: 10px;" %></p> --> <!-- by huang -->
|
||||
<p style="margin-left:-10px;"><em style ="color: #888888;display: block;font-size: 90%;font-style: normal;"><%= f.check_box :is_public, :style => "margin-left:10px;" %></em></p>
|
||||
<p style="margin-left:-10px;"><em style ="color: #888888;display: block;font-size: 90%;font-style: normal;"><%= f.check_box :hidden_repo, :style => "margin-left:10px;" %></em></p>
|
||||
<p style="display:none;"><%= f.text_field :project_type, :value => 0 %></p>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
membership.each do |member|
|
||||
unless(member.project.project_type==1)
|
||||
member.member_roles.each{|role|
|
||||
if(role.role_id == 3)
|
||||
if role.allowed_to?(:quote_project)
|
||||
option << member.project
|
||||
end
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
<div class="alert alert-success">
|
||||
<strong>Well done!</strong> You successfully read this important alert message.
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<strong>Heads up!</strong> This alert needs your attention, but it's not super important.
|
||||
</div>
|
||||
<div class="alert alert-warning">
|
||||
<strong>Warning!</strong> Best check yo self, you're not looking too good.
|
||||
</div>
|
||||
<div class="alert alert-danger">
|
||||
<strong>Oh snap!</strong> Change a few things up and try submitting again.
|
||||
<strong>Warning!</strong> you can stop.
|
||||
</div>
|
||||
|
||||
<div class="page-header">
|
||||
|
@ -29,14 +20,15 @@
|
|||
<div class="homeworks panel-heading">
|
||||
<div class="panel-title">
|
||||
<%= link_to homework.name, respond_path(homework) %>(<%=homework.homeworks.count %>)<%#Bid%>
|
||||
<%= link_to "打包下载", zipdown_assort_path(obj_class: homework.class, obj_id: homework.id), :class => "btn btn-primary btn-sm" %><br/>
|
||||
<%#= link_to "打包下载", zipdown_assort_path(obj_class: homework.class, obj_id: homework.id), :class => "btn btn-primary btn-sm" %><br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="attach_item panel-body ">
|
||||
<div class="col-md-offset-1">
|
||||
<% homework.homeworks.each do |homeattach|%><%#homework.class == Bid %>
|
||||
<% homeattach.attachments.each do |attach|%>
|
||||
<%= link_to_attachment attach, author: true, :download => true %> (<%=attach.author%>)
|
||||
<%= attach.filename %>
|
||||
<%#= link_to_attachment attach, author: true, :download => true %> (<%=attach.author%>)
|
||||
<br/>
|
||||
<% homeworks_attach_path << attach.storage_path %>
|
||||
<% end %>
|
||||
|
@ -44,7 +36,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<%# 所有作业的文件列表%>
|
||||
<!-- (<%=homeworks_attach_path.count%>):<%= homeworks_attach_path.to_json %> -->
|
||||
<!-- (<%#=homeworks_attach_path.count%>):<%#= homeworks_attach_path.to_json %> -->
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
@ -52,3 +44,4 @@
|
|||
<hr/>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="pagination"><%= pagination_links_full @obj_pages, @obj_count, :per_page_links => false %></div>
|
|
@ -1471,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
|
||||
|
|
|
@ -477,6 +477,20 @@ zh:
|
|||
permission_view_real_name: 查看真名
|
||||
permission_view_students: 查看成员
|
||||
permission_export_homeworks: 导出作业
|
||||
permission_quote_project: 引用项目
|
||||
permission_is_manager: 作为管理员
|
||||
permission_as_teacher: 作为教师
|
||||
permission_as_student: 作为学生
|
||||
permission_paret_in_homework: 加入作业
|
||||
permission_view_homework_attaches: 查看作业附件
|
||||
permission_view_course_journals_for_messages: 查看课程留言
|
||||
permission_select_course_modules: 选择课程模块
|
||||
permission_view_course_files: 查看课程资源
|
||||
permission_add_course: 新建课程
|
||||
permission_edit_course: 编辑课程
|
||||
permission_select_contest_modules: 选择竞赛模块
|
||||
permission_manage_contestnotifications: 管理竞赛通知
|
||||
|
||||
|
||||
|
||||
project_module_issue_tracking: 问题跟踪
|
||||
|
@ -1291,6 +1305,9 @@ zh:
|
|||
permission_add_documents: Add documents
|
||||
permission_edit_documents: Edit documents
|
||||
permission_delete_documents: Delete documents
|
||||
permission_add_documents: 新建文档
|
||||
permission_edit_documents: 编辑文档
|
||||
permission_delete_documents: 删除文档
|
||||
label_gantt_progress_line: Progress line
|
||||
setting_jsonp_enabled: Enable JSONP support
|
||||
field_inherit_members: Inherit members
|
||||
|
@ -1842,6 +1859,7 @@ zh:
|
|||
|
||||
#added by Wen
|
||||
label_school_all: 中国高校
|
||||
label_school_not_fount: 没有符合的高校信息
|
||||
|
||||
|
||||
label_project_grade: 项目得分
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# -*coding:utf-8 -*-
|
||||
class AddAuthority < ActiveRecord::Migration
|
||||
def change
|
||||
# 添加课程权限
|
||||
Role.all.each do |role|
|
||||
if role.name == '学生'
|
||||
role.permissions.append(:paret_in_homework)
|
||||
role.permissions.append(:as_student)
|
||||
elsif role.name == 'Manager'
|
||||
role.permissions.append(:is_manager)
|
||||
role.permissions.append(:as_teacher)
|
||||
elsif role.name == '助教'
|
||||
role.permissions.append(:as_teacher)
|
||||
elsif role.name == '老师'
|
||||
role.permissions.append(:as_teacher)
|
||||
end
|
||||
role.save(:validate => false)
|
||||
end
|
||||
end
|
||||
end
|
19
db/schema.rb
19
db/schema.rb
|
@ -11,7 +11,11 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
<<<<<<< HEAD
|
||||
ActiveRecord::Schema.define(:version => 20140710030426) do
|
||||
=======
|
||||
ActiveRecord::Schema.define(:version => 20140708023356) do
|
||||
>>>>>>> 056f86caad29ca95632d9da9e1e616cd00e2349a
|
||||
|
||||
create_table "activities", :force => true do |t|
|
||||
t.integer "act_id", :null => false
|
||||
|
@ -795,7 +799,7 @@ ActiveRecord::Schema.define(:version => 20140710030426) 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
|
||||
|
@ -832,6 +836,19 @@ ActiveRecord::Schema.define(:version => 20140710030426) 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
|
||||
|
|
|
@ -99,6 +99,9 @@ Redmine::AccessControl.map do |map|
|
|||
map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member
|
||||
map.permission :view_journals_for_messages, {:gantts => [:show, :update]}, :read => true
|
||||
map.permission :quote_project, {},:require => :member
|
||||
map.permission :is_manager,{},:require => :member
|
||||
map.permission :as_teacher,{},:require => :member
|
||||
map.permission :as_student,{},:require => :member
|
||||
|
||||
#课程权限模块
|
||||
#added by nwb
|
||||
|
@ -122,6 +125,7 @@ Redmine::AccessControl.map do |map|
|
|||
#作业模块权限
|
||||
map.course_module :bids do |map|
|
||||
map.permission :view_homework_attaches, {:bids => [:show, :show_project, :revision]}, :read => true
|
||||
map.permission :paret_in_homework,{},:require => :member
|
||||
end
|
||||
|
||||
map.course_module :boards do |map|
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "app/assets/javascripts/ckeditor-releases"]
|
||||
path = app/assets/javascripts/ckeditor-releases
|
||||
url = git://github.com/ckeditor/ckeditor-releases.git
|
|
@ -0,0 +1,6 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'rich', '1.4.6'
|
||||
gem 'kaminari'
|
||||
gem 'htmlentities'
|
||||
gem 'paperclip', '~> 3.5.4'
|
|
@ -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]
|
|
@ -0,0 +1,5 @@
|
|||
//
|
||||
//= require rich/editor/ckeditor_path
|
||||
//= require ckeditor-releases/ckeditor
|
||||
//= require rich/editor/rich_editor
|
||||
//= require rich/editor/rich_picker
|
|
@ -0,0 +1,4 @@
|
|||
//= require fileuploader
|
||||
//= require rich/browser/extensions
|
||||
//= require rich/browser/uploader
|
||||
//= require rich/browser/filebrowser
|
|
@ -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
|
|
@ -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 %>
|
|
@ -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");
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Rich Browser</title>
|
||||
<%= javascript_heads %>
|
||||
<%= stylesheet_link_tag "application", :plugin => "redmine_ckeditor" %>
|
||||
<%= ckeditor_javascripts %>
|
||||
<%= javascript_include_tag "browser", :plugin => "redmine_ckeditor" %>
|
||||
<%= csrf_meta_tags %>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<%= yield %>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,2 @@
|
|||
<%= render :file => "messages/quote" %>
|
||||
CKEDITOR.instances['message_content'].setData($('#message_content').val());
|
|
@ -0,0 +1,12 @@
|
|||
<li class="clickable">
|
||||
<img id="file<%= file.id %>"
|
||||
src="<%= thumb_for_file(file) %>"
|
||||
data-uris="<%= file.uri_cache %>"
|
||||
data-relative-url-root="<%= Redmine::Utils.relative_url_root %>"
|
||||
data-rich-asset-id="<%= file.id %>"
|
||||
data-rich-asset-type="<%= file.simplified_type %>"
|
||||
data-rich-asset-name="<%= file.rich_file_file_name %>"
|
||||
/>
|
||||
<p><%= file.rich_file_file_name %></p>
|
||||
<%= link_to "delete", file.id.to_s, :method => :delete, :remote => true, :confirm => t(:delete_confirm), :class => "delete", :title => t(:delete) %>
|
||||
</li>
|
|
@ -0,0 +1,142 @@
|
|||
<%= ckeditor_javascripts %>
|
||||
<%= stylesheet_link_tag 'editor', :plugin => 'redmine_ckeditor'%>
|
||||
<%= stylesheet_link_tag 'selector', :plugin => 'redmine_ckeditor'%>
|
||||
<p>
|
||||
<%= content_tag :label, l(:ckeditor_skin) %>
|
||||
<%= select_tag "settings[skin]", RedmineCkeditor.skin_options %>
|
||||
</p>
|
||||
<p>
|
||||
<%= content_tag :label, l(:ckeditor_ui_color) %>
|
||||
<%= text_field_tag "settings[ui_color]", RedmineCkeditorSetting.ui_color %>
|
||||
</p>
|
||||
<p>
|
||||
<%= content_tag :label, l(:ckeditor_width) %>
|
||||
<%= text_field_tag "settings[width]", RedmineCkeditorSetting.width %>
|
||||
</p>
|
||||
<p>
|
||||
<%= content_tag :label, l(:ckeditor_height) %>
|
||||
<%= text_field_tag "settings[height]", RedmineCkeditorSetting.height %>
|
||||
</p>
|
||||
<p>
|
||||
<%= content_tag :label, l(:ckeditor_enter_mode) %>
|
||||
<%= select_tag "settings[enter_mode]", RedmineCkeditor.enter_mode_options %>
|
||||
</p>
|
||||
<p>
|
||||
<%= 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 %>
|
||||
</p>
|
||||
<p>
|
||||
<%= 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 %>
|
||||
</p>
|
||||
<p>
|
||||
<%= content_tag :label, l(:ckeditor_toolbar_location) %>
|
||||
<%= select_tag "settings[toolbar_location]", RedmineCkeditor.toolbar_location_options %>
|
||||
</p>
|
||||
<p>
|
||||
<%= content_tag :label, l(:ckeditor_toolbar_buttons) %>
|
||||
</p>
|
||||
|
||||
<div class="selector-container">
|
||||
<%= hidden_field_tag "settings[toolbar]", RedmineCkeditorSetting.toolbar_string %>
|
||||
|
||||
<select id="left" multiple="multiple" size="10">
|
||||
</select>
|
||||
|
||||
<div class="container">
|
||||
<input type="button" class="button" value="<%= t(:add) %> >>"
|
||||
onclick="moveItem('left', 'right')"/><br/>
|
||||
<input type="button" class="button" value="<%= t(:remove) %> <<"
|
||||
onclick="moveItem('right', 'left')"/><br/><br/>
|
||||
<input type="button" class="button" value="<%= t(:separator) %> >>"
|
||||
onclick="addItem('-')"/><br/>
|
||||
<input type="button" class="button" value="<%= t(:subgroup) %> >>"
|
||||
onclick="addItem('--')"/><br/>
|
||||
<input type="button" class="button" value="<%= t(:line_break) %> >>"
|
||||
onclick="addItem('/')"/>
|
||||
</div>
|
||||
|
||||
<select id="right" multiple="multiple" size="10">
|
||||
</select>
|
||||
|
||||
<div class="clear"></div>
|
||||
<div id="toolbar"></div>
|
||||
</div>
|
||||
|
||||
<%= 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 = $("<option/>").val(item).text(item);
|
||||
var to = $("#right");
|
||||
var selected = to.find("option:selected").first();
|
||||
selected.size() ? selected.before(option) : to.append(option);
|
||||
changeHandler();
|
||||
}
|
||||
|
||||
function changeHandler() {
|
||||
var values = $("#right").find("option").map(function() {
|
||||
return this.value;
|
||||
});
|
||||
$("#settings_toolbar").val(values.toArray().join(","));
|
||||
|
||||
var bars = [];
|
||||
var bar = [];
|
||||
values.each(function() {
|
||||
var value = this.toString();
|
||||
if (value == "/") {
|
||||
bars.push(bar, value);
|
||||
bar = [];
|
||||
} else if (value == "--") {
|
||||
bars.push(bar);
|
||||
bar = [];
|
||||
} else {
|
||||
bar.push(value);
|
||||
}
|
||||
});
|
||||
if (bar.length > 0) bars.push(bar);
|
||||
|
||||
CKEDITOR.instances['toolbar'].destroy();
|
||||
updateCkeditor(bars);
|
||||
}
|
||||
|
||||
function updateCkeditor(toolbar) {
|
||||
var options = <%= RedmineCkeditor.options.to_json.html_safe %>;
|
||||
options.toolbar = toolbar;
|
||||
CKEDITOR.replace('toolbar', options);
|
||||
}
|
||||
|
||||
CKEDITOR.on('instanceReady', function() {
|
||||
CKEDITOR.removeListener('instanceReady', arguments.callee);
|
||||
|
||||
var left = $("#left");
|
||||
var right = $("#right");
|
||||
var rightItems = $("#settings_toolbar").val().split(",");
|
||||
|
||||
var dict = {};
|
||||
$.each(CKEDITOR.instances.toolbar.ui.items, function(key, value) {
|
||||
if (key == '-') return;
|
||||
dict[key] = value.label;
|
||||
if (rightItems.indexOf(key) < 0) {
|
||||
left.append($("<option/>").val(key).text(dict[key] || key));
|
||||
}
|
||||
});
|
||||
$.each(rightItems, function() {
|
||||
right.append($("<option/>").val(this).text(dict[this] || this));
|
||||
});
|
||||
});
|
||||
|
||||
updateCkeditor(<%= RedmineCkeditorSetting.toolbar.to_json.html_safe %>);
|
||||
<% end %>
|
|
@ -0,0 +1,112 @@
|
|||
/* Extra for the CKEditor CodeMirror Plugin */
|
||||
|
||||
.CodeMirror {font:13px/1.4em monospace;}
|
||||
|
||||
.CodeMirror .activeline { background: #e8f2ff; }
|
||||
|
||||
.CodeMirror .CodeMirror-foldmarker {
|
||||
color: blue;
|
||||
text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
|
||||
font-family: arial;
|
||||
line-height: .3;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Fixes for themes */
|
||||
.cm-s-cobalt .CodeMirror-selected { background: #b36539 !important; }
|
||||
.cm-s-erlang-dark .CodeMirror-selected { background: #b36539 !important; }
|
||||
.cm-s-lesser-dark .CodeMirror-selected {background: #45443B !important;}
|
||||
.cm-s-monokai .CodeMirror-selected {background: #49483E !important;}
|
||||
.cm-s-night .CodeMirror-selected { background: #447 !important; }
|
||||
.cm-s-rubyblue .CodeMirror-selected { background: #38566F !important; }
|
||||
.cm-s-twilight .CodeMirror-selected { background: #323232 !important; }
|
||||
.cm-s-xq-dark .CodeMirror-selected { background: #a8f !important; }
|
||||
|
||||
.cm-s-blackboard .activeline,
|
||||
.cm-s-cobalt .activeline,
|
||||
.cm-s-erlang-dark .activeline,
|
||||
.cm-s-lesser-dark .activeline,
|
||||
.cm-s-monokai .activeline,
|
||||
.cm-s-night .activeline,
|
||||
.cm-s-rubyblue .activeline,
|
||||
.cm-s-vibrant-ink .activeline,
|
||||
.cm-s-xq-dark .activeline { background: #757575; }
|
||||
.cm-s-twilight .activeline { background:#494949; }
|
||||
|
||||
.CodeMirror-focused .cm-matchhighlight {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);
|
||||
background-position: bottom;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
/* Dialog Addon */
|
||||
.CodeMirror-dialog {
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
background: white;
|
||||
z-index: 15;
|
||||
padding: .1em .8em;
|
||||
overflow: hidden;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog-top {
|
||||
border-bottom: 1px solid #eee;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog-bottom {
|
||||
border-top: 1px solid #eee;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog input {
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
width: 20em;
|
||||
color: inherit;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog button {
|
||||
font-size: 70%;
|
||||
}
|
||||
.CodeMirror-hints {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
overflow: hidden;
|
||||
list-style: none;
|
||||
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
|
||||
-webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
-moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
border-radius: 3px;
|
||||
border: 1px solid silver;
|
||||
|
||||
background: white;
|
||||
font-size: 90%;
|
||||
font-family: monospace;
|
||||
|
||||
max-height: 20em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.CodeMirror-hint {
|
||||
margin: 0;
|
||||
padding: 0 4px;
|
||||
border-radius: 2px;
|
||||
max-width: 19em;
|
||||
overflow: hidden;
|
||||
white-space: pre;
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.CodeMirror-hint-active {
|
||||
background: #08f;
|
||||
color: white;
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
/* BASICS */
|
||||
|
||||
.CodeMirror {
|
||||
/* Set height, width, borders, and global font properties here */
|
||||
font-family: monospace;
|
||||
height: 300px;
|
||||
}
|
||||
.CodeMirror-scroll {
|
||||
/* Set scrolling behaviour here */
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* PADDING */
|
||||
|
||||
.CodeMirror-lines {
|
||||
padding: 4px 0; /* Vertical padding around content */
|
||||
}
|
||||
.CodeMirror pre {
|
||||
padding: 0 4px; /* Horizontal padding of content */
|
||||
}
|
||||
|
||||
.CodeMirror-scrollbar-filler {
|
||||
background-color: white; /* The little square between H and V scrollbars */
|
||||
}
|
||||
|
||||
/* GUTTER */
|
||||
|
||||
.CodeMirror-gutters {
|
||||
border-right: 1px solid #ddd;
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
.CodeMirror-linenumbers {}
|
||||
.CodeMirror-linenumber {
|
||||
padding: 0 3px 0 5px;
|
||||
min-width: 20px;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* CURSOR */
|
||||
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
border-left: 1px solid black;
|
||||
z-index: 3;
|
||||
}
|
||||
/* Shown when moving in bi-directional text */
|
||||
.CodeMirror div.CodeMirror-secondarycursor {
|
||||
border-left: 1px solid silver;
|
||||
}
|
||||
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
|
||||
width: auto;
|
||||
border: 0;
|
||||
background: #7e7;
|
||||
z-index: 1;
|
||||
}
|
||||
/* Can style cursor different in overwrite (non-insert) mode */
|
||||
.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
|
||||
|
||||
.cm-tab { display: inline-block; }
|
||||
|
||||
/* DEFAULT THEME */
|
||||
|
||||
.cm-s-default .cm-keyword {color: #708;}
|
||||
.cm-s-default .cm-atom {color: #219;}
|
||||
.cm-s-default .cm-number {color: #164;}
|
||||
.cm-s-default .cm-def {color: #00f;}
|
||||
.cm-s-default .cm-variable {color: black;}
|
||||
.cm-s-default .cm-variable-2 {color: #05a;}
|
||||
.cm-s-default .cm-variable-3 {color: #085;}
|
||||
.cm-s-default .cm-property {color: black;}
|
||||
.cm-s-default .cm-operator {color: black;}
|
||||
.cm-s-default .cm-comment {color: #a50;}
|
||||
.cm-s-default .cm-string {color: #a11;}
|
||||
.cm-s-default .cm-string-2 {color: #f50;}
|
||||
.cm-s-default .cm-meta {color: #555;}
|
||||
.cm-s-default .cm-error {color: #f00;}
|
||||
.cm-s-default .cm-qualifier {color: #555;}
|
||||
.cm-s-default .cm-builtin {color: #30a;}
|
||||
.cm-s-default .cm-bracket {color: #997;}
|
||||
.cm-s-default .cm-tag {color: #170;}
|
||||
.cm-s-default .cm-attribute {color: #00c;}
|
||||
.cm-s-default .cm-header {color: blue;}
|
||||
.cm-s-default .cm-quote {color: #090;}
|
||||
.cm-s-default .cm-hr {color: #999;}
|
||||
.cm-s-default .cm-link {color: #00c;}
|
||||
|
||||
.cm-negative {color: #d44;}
|
||||
.cm-positive {color: #292;}
|
||||
.cm-header, .cm-strong {font-weight: bold;}
|
||||
.cm-em {font-style: italic;}
|
||||
.cm-link {text-decoration: underline;}
|
||||
|
||||
.cm-invalidchar {color: #f00;}
|
||||
|
||||
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
|
||||
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
||||
|
||||
/* STOP */
|
||||
|
||||
/* The rest of this file contains styles related to the mechanics of
|
||||
the editor. You probably shouldn't touch them. */
|
||||
|
||||
.CodeMirror {
|
||||
line-height: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.CodeMirror-scroll {
|
||||
/* 30px is the magic margin used to hide the element's real scrollbars */
|
||||
/* See overflow: hidden in .CodeMirror, and the paddings in .CodeMirror-sizer */
|
||||
margin-bottom: -30px; margin-right: -30px;
|
||||
padding-bottom: 30px; padding-right: 30px;
|
||||
height: 100%;
|
||||
outline: none; /* Prevent dragging from highlighting the element */
|
||||
position: relative;
|
||||
}
|
||||
.CodeMirror-sizer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
||||
before actuall scrolling happens, thus preventing shaking and
|
||||
flickering artifacts. */
|
||||
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
display: none;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
right: 0; top: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.CodeMirror-hscrollbar {
|
||||
bottom: 0; left: 0;
|
||||
overflow-y: hidden;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.CodeMirror-scrollbar-filler {
|
||||
right: 0; bottom: 0;
|
||||
z-index: 6;
|
||||
}
|
||||
|
||||
.CodeMirror-gutters {
|
||||
position: absolute; left: 0; top: 0;
|
||||
height: 100%;
|
||||
padding-bottom: 30px;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
height: 100%;
|
||||
padding-bottom: 30px;
|
||||
margin-bottom: -32px;
|
||||
display: inline-block;
|
||||
/* Hack to make IE7 behave */
|
||||
*zoom:1;
|
||||
*display:inline;
|
||||
}
|
||||
.CodeMirror-gutter-elt {
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.CodeMirror-lines {
|
||||
cursor: text;
|
||||
}
|
||||
.CodeMirror pre {
|
||||
/* Reset some styles that the rest of the page might have set */
|
||||
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
||||
border-width: 0;
|
||||
background: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
.CodeMirror-wrap pre {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
word-break: normal;
|
||||
}
|
||||
.CodeMirror-linebackground {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: 0; bottom: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-linewidget {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.CodeMirror-widget {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.CodeMirror-wrap .CodeMirror-scroll {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.CodeMirror-measure {
|
||||
position: absolute;
|
||||
width: 100%; height: 0px;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
.CodeMirror-measure pre { position: static; }
|
||||
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
border-right: none;
|
||||
width: 0;
|
||||
}
|
||||
.CodeMirror-focused div.CodeMirror-cursor {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-selected { background: #d9d9d9; }
|
||||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
|
||||
|
||||
.cm-searching {
|
||||
background: #ffa;
|
||||
background: rgba(255, 255, 0, .4);
|
||||
}
|
||||
|
||||
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
|
||||
.CodeMirror span { *vertical-align: text-bottom; }
|
||||
|
||||
@media print {
|
||||
/* Hide the cursor when printing */
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
1
plugins/redmine_ckeditor/assets/ckeditor-contrib/plugins/codemirror/css/codemirror.min.css
vendored
Normal file
1
plugins/redmine_ckeditor/assets/ckeditor-contrib/plugins/codemirror/css/codemirror.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 644 B |
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 490 B |
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
|
@ -0,0 +1,81 @@
|
|||
// Open simple dialogs on top of an editor. Relies on dialog.css.
|
||||
|
||||
(function() {
|
||||
function dialogDiv(cm, template, bottom) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
var dialog;
|
||||
|
||||
dialog = wrap.appendChild(document.createElement("div"));
|
||||
if (bottom) {
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
|
||||
} else {
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
|
||||
}
|
||||
dialog.innerHTML = template;
|
||||
return dialog;
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("openDialog", function(template, callback, options) {
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var closed = false, me = this;
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
}
|
||||
var inp = dialog.getElementsByTagName("input")[0], button;
|
||||
if (inp) {
|
||||
CodeMirror.on(inp, "keydown", function(e) {
|
||||
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
|
||||
if (e.keyCode == 13 || e.keyCode == 27) {
|
||||
CodeMirror.e_stop(e);
|
||||
close();
|
||||
me.focus();
|
||||
if (e.keyCode == 13) callback(inp.value);
|
||||
}
|
||||
});
|
||||
if (options && options.onKeyUp) {
|
||||
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
|
||||
}
|
||||
if (options && options.value) inp.value = options.value;
|
||||
inp.focus();
|
||||
CodeMirror.on(inp, "blur", close);
|
||||
} else if (button = dialog.getElementsByTagName("button")[0]) {
|
||||
CodeMirror.on(button, "click", function() {
|
||||
close();
|
||||
me.focus();
|
||||
});
|
||||
button.focus();
|
||||
CodeMirror.on(button, "blur", close);
|
||||
}
|
||||
return close;
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var buttons = dialog.getElementsByTagName("button");
|
||||
var closed = false, me = this, blurring = 1;
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
}
|
||||
buttons[0].focus();
|
||||
for (var i = 0; i < buttons.length; ++i) {
|
||||
var b = buttons[i];
|
||||
(function(callback) {
|
||||
CodeMirror.on(b, "click", function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
if (callback) callback(me);
|
||||
});
|
||||
})(callbacks[i]);
|
||||
CodeMirror.on(b, "blur", function() {
|
||||
--blurring;
|
||||
setTimeout(function() { if (blurring <= 0) close(); }, 200);
|
||||
});
|
||||
CodeMirror.on(b, "focus", function() { ++blurring; });
|
||||
}
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,52 @@
|
|||
(function() {
|
||||
var DEFAULT_BRACKETS = "()[]{}''\"\"";
|
||||
var SPACE_CHAR_REGEX = /\s/;
|
||||
|
||||
CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
|
||||
var wasOn = old && old != CodeMirror.Init;
|
||||
if (val && !wasOn)
|
||||
cm.addKeyMap(buildKeymap(typeof val == "string" ? val : DEFAULT_BRACKETS));
|
||||
else if (!val && wasOn)
|
||||
cm.removeKeyMap("autoCloseBrackets");
|
||||
});
|
||||
|
||||
function buildKeymap(pairs) {
|
||||
var map = {
|
||||
name : "autoCloseBrackets",
|
||||
Backspace: function(cm) {
|
||||
if (cm.somethingSelected()) return CodeMirror.Pass;
|
||||
var cur = cm.getCursor(), line = cm.getLine(cur.line);
|
||||
if (cur.ch && cur.ch < line.length &&
|
||||
pairs.indexOf(line.slice(cur.ch - 1, cur.ch + 1)) % 2 == 0)
|
||||
cm.replaceRange("", CodeMirror.Pos(cur.line, cur.ch - 1), CodeMirror.Pos(cur.line, cur.ch + 1));
|
||||
else
|
||||
return CodeMirror.Pass;
|
||||
}
|
||||
};
|
||||
var closingBrackets = [];
|
||||
for (var i = 0; i < pairs.length; i += 2) (function(left, right) {
|
||||
if (left != right) closingBrackets.push(right);
|
||||
function surround(cm) {
|
||||
var selection = cm.getSelection();
|
||||
cm.replaceSelection(left + selection + right);
|
||||
}
|
||||
function maybeOverwrite(cm) {
|
||||
var cur = cm.getCursor(), ahead = cm.getRange(cur, CodeMirror.Pos(cur.line, cur.ch + 1));
|
||||
if (ahead != right || cm.somethingSelected()) return CodeMirror.Pass;
|
||||
else cm.execCommand("goCharRight");
|
||||
}
|
||||
map["'" + left + "'"] = function(cm) {
|
||||
if (cm.somethingSelected()) return surround(cm);
|
||||
if (left == right && maybeOverwrite(cm) != CodeMirror.Pass) return;
|
||||
var cur = cm.getCursor(), ahead = CodeMirror.Pos(cur.line, cur.ch + 1);
|
||||
var line = cm.getLine(cur.line), nextChar = line.charAt(cur.ch);
|
||||
if (line.length == cur.ch || closingBrackets.indexOf(nextChar) >= 0 || SPACE_CHAR_REGEX.test(nextChar))
|
||||
cm.replaceSelection(left + right, {head: ahead, anchor: ahead});
|
||||
else
|
||||
return CodeMirror.Pass;
|
||||
};
|
||||
if (left != right) map["'" + right + "'"] = maybeOverwrite;
|
||||
})(pairs.charAt(i), pairs.charAt(i + 1));
|
||||
return map;
|
||||
}
|
||||
})();
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* Tag-closer extension for CodeMirror.
|
||||
*
|
||||
* This extension adds an "autoCloseTags" option that can be set to
|
||||
* either true to get the default behavior, or an object to further
|
||||
* configure its behavior.
|
||||
*
|
||||
* These are supported options:
|
||||
*
|
||||
* `whenClosing` (default true)
|
||||
* Whether to autoclose when the '/' of a closing tag is typed.
|
||||
* `whenOpening` (default true)
|
||||
* Whether to autoclose the tag when the final '>' of an opening
|
||||
* tag is typed.
|
||||
* `dontCloseTags` (default is empty tags for HTML, none for XML)
|
||||
* An array of tag names that should not be autoclosed.
|
||||
* `indentTags` (default is block tags for HTML, none for XML)
|
||||
* An array of tag names that should, when opened, cause a
|
||||
* blank line to be added inside the tag, and the blank line and
|
||||
* closing line to be indented.
|
||||
*
|
||||
* See demos/closetag.html for a usage example.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
|
||||
if (val && (old == CodeMirror.Init || !old)) {
|
||||
var map = {name: "autoCloseTags"};
|
||||
if (typeof val != "object" || val.whenClosing)
|
||||
map["'/'"] = function(cm) { return autoCloseTag(cm, '/'); };
|
||||
if (typeof val != "object" || val.whenOpening)
|
||||
map["'>'"] = function(cm) { return autoCloseTag(cm, '>'); };
|
||||
cm.addKeyMap(map);
|
||||
} else if (!val && (old != CodeMirror.Init && old)) {
|
||||
cm.removeKeyMap("autoCloseTags");
|
||||
}
|
||||
});
|
||||
|
||||
var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
|
||||
"source", "track", "wbr"];
|
||||
var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4",
|
||||
"h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
|
||||
|
||||
function autoCloseTag(cm, ch) {
|
||||
var pos = cm.getCursor(), tok = cm.getTokenAt(pos);
|
||||
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
|
||||
if (inner.mode.name != "xml") return CodeMirror.Pass;
|
||||
|
||||
var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
|
||||
var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
|
||||
var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
|
||||
|
||||
if (ch == ">" && state.tagName) {
|
||||
var tagName = state.tagName;
|
||||
if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
|
||||
var lowerTagName = tagName.toLowerCase();
|
||||
// Don't process the '>' at the end of an end-tag or self-closing tag
|
||||
if (tok.type == "tag" && state.type == "closeTag" || tok.string.indexOf("/") > -1 ||
|
||||
dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1)
|
||||
return CodeMirror.Pass;
|
||||
|
||||
var doIndent = indentTags && indexOf(indentTags, lowerTagName) > -1;
|
||||
var curPos = doIndent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1);
|
||||
cm.replaceSelection(">" + (doIndent ? "\n\n" : "") + "</" + tagName + ">",
|
||||
{head: curPos, anchor: curPos});
|
||||
if (doIndent) {
|
||||
cm.indentLine(pos.line + 1);
|
||||
cm.indentLine(pos.line + 2);
|
||||
}
|
||||
return;
|
||||
} else if (ch == "/" && tok.string == "<") {
|
||||
var tagName = state.context && state.context.tagName;
|
||||
if (tagName) cm.replaceSelection("/" + tagName + ">", "end");
|
||||
return;
|
||||
}
|
||||
return CodeMirror.Pass;
|
||||
}
|
||||
|
||||
function indexOf(collection, elt) {
|
||||
if (collection.indexOf) return collection.indexOf(elt);
|
||||
for (var i = 0, e = collection.length; i < e; ++i)
|
||||
if (collection[i] == elt) return i;
|
||||
return -1;
|
||||
}
|
||||
})();
|
|
@ -0,0 +1,44 @@
|
|||
(function() {
|
||||
var modes = ["clike", "css", "javascript"];
|
||||
for (var i = 0; i < modes.length; ++i)
|
||||
CodeMirror.extendMode(modes[i], {blockCommentStart: "/*",
|
||||
blockCommentEnd: "*/",
|
||||
blockCommentContinue: " * "});
|
||||
|
||||
function continueComment(cm) {
|
||||
var pos = cm.getCursor(), token = cm.getTokenAt(pos);
|
||||
var mode = CodeMirror.innerMode(cm.getMode(), token.state).mode;
|
||||
var space;
|
||||
|
||||
if (token.type == "comment" && mode.blockCommentStart) {
|
||||
var end = token.string.indexOf(mode.blockCommentEnd);
|
||||
var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found;
|
||||
if (end != -1 && end == token.string.length - mode.blockCommentEnd.length) {
|
||||
// Comment ended, don't continue it
|
||||
} else if (token.string.indexOf(mode.blockCommentStart) == 0) {
|
||||
space = full.slice(0, token.start);
|
||||
if (!/^\s*$/.test(space)) {
|
||||
space = "";
|
||||
for (var i = 0; i < token.start; ++i) space += " ";
|
||||
}
|
||||
} else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 &&
|
||||
found + mode.blockCommentContinue.length > token.start &&
|
||||
/^\s*$/.test(full.slice(0, found))) {
|
||||
space = full.slice(0, found);
|
||||
}
|
||||
}
|
||||
|
||||
if (space != null)
|
||||
cm.replaceSelection("\n" + space + mode.blockCommentContinue, "end");
|
||||
else
|
||||
return CodeMirror.Pass;
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("continueComments", null, function(cm, val, prev) {
|
||||
if (prev && prev != CodeMirror.Init)
|
||||
cm.removeKeyMap("continueComment");
|
||||
var map = {name: "continueComment"};
|
||||
map[typeof val == "string" ? val : "Enter"] = continueComment;
|
||||
cm.addKeyMap(map);
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,25 @@
|
|||
(function() {
|
||||
'use strict';
|
||||
|
||||
var listRE = /^(\s*)([*+-]|(\d+)\.)(\s*)/,
|
||||
unorderedBullets = '*+-';
|
||||
|
||||
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
|
||||
var pos = cm.getCursor(),
|
||||
inList = cm.getStateAfter(pos.line).list,
|
||||
match;
|
||||
|
||||
if (!inList || !(match = cm.getLine(pos.line).match(listRE))) {
|
||||
cm.execCommand('newlineAndIndent');
|
||||
return;
|
||||
}
|
||||
|
||||
var indent = match[1], after = match[4];
|
||||
var bullet = unorderedBullets.indexOf(match[2]) >= 0
|
||||
? match[2]
|
||||
: (parseInt(match[3], 10) + 1) + '.';
|
||||
|
||||
cm.replaceSelection('\n' + indent + bullet + after, 'end');
|
||||
};
|
||||
|
||||
}());
|
|
@ -0,0 +1,74 @@
|
|||
(function() {
|
||||
var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
|
||||
(document.documentMode == null || document.documentMode < 8);
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
// Disable brace matching in long lines, since it'll cause hugely slow updates
|
||||
var maxLineLen = 1000;
|
||||
|
||||
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
|
||||
function findMatchingBracket(cm) {
|
||||
var cur = cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1;
|
||||
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
|
||||
if (!match) return null;
|
||||
var forward = match.charAt(1) == ">", d = forward ? 1 : -1;
|
||||
var style = cm.getTokenAt(Pos(cur.line, pos + 1)).type;
|
||||
|
||||
var stack = [line.text.charAt(pos)], re = /[(){}[\]]/;
|
||||
function scan(line, lineNo, start) {
|
||||
if (!line.text) return;
|
||||
var pos = forward ? 0 : line.text.length - 1, end = forward ? line.text.length : -1;
|
||||
if (start != null) pos = start + d;
|
||||
for (; pos != end; pos += d) {
|
||||
var ch = line.text.charAt(pos);
|
||||
if (re.test(ch) && cm.getTokenAt(Pos(lineNo, pos + 1)).type == style) {
|
||||
var match = matching[ch];
|
||||
if (match.charAt(1) == ">" == forward) stack.push(ch);
|
||||
else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false};
|
||||
else if (!stack.length) return {pos: pos, match: true};
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = cur.line, found, e = forward ? Math.min(i + 100, cm.lineCount()) : Math.max(-1, i - 100); i != e; i+=d) {
|
||||
if (i == cur.line) found = scan(line, i, pos);
|
||||
else found = scan(cm.getLineHandle(i), i);
|
||||
if (found) break;
|
||||
}
|
||||
return {from: Pos(cur.line, pos), to: found && Pos(i, found.pos), match: found && found.match};
|
||||
}
|
||||
|
||||
function matchBrackets(cm, autoclear) {
|
||||
var found = findMatchingBracket(cm);
|
||||
if (!found || cm.getLine(found.from.line).length > maxLineLen ||
|
||||
found.to && cm.getLine(found.to.line).length > maxLineLen)
|
||||
return;
|
||||
|
||||
var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
|
||||
var one = cm.markText(found.from, Pos(found.from.line, found.from.ch + 1), {className: style});
|
||||
var two = found.to && cm.markText(found.to, Pos(found.to.line, found.to.ch + 1), {className: style});
|
||||
// Kludge to work around the IE bug from issue #1193, where text
|
||||
// input stops going to the textare whever this fires.
|
||||
if (ie_lt8 && cm.state.focused) cm.display.input.focus();
|
||||
var clear = function() {
|
||||
cm.operation(function() { one.clear(); two && two.clear(); });
|
||||
};
|
||||
if (autoclear) setTimeout(clear, 800);
|
||||
else return clear;
|
||||
}
|
||||
|
||||
var currentlyHighlighted = null;
|
||||
function doMatchBrackets(cm) {
|
||||
cm.operation(function() {
|
||||
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
|
||||
if (!cm.somethingSelected()) currentlyHighlighted = matchBrackets(cm, false);
|
||||
});
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("matchBrackets", false, function(cm, val) {
|
||||
if (val) cm.on("cursorActivity", doMatchBrackets);
|
||||
else cm.off("cursorActivity", doMatchBrackets);
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
|
||||
CodeMirror.defineExtension("findMatchingBracket", function(){return findMatchingBracket(this);});
|
||||
})();
|
|
@ -0,0 +1,31 @@
|
|||
CodeMirror.braceRangeFinder = function(cm, start) {
|
||||
var line = start.line, lineText = cm.getLine(line);
|
||||
var at = lineText.length, startChar, tokenType;
|
||||
for (;;) {
|
||||
var found = lineText.lastIndexOf("{", at);
|
||||
if (found < start.ch) break;
|
||||
tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type;
|
||||
if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
|
||||
at = found - 1;
|
||||
}
|
||||
if (startChar == null || lineText.lastIndexOf("}") > startChar) return;
|
||||
var count = 1, lastLine = cm.lineCount(), end, endCh;
|
||||
outer: for (var i = line + 1; i < lastLine; ++i) {
|
||||
var text = cm.getLine(i), pos = 0;
|
||||
for (;;) {
|
||||
var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos);
|
||||
if (nextOpen < 0) nextOpen = text.length;
|
||||
if (nextClose < 0) nextClose = text.length;
|
||||
pos = Math.min(nextOpen, nextClose);
|
||||
if (pos == text.length) break;
|
||||
if (cm.getTokenAt(CodeMirror.Pos(i, pos + 1)).type == tokenType) {
|
||||
if (pos == nextOpen) ++count;
|
||||
else if (!--count) { end = i; endCh = pos; break outer; }
|
||||
}
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
if (end == null || end == line + 1) return;
|
||||
return {from: CodeMirror.Pos(line, startChar + 1),
|
||||
to: CodeMirror.Pos(end, endCh)};
|
||||
};
|
|
@ -0,0 +1,32 @@
|
|||
CodeMirror.newFoldFunction = function(rangeFinder, widget) {
|
||||
if (widget == null) widget = "\u2194";
|
||||
if (typeof widget == "string") {
|
||||
var text = document.createTextNode(widget);
|
||||
widget = document.createElement("span");
|
||||
widget.appendChild(text);
|
||||
widget.className = "CodeMirror-foldmarker";
|
||||
}
|
||||
|
||||
return function(cm, pos) {
|
||||
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
|
||||
var range = rangeFinder(cm, pos);
|
||||
if (!range) return;
|
||||
|
||||
var present = cm.findMarksAt(range.from), cleared = 0;
|
||||
for (var i = 0; i < present.length; ++i) {
|
||||
if (present[i].__isFold) {
|
||||
++cleared;
|
||||
present[i].clear();
|
||||
}
|
||||
}
|
||||
if (cleared) return;
|
||||
|
||||
var myWidget = widget.cloneNode(true);
|
||||
CodeMirror.on(myWidget, "mousedown", function() {myRange.clear();});
|
||||
var myRange = cm.markText(range.from, range.to, {
|
||||
replacedWith: myWidget,
|
||||
clearOnEnter: true,
|
||||
__isFold: true
|
||||
});
|
||||
};
|
||||
};
|
|
@ -0,0 +1,64 @@
|
|||
CodeMirror.tagRangeFinder = (function() {
|
||||
var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
|
||||
var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
|
||||
var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
|
||||
|
||||
return function(cm, start) {
|
||||
var line = start.line, ch = start.ch, lineText = cm.getLine(line);
|
||||
|
||||
function nextLine() {
|
||||
if (line >= cm.lastLine()) return;
|
||||
ch = 0;
|
||||
lineText = cm.getLine(++line);
|
||||
return true;
|
||||
}
|
||||
function toTagEnd() {
|
||||
for (;;) {
|
||||
var gt = lineText.indexOf(">", ch);
|
||||
if (gt == -1) { if (nextLine()) continue; else return; }
|
||||
var lastSlash = lineText.lastIndexOf("/", gt);
|
||||
var selfClose = lastSlash > -1 && /^\s*$/.test(lineText.slice(lastSlash + 1, gt));
|
||||
ch = gt + 1;
|
||||
return selfClose ? "selfClose" : "regular";
|
||||
}
|
||||
}
|
||||
function toNextTag() {
|
||||
for (;;) {
|
||||
xmlTagStart.lastIndex = ch;
|
||||
var found = xmlTagStart.exec(lineText);
|
||||
if (!found) { if (nextLine()) continue; else return; }
|
||||
ch = found.index + found[0].length;
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
var stack = [], startCh;
|
||||
for (;;) {
|
||||
var openTag = toNextTag(), end;
|
||||
if (!openTag || line != start.line || !(end = toTagEnd())) return;
|
||||
if (!openTag[1] && end != "selfClose") {
|
||||
stack.push(openTag[2]);
|
||||
startCh = ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
var next = toNextTag(), end, tagLine = line, tagCh = ch - (next ? next[0].length : 0);
|
||||
if (!next || !(end = toTagEnd())) return;
|
||||
if (end == "selfClose") continue;
|
||||
if (next[1]) { // closing tag
|
||||
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
|
||||
stack.length = i;
|
||||
break;
|
||||
}
|
||||
if (!stack.length) return {
|
||||
from: CodeMirror.Pos(start.line, startCh),
|
||||
to: CodeMirror.Pos(tagLine, tagCh)
|
||||
};
|
||||
} else { // opening tag
|
||||
stack.push(next[2]);
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,43 @@
|
|||
(function() {
|
||||
|
||||
// Applies automatic formatting to the specified range
|
||||
CodeMirror.defineExtension("autoFormatAll", function (from, to) {
|
||||
var cm = this;
|
||||
var outer = cm.getMode(), text = cm.getRange(from, to).split("\n");
|
||||
var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state);
|
||||
var tabSize = cm.getOption("tabSize");
|
||||
|
||||
var out = "", lines = 0, atSol = from.ch == 0;
|
||||
function newline() {
|
||||
out += "\n";
|
||||
atSol = true;
|
||||
++lines;
|
||||
}
|
||||
|
||||
for (var i = 0; i < text.length; ++i) {
|
||||
var stream = new CodeMirror.StringStream(text[i], tabSize);
|
||||
while (!stream.eol()) {
|
||||
var inner = CodeMirror.innerMode(outer, state);
|
||||
var style = outer.token(stream, state), cur = stream.current();
|
||||
stream.start = stream.pos;
|
||||
if (!atSol || /\S/.test(cur)) {
|
||||
out += cur;
|
||||
atSol = false;
|
||||
}
|
||||
if (!atSol && inner.mode.newlineAfterToken &&
|
||||
inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i+1] || "", inner.state))
|
||||
newline();
|
||||
}
|
||||
if (!stream.pos && outer.blankLine) outer.blankLine(state);
|
||||
if (!atSol && i < text.length - 1) newline();
|
||||
}
|
||||
|
||||
cm.operation(function () {
|
||||
cm.replaceRange(out, from, to);
|
||||
for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur)
|
||||
cm.indentLine(cur, "smart");
|
||||
|
||||
cm.setCursor({ line:0, ch:0 });
|
||||
});
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,114 @@
|
|||
(function() {
|
||||
|
||||
CodeMirror.extendMode("css", {
|
||||
commentStart: "/*",
|
||||
commentEnd: "*/",
|
||||
newlineAfterToken: function(_type, content) {
|
||||
return /^[;{}]$/.test(content);
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.extendMode("javascript", {
|
||||
commentStart: "/*",
|
||||
commentEnd: "*/",
|
||||
// FIXME semicolons inside of for
|
||||
newlineAfterToken: function(_type, content, textAfter, state) {
|
||||
if (this.jsonMode) {
|
||||
return /^[\[,{]$/.test(content) || /^}/.test(textAfter);
|
||||
} else {
|
||||
if (content == ";" && state.lexical && state.lexical.type == ")") return false;
|
||||
return /^[;{}]$/.test(content) && !/^;/.test(textAfter);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var inlineElements = /^(a|abbr|acronym|area|base|bdo|big|br|button|caption|cite|code|col|colgroup|dd|del|dfn|em|frame|hr|iframe|img|input|ins|kbd|label|legend|link|map|object|optgroup|option|param|q|samp|script|select|small|span|strong|sub|sup|textarea|tt|var)$/;
|
||||
|
||||
CodeMirror.extendMode("xml", {
|
||||
commentStart: "<!--",
|
||||
commentEnd: "-->",
|
||||
newlineAfterToken: function(type, content, textAfter, state) {
|
||||
var inline = false;
|
||||
if (this.configuration == "html")
|
||||
inline = state.context ? inlineElements.test(state.context.tagName) : false;
|
||||
return !inline && ((type == "tag" && />$/.test(content) && state.context) ||
|
||||
/^</.test(textAfter));
|
||||
}
|
||||
});
|
||||
|
||||
// Comment/uncomment the specified range
|
||||
CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
|
||||
var cm = this, curMode = CodeMirror.innerMode(cm.getMode(), cm.getTokenAt(from).state).mode;
|
||||
cm.operation(function() {
|
||||
if (isComment) { // Comment range
|
||||
cm.replaceRange(curMode.commentEnd, to);
|
||||
cm.replaceRange(curMode.commentStart, from);
|
||||
if (from.line == to.line && from.ch == to.ch) // An empty comment inserted - put cursor inside
|
||||
cm.setCursor(from.line, from.ch + curMode.commentStart.length);
|
||||
} else { // Uncomment range
|
||||
var selText = cm.getRange(from, to);
|
||||
var startIndex = selText.indexOf(curMode.commentStart);
|
||||
var endIndex = selText.lastIndexOf(curMode.commentEnd);
|
||||
if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
|
||||
// Take string till comment start
|
||||
selText = selText.substr(0, startIndex)
|
||||
// From comment start till comment end
|
||||
+ selText.substring(startIndex + curMode.commentStart.length, endIndex)
|
||||
// From comment end till string end
|
||||
+ selText.substr(endIndex + curMode.commentEnd.length);
|
||||
}
|
||||
cm.replaceRange(selText, from, to);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Applies automatic mode-aware indentation to the specified range
|
||||
CodeMirror.defineExtension("autoIndentRange", function (from, to) {
|
||||
var cmInstance = this;
|
||||
this.operation(function () {
|
||||
for (var i = from.line; i <= to.line; i++) {
|
||||
cmInstance.indentLine(i, "smart");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Applies automatic formatting to the specified range
|
||||
CodeMirror.defineExtension("autoFormatRange", function (from, to) {
|
||||
var cm = this;
|
||||
var outer = cm.getMode(), text = cm.getRange(from, to).split("\n");
|
||||
var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state);
|
||||
var tabSize = cm.getOption("tabSize");
|
||||
|
||||
var out = "", lines = 0, atSol = from.ch == 0;
|
||||
function newline() {
|
||||
out += "\n";
|
||||
atSol = true;
|
||||
++lines;
|
||||
}
|
||||
|
||||
for (var i = 0; i < text.length; ++i) {
|
||||
var stream = new CodeMirror.StringStream(text[i], tabSize);
|
||||
while (!stream.eol()) {
|
||||
var inner = CodeMirror.innerMode(outer, state);
|
||||
var style = outer.token(stream, state), cur = stream.current();
|
||||
stream.start = stream.pos;
|
||||
if (!atSol || /\S/.test(cur)) {
|
||||
out += cur;
|
||||
atSol = false;
|
||||
}
|
||||
if (!atSol && inner.mode.newlineAfterToken &&
|
||||
inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i+1] || "", inner.state))
|
||||
newline();
|
||||
}
|
||||
if (!stream.pos && outer.blankLine) outer.blankLine(state);
|
||||
if (!atSol && i < text.length - 1) newline();
|
||||
}
|
||||
|
||||
cm.operation(function () {
|
||||
cm.replaceRange(out, from, to);
|
||||
for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur)
|
||||
cm.indentLine(cur, "smart");
|
||||
cm.setSelection(from, cm.getCursor(false));
|
||||
});
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,60 @@
|
|||
// Highlighting text that matches the selection
|
||||
//
|
||||
// Defines an option highlightSelectionMatches, which, when enabled,
|
||||
// will style strings that match the selection throughout the
|
||||
// document.
|
||||
//
|
||||
// The option can be set to true to simply enable it, or to a
|
||||
// {minChars, style} object to explicitly configure it. minChars is
|
||||
// the minimum amount of characters that should be selected for the
|
||||
// behavior to occur, and style is the token style to apply to the
|
||||
// matches. This will be prefixed by "cm-" to create an actual CSS
|
||||
// class name.
|
||||
|
||||
(function() {
|
||||
var DEFAULT_MIN_CHARS = 2;
|
||||
var DEFAULT_TOKEN_STYLE = "matchhighlight";
|
||||
|
||||
function State(options) {
|
||||
this.minChars = typeof options == "object" && options.minChars || DEFAULT_MIN_CHARS;
|
||||
this.style = typeof options == "object" && options.style || DEFAULT_TOKEN_STYLE;
|
||||
this.overlay = null;
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
|
||||
var prev = old && old != CodeMirror.Init;
|
||||
if (val && !prev) {
|
||||
cm._matchHighlightState = new State(val);
|
||||
cm.on("cursorActivity", highlightMatches);
|
||||
} else if (!val && prev) {
|
||||
var over = cm._matchHighlightState.overlay;
|
||||
if (over) cm.removeOverlay(over);
|
||||
cm._matchHighlightState = null;
|
||||
cm.off("cursorActivity", highlightMatches);
|
||||
}
|
||||
});
|
||||
|
||||
function highlightMatches(cm) {
|
||||
cm.operation(function() {
|
||||
var state = cm._matchHighlightState;
|
||||
if (state.overlay) {
|
||||
cm.removeOverlay(state.overlay);
|
||||
state.overlay = null;
|
||||
}
|
||||
|
||||
if (!cm.somethingSelected()) return;
|
||||
var selection = cm.getSelection().replace(/^\s+|\s+$/g, "");
|
||||
if (selection.length < state.minChars) return;
|
||||
|
||||
cm.addOverlay(state.overlay = makeOverlay(selection, state.style));
|
||||
});
|
||||
}
|
||||
|
||||
function makeOverlay(query, style) {
|
||||
return {token: function(stream) {
|
||||
if (stream.match(query)) return style;
|
||||
stream.next();
|
||||
stream.skipTo(query.charAt(0)) || stream.skipToEnd();
|
||||
}};
|
||||
}
|
||||
})();
|
|
@ -0,0 +1,131 @@
|
|||
// Define search commands. Depends on dialog.js or another
|
||||
// implementation of the openDialog method.
|
||||
|
||||
// Replace works a little oddly -- it will do the replace on the next
|
||||
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
|
||||
// replace by making sure the match is no longer selected when hitting
|
||||
// Ctrl-G.
|
||||
|
||||
(function() {
|
||||
function searchOverlay(query) {
|
||||
if (typeof query == "string") return {token: function(stream) {
|
||||
if (stream.match(query)) return "searching";
|
||||
stream.next();
|
||||
stream.skipTo(query.charAt(0)) || stream.skipToEnd();
|
||||
}};
|
||||
return {token: function(stream) {
|
||||
if (stream.match(query)) return "searching";
|
||||
while (!stream.eol()) {
|
||||
stream.next();
|
||||
if (stream.match(query, false)) break;
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
function SearchState() {
|
||||
this.posFrom = this.posTo = this.query = null;
|
||||
this.overlay = null;
|
||||
}
|
||||
function getSearchState(cm) {
|
||||
return cm._searchState || (cm._searchState = new SearchState());
|
||||
}
|
||||
function getSearchCursor(cm, query, pos) {
|
||||
// Heuristic: if the query string is all lowercase, do a case insensitive search.
|
||||
return cm.getSearchCursor(query, pos, typeof query == "string" && query == query.toLowerCase());
|
||||
}
|
||||
function dialog(cm, text, shortText, f) {
|
||||
if (cm.openDialog) cm.openDialog(text, f);
|
||||
else f(prompt(shortText, ""));
|
||||
}
|
||||
function confirmDialog(cm, text, shortText, fs) {
|
||||
if (cm.openConfirm) cm.openConfirm(text, fs);
|
||||
else if (confirm(shortText)) fs[0]();
|
||||
}
|
||||
function parseQuery(query) {
|
||||
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
|
||||
return isRE ? new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i") : query;
|
||||
}
|
||||
var queryDialog =
|
||||
'Search: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
|
||||
function doSearch(cm, rev) {
|
||||
var state = getSearchState(cm);
|
||||
if (state.query) return findNext(cm, rev);
|
||||
dialog(cm, queryDialog, "Search for:", function(query) {
|
||||
cm.operation(function() {
|
||||
if (!query || state.query) return;
|
||||
state.query = parseQuery(query);
|
||||
cm.removeOverlay(state.overlay);
|
||||
state.overlay = searchOverlay(query);
|
||||
cm.addOverlay(state.overlay);
|
||||
state.posFrom = state.posTo = cm.getCursor();
|
||||
findNext(cm, rev);
|
||||
});
|
||||
});
|
||||
}
|
||||
function findNext(cm, rev) {cm.operation(function() {
|
||||
var state = getSearchState(cm);
|
||||
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
|
||||
if (!cursor.find(rev)) {
|
||||
cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
|
||||
if (!cursor.find(rev)) return;
|
||||
}
|
||||
cm.setSelection(cursor.from(), cursor.to());
|
||||
state.posFrom = cursor.from(); state.posTo = cursor.to();
|
||||
});}
|
||||
function clearSearch(cm) {cm.operation(function() {
|
||||
var state = getSearchState(cm);
|
||||
if (!state.query) return;
|
||||
state.query = null;
|
||||
cm.removeOverlay(state.overlay);
|
||||
});}
|
||||
|
||||
var replaceQueryDialog =
|
||||
'Replace: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
|
||||
var replacementQueryDialog = 'With: <input type="text" style="width: 10em"/>';
|
||||
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
|
||||
function replace(cm, all) {
|
||||
dialog(cm, replaceQueryDialog, "Replace:", function(query) {
|
||||
if (!query) return;
|
||||
query = parseQuery(query);
|
||||
dialog(cm, replacementQueryDialog, "Replace with:", function(text) {
|
||||
if (all) {
|
||||
cm.operation(function() {
|
||||
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
|
||||
if (typeof query != "string") {
|
||||
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
|
||||
cursor.replace(text.replace(/\$(\d)/, function(_, i) {return match[i];}));
|
||||
} else cursor.replace(text);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
clearSearch(cm);
|
||||
var cursor = getSearchCursor(cm, query, cm.getCursor());
|
||||
var advance = function() {
|
||||
var start = cursor.from(), match;
|
||||
if (!(match = cursor.findNext())) {
|
||||
cursor = getSearchCursor(cm, query);
|
||||
if (!(match = cursor.findNext()) ||
|
||||
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
|
||||
}
|
||||
cm.setSelection(cursor.from(), cursor.to());
|
||||
confirmDialog(cm, doReplaceConfirm, "Replace?",
|
||||
[function() {doReplace(match);}, advance]);
|
||||
};
|
||||
var doReplace = function(match) {
|
||||
cursor.replace(typeof query == "string" ? text :
|
||||
text.replace(/\$(\d)/, function(_, i) {return match[i];}));
|
||||
advance();
|
||||
};
|
||||
advance();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
|
||||
CodeMirror.commands.findNext = doSearch;
|
||||
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
|
||||
CodeMirror.commands.clearSearch = clearSearch;
|
||||
CodeMirror.commands.replace = replace;
|
||||
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
|
||||
})();
|
|
@ -0,0 +1,130 @@
|
|||
(function(){
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
function SearchCursor(cm, query, pos, caseFold) {
|
||||
this.atOccurrence = false; this.cm = cm;
|
||||
if (caseFold == null && typeof query == "string") caseFold = false;
|
||||
|
||||
pos = pos ? cm.clipPos(pos) : Pos(0, 0);
|
||||
this.pos = {from: pos, to: pos};
|
||||
|
||||
// The matches method is filled in based on the type of query.
|
||||
// It takes a position and a direction, and returns an object
|
||||
// describing the next occurrence of the query, or null if no
|
||||
// more matches were found.
|
||||
if (typeof query != "string") { // Regexp match
|
||||
if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g");
|
||||
this.matches = function(reverse, pos) {
|
||||
if (reverse) {
|
||||
query.lastIndex = 0;
|
||||
var line = cm.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;
|
||||
for (;;) {
|
||||
query.lastIndex = cutOff;
|
||||
var newMatch = query.exec(line);
|
||||
if (!newMatch) break;
|
||||
match = newMatch;
|
||||
start = match.index;
|
||||
cutOff = match.index + 1;
|
||||
}
|
||||
} else {
|
||||
query.lastIndex = pos.ch;
|
||||
var line = cm.getLine(pos.line), match = query.exec(line),
|
||||
start = match && match.index;
|
||||
}
|
||||
if (match && match[0])
|
||||
return {from: Pos(pos.line, start),
|
||||
to: Pos(pos.line, start + match[0].length),
|
||||
match: match};
|
||||
};
|
||||
} else { // String query
|
||||
if (caseFold) query = query.toLowerCase();
|
||||
var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
|
||||
var target = query.split("\n");
|
||||
// Different methods for single-line and multi-line queries
|
||||
if (target.length == 1) {
|
||||
if (!query.length) {
|
||||
// Empty string would match anything and never progress, so
|
||||
// we define it to match nothing instead.
|
||||
this.matches = function() {};
|
||||
} else {
|
||||
this.matches = function(reverse, pos) {
|
||||
var line = fold(cm.getLine(pos.line)), len = query.length, match;
|
||||
if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
|
||||
: (match = line.indexOf(query, pos.ch)) != -1)
|
||||
return {from: Pos(pos.line, match),
|
||||
to: Pos(pos.line, match + len)};
|
||||
};
|
||||
}
|
||||
} else {
|
||||
this.matches = function(reverse, pos) {
|
||||
var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(cm.getLine(ln));
|
||||
var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
|
||||
if (reverse ? offsetA >= pos.ch || offsetA != match.length
|
||||
: offsetA <= pos.ch || offsetA != line.length - match.length)
|
||||
return;
|
||||
for (;;) {
|
||||
if (reverse ? !ln : ln == cm.lineCount() - 1) return;
|
||||
line = fold(cm.getLine(ln += reverse ? -1 : 1));
|
||||
match = target[reverse ? --idx : ++idx];
|
||||
if (idx > 0 && idx < target.length - 1) {
|
||||
if (line != match) return;
|
||||
else continue;
|
||||
}
|
||||
var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
|
||||
if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
|
||||
return;
|
||||
var start = Pos(pos.line, offsetA), end = Pos(ln, offsetB);
|
||||
return {from: reverse ? end : start, to: reverse ? start : end};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SearchCursor.prototype = {
|
||||
findNext: function() {return this.find(false);},
|
||||
findPrevious: function() {return this.find(true);},
|
||||
|
||||
find: function(reverse) {
|
||||
var self = this, pos = this.cm.clipPos(reverse ? this.pos.from : this.pos.to);
|
||||
function savePosAndFail(line) {
|
||||
var pos = Pos(line, 0);
|
||||
self.pos = {from: pos, to: pos};
|
||||
self.atOccurrence = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (this.pos = this.matches(reverse, pos)) {
|
||||
if (!this.pos.from || !this.pos.to) { console.log(this.matches, this.pos); }
|
||||
this.atOccurrence = true;
|
||||
return this.pos.match || true;
|
||||
}
|
||||
if (reverse) {
|
||||
if (!pos.line) return savePosAndFail(0);
|
||||
pos = Pos(pos.line-1, this.cm.getLine(pos.line-1).length);
|
||||
}
|
||||
else {
|
||||
var maxLine = this.cm.lineCount();
|
||||
if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
|
||||
pos = Pos(pos.line + 1, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
from: function() {if (this.atOccurrence) return this.pos.from;},
|
||||
to: function() {if (this.atOccurrence) return this.pos.to;},
|
||||
|
||||
replace: function(newText) {
|
||||
if (!this.atOccurrence) return;
|
||||
var lines = CodeMirror.splitLines(newText);
|
||||
this.cm.replaceRange(lines, this.pos.from, this.pos.to);
|
||||
this.pos.to = Pos(this.pos.from.line + lines.length - 1,
|
||||
lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
|
||||
return new SearchCursor(this, query, pos, caseFold);
|
||||
});
|
||||
})();
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
1
plugins/redmine_ckeditor/assets/ckeditor-contrib/plugins/codemirror/js/codemirror.min.js
vendored
Normal file
1
plugins/redmine_ckeditor/assets/ckeditor-contrib/plugins/codemirror/js/codemirror.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,567 @@
|
|||
CodeMirror.defineMode("css", function(config) {
|
||||
return CodeMirror.getMode(config, "text/css");
|
||||
});
|
||||
|
||||
CodeMirror.defineMode("css-base", function(config, parserConfig) {
|
||||
"use strict";
|
||||
|
||||
var indentUnit = config.indentUnit,
|
||||
hooks = parserConfig.hooks || {},
|
||||
atMediaTypes = parserConfig.atMediaTypes || {},
|
||||
atMediaFeatures = parserConfig.atMediaFeatures || {},
|
||||
propertyKeywords = parserConfig.propertyKeywords || {},
|
||||
colorKeywords = parserConfig.colorKeywords || {},
|
||||
valueKeywords = parserConfig.valueKeywords || {},
|
||||
allowNested = !!parserConfig.allowNested,
|
||||
type = null;
|
||||
|
||||
function ret(style, tp) { type = tp; return style; }
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (hooks[ch]) {
|
||||
// result[0] is style and result[1] is type
|
||||
var result = hooks[ch](stream, state);
|
||||
if (result !== false) return result;
|
||||
}
|
||||
if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());}
|
||||
else if (ch == "=") ret(null, "compare");
|
||||
else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
|
||||
else if (ch == "\"" || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
else if (ch == "#") {
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
return ret("atom", "hash");
|
||||
}
|
||||
else if (ch == "!") {
|
||||
stream.match(/^\s*\w*/);
|
||||
return ret("keyword", "important");
|
||||
}
|
||||
else if (/\d/.test(ch)) {
|
||||
stream.eatWhile(/[\w.%]/);
|
||||
return ret("number", "unit");
|
||||
}
|
||||
else if (ch === "-") {
|
||||
if (/\d/.test(stream.peek())) {
|
||||
stream.eatWhile(/[\w.%]/);
|
||||
return ret("number", "unit");
|
||||
} else if (stream.match(/^[^-]+-/)) {
|
||||
return ret("meta", "meta");
|
||||
}
|
||||
}
|
||||
else if (/[,+>*\/]/.test(ch)) {
|
||||
return ret(null, "select-op");
|
||||
}
|
||||
else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
|
||||
return ret("qualifier", "qualifier");
|
||||
}
|
||||
else if (ch == ":") {
|
||||
return ret("operator", ch);
|
||||
}
|
||||
else if (/[;{}\[\]\(\)]/.test(ch)) {
|
||||
return ret(null, ch);
|
||||
}
|
||||
else if (ch == "u" && stream.match("rl(")) {
|
||||
stream.backUp(1);
|
||||
state.tokenize = tokenParenthesized;
|
||||
return ret("property", "variable");
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
return ret("property", "variable");
|
||||
}
|
||||
}
|
||||
|
||||
function tokenString(quote, nonInclusive) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == quote && !escaped)
|
||||
break;
|
||||
escaped = !escaped && ch == "\\";
|
||||
}
|
||||
if (!escaped) {
|
||||
if (nonInclusive) stream.backUp(1);
|
||||
state.tokenize = tokenBase;
|
||||
}
|
||||
return ret("string", "string");
|
||||
};
|
||||
}
|
||||
|
||||
function tokenParenthesized(stream, state) {
|
||||
stream.next(); // Must be '('
|
||||
if (!stream.match(/\s*[\"\']/, false))
|
||||
state.tokenize = tokenString(")", true);
|
||||
else
|
||||
state.tokenize = tokenBase;
|
||||
return ret(null, "(");
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function(base) {
|
||||
return {tokenize: tokenBase,
|
||||
baseIndent: base || 0,
|
||||
stack: []};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
|
||||
// Use these terms when applicable (see http://www.xanthir.com/blog/b4E50)
|
||||
//
|
||||
// rule** or **ruleset:
|
||||
// A selector + braces combo, or an at-rule.
|
||||
//
|
||||
// declaration block:
|
||||
// A sequence of declarations.
|
||||
//
|
||||
// declaration:
|
||||
// A property + colon + value combo.
|
||||
//
|
||||
// property value:
|
||||
// The entire value of a property.
|
||||
//
|
||||
// component value:
|
||||
// A single piece of a property value. Like the 5px in
|
||||
// text-shadow: 0 0 5px blue;. Can also refer to things that are
|
||||
// multiple terms, like the 1-4 terms that make up the background-size
|
||||
// portion of the background shorthand.
|
||||
//
|
||||
// term:
|
||||
// The basic unit of author-facing CSS, like a single number (5),
|
||||
// dimension (5px), string ("foo"), or function. Officially defined
|
||||
// by the CSS 2.1 grammar (look for the 'term' production)
|
||||
//
|
||||
//
|
||||
// simple selector:
|
||||
// A single atomic selector, like a type selector, an attr selector, a
|
||||
// class selector, etc.
|
||||
//
|
||||
// compound selector:
|
||||
// One or more simple selectors without a combinator. div.example is
|
||||
// compound, div > .example is not.
|
||||
//
|
||||
// complex selector:
|
||||
// One or more compound selectors chained with combinators.
|
||||
//
|
||||
// combinator:
|
||||
// The parts of selectors that express relationships. There are four
|
||||
// currently - the space (descendant combinator), the greater-than
|
||||
// bracket (child combinator), the plus sign (next sibling combinator),
|
||||
// and the tilda (following sibling combinator).
|
||||
//
|
||||
// sequence of selectors:
|
||||
// One or more of the named type of selector chained with commas.
|
||||
|
||||
state.tokenize = state.tokenize || tokenBase;
|
||||
if (state.tokenize == tokenBase && stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if (style && typeof style != "string") style = ret(style[0], style[1]);
|
||||
|
||||
// Changing style returned based on context
|
||||
var context = state.stack[state.stack.length-1];
|
||||
if (style == "variable") {
|
||||
if (type == "variable-definition") state.stack.push("propertyValue");
|
||||
return "variable-2";
|
||||
} else if (style == "property") {
|
||||
if (context == "propertyValue"){
|
||||
if (valueKeywords[stream.current()]) {
|
||||
style = "string-2";
|
||||
} else if (colorKeywords[stream.current()]) {
|
||||
style = "keyword";
|
||||
} else {
|
||||
style = "variable-2";
|
||||
}
|
||||
} else if (context == "rule") {
|
||||
if (!propertyKeywords[stream.current()]) {
|
||||
style += " error";
|
||||
}
|
||||
} else if (context == "block") {
|
||||
// if a value is present in both property, value, or color, the order
|
||||
// of preference is property -> color -> value
|
||||
if (propertyKeywords[stream.current()]) {
|
||||
style = "property";
|
||||
} else if (colorKeywords[stream.current()]) {
|
||||
style = "keyword";
|
||||
} else if (valueKeywords[stream.current()]) {
|
||||
style = "string-2";
|
||||
} else {
|
||||
style = "tag";
|
||||
}
|
||||
} else if (!context || context == "@media{") {
|
||||
style = "tag";
|
||||
} else if (context == "@media") {
|
||||
if (atMediaTypes[stream.current()]) {
|
||||
style = "attribute"; // Known attribute
|
||||
} else if (/^(only|not)$/i.test(stream.current())) {
|
||||
style = "keyword";
|
||||
} else if (stream.current().toLowerCase() == "and") {
|
||||
style = "error"; // "and" is only allowed in @mediaType
|
||||
} else if (atMediaFeatures[stream.current()]) {
|
||||
style = "error"; // Known property, should be in @mediaType(
|
||||
} else {
|
||||
// Unknown, expecting keyword or attribute, assuming attribute
|
||||
style = "attribute error";
|
||||
}
|
||||
} else if (context == "@mediaType") {
|
||||
if (atMediaTypes[stream.current()]) {
|
||||
style = "attribute";
|
||||
} else if (stream.current().toLowerCase() == "and") {
|
||||
style = "operator";
|
||||
} else if (/^(only|not)$/i.test(stream.current())) {
|
||||
style = "error"; // Only allowed in @media
|
||||
} else if (atMediaFeatures[stream.current()]) {
|
||||
style = "error"; // Known property, should be in parentheses
|
||||
} else {
|
||||
// Unknown attribute or property, but expecting property (preceded
|
||||
// by "and"). Should be in parentheses
|
||||
style = "error";
|
||||
}
|
||||
} else if (context == "@mediaType(") {
|
||||
if (propertyKeywords[stream.current()]) {
|
||||
// do nothing, remains "property"
|
||||
} else if (atMediaTypes[stream.current()]) {
|
||||
style = "error"; // Known property, should be in parentheses
|
||||
} else if (stream.current().toLowerCase() == "and") {
|
||||
style = "operator";
|
||||
} else if (/^(only|not)$/i.test(stream.current())) {
|
||||
style = "error"; // Only allowed in @media
|
||||
} else {
|
||||
style += " error";
|
||||
}
|
||||
} else {
|
||||
style = "error";
|
||||
}
|
||||
} else if (style == "atom") {
|
||||
if(!context || context == "@media{" || context == "block") {
|
||||
style = "builtin";
|
||||
} else if (context == "propertyValue") {
|
||||
if (!/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
|
||||
style += " error";
|
||||
}
|
||||
} else {
|
||||
style = "error";
|
||||
}
|
||||
} else if (context == "@media" && type == "{") {
|
||||
style = "error";
|
||||
}
|
||||
|
||||
// Push/pop context stack
|
||||
if (type == "{") {
|
||||
if (context == "@media" || context == "@mediaType") {
|
||||
state.stack.pop();
|
||||
state.stack[state.stack.length-1] = "@media{";
|
||||
}
|
||||
else {
|
||||
var newContext = allowNested ? "block" : "rule";
|
||||
state.stack.push(newContext);
|
||||
}
|
||||
}
|
||||
else if (type == "}") {
|
||||
var lastState = state.stack[state.stack.length - 1];
|
||||
if (lastState == "interpolation") style = "operator";
|
||||
state.stack.pop();
|
||||
if (context == "propertyValue") state.stack.pop();
|
||||
}
|
||||
else if (type == "interpolation") state.stack.push("interpolation");
|
||||
else if (type == "@media") state.stack.push("@media");
|
||||
else if (context == "@media" && /\b(keyword|attribute)\b/.test(style))
|
||||
state.stack.push("@mediaType");
|
||||
else if (context == "@mediaType" && stream.current() == ",") state.stack.pop();
|
||||
else if (context == "@mediaType" && type == "(") state.stack.push("@mediaType(");
|
||||
else if (context == "@mediaType(" && type == ")") state.stack.pop();
|
||||
else if ((context == "rule" || context == "block") && type == ":") state.stack.push("propertyValue");
|
||||
else if (context == "propertyValue" && type == ";") state.stack.pop();
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
var n = state.stack.length;
|
||||
if (/^\}/.test(textAfter))
|
||||
n -= state.stack[state.stack.length-1] == "propertyValue" ? 2 : 1;
|
||||
return state.baseIndent + n * indentUnit;
|
||||
},
|
||||
|
||||
electricChars: "}"
|
||||
};
|
||||
});
|
||||
|
||||
(function() {
|
||||
function keySet(array) {
|
||||
var keys = {};
|
||||
for (var i = 0; i < array.length; ++i) {
|
||||
keys[array[i]] = true;
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
var atMediaTypes = keySet([
|
||||
"all", "aural", "braille", "handheld", "print", "projection", "screen",
|
||||
"tty", "tv", "embossed"
|
||||
]);
|
||||
|
||||
var atMediaFeatures = keySet([
|
||||
"width", "min-width", "max-width", "height", "min-height", "max-height",
|
||||
"device-width", "min-device-width", "max-device-width", "device-height",
|
||||
"min-device-height", "max-device-height", "aspect-ratio",
|
||||
"min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
|
||||
"min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
|
||||
"max-color", "color-index", "min-color-index", "max-color-index",
|
||||
"monochrome", "min-monochrome", "max-monochrome", "resolution",
|
||||
"min-resolution", "max-resolution", "scan", "grid"
|
||||
]);
|
||||
|
||||
var propertyKeywords = keySet([
|
||||
"align-content", "align-items", "align-self", "alignment-adjust",
|
||||
"alignment-baseline", "anchor-point", "animation", "animation-delay",
|
||||
"animation-direction", "animation-duration", "animation-iteration-count",
|
||||
"animation-name", "animation-play-state", "animation-timing-function",
|
||||
"appearance", "azimuth", "backface-visibility", "background",
|
||||
"background-attachment", "background-clip", "background-color",
|
||||
"background-image", "background-origin", "background-position",
|
||||
"background-repeat", "background-size", "baseline-shift", "binding",
|
||||
"bleed", "bookmark-label", "bookmark-level", "bookmark-state",
|
||||
"bookmark-target", "border", "border-bottom", "border-bottom-color",
|
||||
"border-bottom-left-radius", "border-bottom-right-radius",
|
||||
"border-bottom-style", "border-bottom-width", "border-collapse",
|
||||
"border-color", "border-image", "border-image-outset",
|
||||
"border-image-repeat", "border-image-slice", "border-image-source",
|
||||
"border-image-width", "border-left", "border-left-color",
|
||||
"border-left-style", "border-left-width", "border-radius", "border-right",
|
||||
"border-right-color", "border-right-style", "border-right-width",
|
||||
"border-spacing", "border-style", "border-top", "border-top-color",
|
||||
"border-top-left-radius", "border-top-right-radius", "border-top-style",
|
||||
"border-top-width", "border-width", "bottom", "box-decoration-break",
|
||||
"box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
|
||||
"caption-side", "clear", "clip", "color", "color-profile", "column-count",
|
||||
"column-fill", "column-gap", "column-rule", "column-rule-color",
|
||||
"column-rule-style", "column-rule-width", "column-span", "column-width",
|
||||
"columns", "content", "counter-increment", "counter-reset", "crop", "cue",
|
||||
"cue-after", "cue-before", "cursor", "direction", "display",
|
||||
"dominant-baseline", "drop-initial-after-adjust",
|
||||
"drop-initial-after-align", "drop-initial-before-adjust",
|
||||
"drop-initial-before-align", "drop-initial-size", "drop-initial-value",
|
||||
"elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
|
||||
"flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
|
||||
"float", "float-offset", "font", "font-feature-settings", "font-family",
|
||||
"font-kerning", "font-language-override", "font-size", "font-size-adjust",
|
||||
"font-stretch", "font-style", "font-synthesis", "font-variant",
|
||||
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
|
||||
"font-variant-ligatures", "font-variant-numeric", "font-variant-position",
|
||||
"font-weight", "grid-cell", "grid-column", "grid-column-align",
|
||||
"grid-column-sizing", "grid-column-span", "grid-columns", "grid-flow",
|
||||
"grid-row", "grid-row-align", "grid-row-sizing", "grid-row-span",
|
||||
"grid-rows", "grid-template", "hanging-punctuation", "height", "hyphens",
|
||||
"icon", "image-orientation", "image-rendering", "image-resolution",
|
||||
"inline-box-align", "justify-content", "left", "letter-spacing",
|
||||
"line-break", "line-height", "line-stacking", "line-stacking-ruby",
|
||||
"line-stacking-shift", "line-stacking-strategy", "list-style",
|
||||
"list-style-image", "list-style-position", "list-style-type", "margin",
|
||||
"margin-bottom", "margin-left", "margin-right", "margin-top",
|
||||
"marker-offset", "marks", "marquee-direction", "marquee-loop",
|
||||
"marquee-play-count", "marquee-speed", "marquee-style", "max-height",
|
||||
"max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
|
||||
"nav-left", "nav-right", "nav-up", "opacity", "order", "orphans", "outline",
|
||||
"outline-color", "outline-offset", "outline-style", "outline-width",
|
||||
"overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
|
||||
"padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
|
||||
"page", "page-break-after", "page-break-before", "page-break-inside",
|
||||
"page-policy", "pause", "pause-after", "pause-before", "perspective",
|
||||
"perspective-origin", "pitch", "pitch-range", "play-during", "position",
|
||||
"presentation-level", "punctuation-trim", "quotes", "rendering-intent",
|
||||
"resize", "rest", "rest-after", "rest-before", "richness", "right",
|
||||
"rotation", "rotation-point", "ruby-align", "ruby-overhang",
|
||||
"ruby-position", "ruby-span", "size", "speak", "speak-as", "speak-header",
|
||||
"speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
|
||||
"tab-size", "table-layout", "target", "target-name", "target-new",
|
||||
"target-position", "text-align", "text-align-last", "text-decoration",
|
||||
"text-decoration-color", "text-decoration-line", "text-decoration-skip",
|
||||
"text-decoration-style", "text-emphasis", "text-emphasis-color",
|
||||
"text-emphasis-position", "text-emphasis-style", "text-height",
|
||||
"text-indent", "text-justify", "text-outline", "text-shadow",
|
||||
"text-space-collapse", "text-transform", "text-underline-position",
|
||||
"text-wrap", "top", "transform", "transform-origin", "transform-style",
|
||||
"transition", "transition-delay", "transition-duration",
|
||||
"transition-property", "transition-timing-function", "unicode-bidi",
|
||||
"vertical-align", "visibility", "voice-balance", "voice-duration",
|
||||
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
|
||||
"voice-volume", "volume", "white-space", "widows", "width", "word-break",
|
||||
"word-spacing", "word-wrap", "z-index"
|
||||
]);
|
||||
|
||||
var colorKeywords = keySet([
|
||||
"black", "silver", "gray", "white", "maroon", "red", "purple", "fuchsia",
|
||||
"green", "lime", "olive", "yellow", "navy", "blue", "teal", "aqua"
|
||||
]);
|
||||
|
||||
var valueKeywords = keySet([
|
||||
"above", "absolute", "activeborder", "activecaption", "afar",
|
||||
"after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
|
||||
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
|
||||
"arabic-indic", "armenian", "asterisks", "auto", "avoid", "background",
|
||||
"backwards", "baseline", "below", "bidi-override", "binary", "bengali",
|
||||
"blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
|
||||
"both", "bottom", "break-all", "break-word", "button", "button-bevel",
|
||||
"buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian",
|
||||
"capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
|
||||
"cell", "center", "checkbox", "circle", "cjk-earthly-branch",
|
||||
"cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
|
||||
"col-resize", "collapse", "compact", "condensed", "contain", "content",
|
||||
"content-box", "context-menu", "continuous", "copy", "cover", "crop",
|
||||
"cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal",
|
||||
"decimal-leading-zero", "default", "default-button", "destination-atop",
|
||||
"destination-in", "destination-out", "destination-over", "devanagari",
|
||||
"disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted",
|
||||
"double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
|
||||
"element", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
|
||||
"ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
|
||||
"ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
|
||||
"ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
|
||||
"ethiopic-halehame-gez", "ethiopic-halehame-om-et",
|
||||
"ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
|
||||
"ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et",
|
||||
"ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed",
|
||||
"extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes",
|
||||
"forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
|
||||
"gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew",
|
||||
"help", "hidden", "hide", "higher", "highlight", "highlighttext",
|
||||
"hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
|
||||
"inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
|
||||
"infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
|
||||
"inline-block", "inline-table", "inset", "inside", "intrinsic", "invert",
|
||||
"italic", "justify", "kannada", "katakana", "katakana-iroha", "khmer",
|
||||
"landscape", "lao", "large", "larger", "left", "level", "lighter",
|
||||
"line-through", "linear", "lines", "list-item", "listbox", "listitem",
|
||||
"local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
|
||||
"lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
|
||||
"lower-roman", "lowercase", "ltr", "malayalam", "match",
|
||||
"media-controls-background", "media-current-time-display",
|
||||
"media-fullscreen-button", "media-mute-button", "media-play-button",
|
||||
"media-return-to-realtime-button", "media-rewind-button",
|
||||
"media-seek-back-button", "media-seek-forward-button", "media-slider",
|
||||
"media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
|
||||
"media-volume-slider-container", "media-volume-sliderthumb", "medium",
|
||||
"menu", "menulist", "menulist-button", "menulist-text",
|
||||
"menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
|
||||
"mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize",
|
||||
"narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
|
||||
"no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
|
||||
"ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
|
||||
"optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
|
||||
"outside", "overlay", "overline", "padding", "padding-box", "painted",
|
||||
"paused", "persian", "plus-darker", "plus-lighter", "pointer", "portrait",
|
||||
"pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button",
|
||||
"radio", "read-only", "read-write", "read-write-plaintext-only", "relative",
|
||||
"repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba",
|
||||
"ridge", "right", "round", "row-resize", "rtl", "run-in", "running",
|
||||
"s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield",
|
||||
"searchfield-cancel-button", "searchfield-decoration",
|
||||
"searchfield-results-button", "searchfield-results-decoration",
|
||||
"semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
|
||||
"single", "skip-white-space", "slide", "slider-horizontal",
|
||||
"slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
|
||||
"small", "small-caps", "small-caption", "smaller", "solid", "somali",
|
||||
"source-atop", "source-in", "source-out", "source-over", "space", "square",
|
||||
"square-button", "start", "static", "status-bar", "stretch", "stroke",
|
||||
"sub", "subpixel-antialiased", "super", "sw-resize", "table",
|
||||
"table-caption", "table-cell", "table-column", "table-column-group",
|
||||
"table-footer-group", "table-header-group", "table-row", "table-row-group",
|
||||
"telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
|
||||
"thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
|
||||
"threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
|
||||
"tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
|
||||
"transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
|
||||
"upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
|
||||
"upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
|
||||
"vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
|
||||
"visibleStroke", "visual", "w-resize", "wait", "wave", "white", "wider",
|
||||
"window", "windowframe", "windowtext", "x-large", "x-small", "xor",
|
||||
"xx-large", "xx-small"
|
||||
]);
|
||||
|
||||
function tokenCComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (maybeEnd && ch == "/") {
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ["comment", "comment"];
|
||||
}
|
||||
|
||||
CodeMirror.defineMIME("text/css", {
|
||||
atMediaTypes: atMediaTypes,
|
||||
atMediaFeatures: atMediaFeatures,
|
||||
propertyKeywords: propertyKeywords,
|
||||
colorKeywords: colorKeywords,
|
||||
valueKeywords: valueKeywords,
|
||||
hooks: {
|
||||
"<": function(stream, state) {
|
||||
function tokenSGMLComment(stream, state) {
|
||||
var dashes = 0, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (dashes >= 2 && ch == ">") {
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
dashes = (ch == "-") ? dashes + 1 : 0;
|
||||
}
|
||||
return ["comment", "comment"];
|
||||
}
|
||||
if (stream.eat("!")) {
|
||||
state.tokenize = tokenSGMLComment;
|
||||
return tokenSGMLComment(stream, state);
|
||||
}
|
||||
},
|
||||
"/": function(stream, state) {
|
||||
if (stream.eat("*")) {
|
||||
state.tokenize = tokenCComment;
|
||||
return tokenCComment(stream, state);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
name: "css-base"
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-scss", {
|
||||
atMediaTypes: atMediaTypes,
|
||||
atMediaFeatures: atMediaFeatures,
|
||||
propertyKeywords: propertyKeywords,
|
||||
colorKeywords: colorKeywords,
|
||||
valueKeywords: valueKeywords,
|
||||
allowNested: true,
|
||||
hooks: {
|
||||
"$": function(stream) {
|
||||
stream.match(/^[\w-]+/);
|
||||
if (stream.peek() == ":") {
|
||||
return ["variable", "variable-definition"];
|
||||
}
|
||||
return ["variable", "variable"];
|
||||
},
|
||||
"/": function(stream, state) {
|
||||
if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ["comment", "comment"];
|
||||
} else if (stream.eat("*")) {
|
||||
state.tokenize = tokenCComment;
|
||||
return tokenCComment(stream, state);
|
||||
} else {
|
||||
return ["operator", "operator"];
|
||||
}
|
||||
},
|
||||
"#": function(stream) {
|
||||
if (stream.eat("{")) {
|
||||
return ["operator", "interpolation"];
|
||||
} else {
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
return ["atom", "hash"];
|
||||
}
|
||||
}
|
||||
},
|
||||
name: "css-base"
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,104 @@
|
|||
CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
|
||||
var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
|
||||
var cssMode = CodeMirror.getMode(config, "css");
|
||||
|
||||
var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
|
||||
scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
|
||||
mode: CodeMirror.getMode(config, "javascript")});
|
||||
if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
|
||||
var conf = scriptTypesConf[i];
|
||||
scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
|
||||
}
|
||||
scriptTypes.push({matches: /./,
|
||||
mode: CodeMirror.getMode(config, "text/plain")});
|
||||
|
||||
function html(stream, state) {
|
||||
var tagName = state.htmlState.tagName;
|
||||
var style = htmlMode.token(stream, state.htmlState);
|
||||
if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") {
|
||||
// Script block: mode to change to depends on type attribute
|
||||
var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
|
||||
scriptType = scriptType ? scriptType[1] : "";
|
||||
if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);
|
||||
for (var i = 0; i < scriptTypes.length; ++i) {
|
||||
var tp = scriptTypes[i];
|
||||
if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
|
||||
if (tp.mode) {
|
||||
state.token = script;
|
||||
state.localMode = tp.mode;
|
||||
state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") {
|
||||
state.token = css;
|
||||
state.localMode = cssMode;
|
||||
state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
|
||||
}
|
||||
return style;
|
||||
}
|
||||
function maybeBackup(stream, pat, style) {
|
||||
var cur = stream.current();
|
||||
var close = cur.search(pat), m;
|
||||
if (close > -1) stream.backUp(cur.length - close);
|
||||
else if (m = cur.match(/<\/?$/)) {
|
||||
stream.backUp(cur.length);
|
||||
if (!stream.match(pat, false)) stream.match(cur[0]);
|
||||
}
|
||||
return style;
|
||||
}
|
||||
function script(stream, state) {
|
||||
if (stream.match(/^<\/\s*script\s*>/i, false)) {
|
||||
state.token = html;
|
||||
state.localState = state.localMode = null;
|
||||
return html(stream, state);
|
||||
}
|
||||
return maybeBackup(stream, /<\/\s*script\s*>/,
|
||||
state.localMode.token(stream, state.localState));
|
||||
}
|
||||
function css(stream, state) {
|
||||
if (stream.match(/^<\/\s*style\s*>/i, false)) {
|
||||
state.token = html;
|
||||
state.localState = state.localMode = null;
|
||||
return html(stream, state);
|
||||
}
|
||||
return maybeBackup(stream, /<\/\s*style\s*>/,
|
||||
cssMode.token(stream, state.localState));
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
var state = htmlMode.startState();
|
||||
return {token: html, localMode: null, localState: null, htmlState: state};
|
||||
},
|
||||
|
||||
copyState: function(state) {
|
||||
if (state.localState)
|
||||
var local = CodeMirror.copyState(state.localMode, state.localState);
|
||||
return {token: state.token, localMode: state.localMode, localState: local,
|
||||
htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
return state.token(stream, state);
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (!state.localMode || /^\s*<\//.test(textAfter))
|
||||
return htmlMode.indent(state.htmlState, textAfter);
|
||||
else if (state.localMode.indent)
|
||||
return state.localMode.indent(state.localState, textAfter);
|
||||
else
|
||||
return CodeMirror.Pass;
|
||||
},
|
||||
|
||||
electricChars: "/{}:",
|
||||
|
||||
innerMode: function(state) {
|
||||
return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
|
||||
}
|
||||
};
|
||||
}, "xml", "javascript", "css");
|
||||
|
||||
CodeMirror.defineMIME("text/html", "htmlmixed");
|
|
@ -0,0 +1,437 @@
|
|||
// TODO actually recognize syntax of TypeScript constructs
|
||||
|
||||
CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var jsonMode = parserConfig.json;
|
||||
var isTS = parserConfig.typescript;
|
||||
|
||||
// Tokenizer
|
||||
|
||||
var keywords = function(){
|
||||
function kw(type) {return {type: type, style: "keyword"};}
|
||||
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
|
||||
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
|
||||
|
||||
var jsKeywords = {
|
||||
"if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
|
||||
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
|
||||
"var": kw("var"), "const": kw("var"), "let": kw("var"),
|
||||
"function": kw("function"), "catch": kw("catch"),
|
||||
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
|
||||
"in": operator, "typeof": operator, "instanceof": operator,
|
||||
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
|
||||
"this": kw("this")
|
||||
};
|
||||
|
||||
// Extend the 'normal' keywords with the TypeScript language extensions
|
||||
if (isTS) {
|
||||
var type = {type: "variable", style: "variable-3"};
|
||||
var tsKeywords = {
|
||||
// object-like things
|
||||
"interface": kw("interface"),
|
||||
"class": kw("class"),
|
||||
"extends": kw("extends"),
|
||||
"constructor": kw("constructor"),
|
||||
|
||||
// scope modifiers
|
||||
"public": kw("public"),
|
||||
"private": kw("private"),
|
||||
"protected": kw("protected"),
|
||||
"static": kw("static"),
|
||||
|
||||
"super": kw("super"),
|
||||
|
||||
// types
|
||||
"string": type, "number": type, "bool": type, "any": type
|
||||
};
|
||||
|
||||
for (var attr in tsKeywords) {
|
||||
jsKeywords[attr] = tsKeywords[attr];
|
||||
}
|
||||
}
|
||||
|
||||
return jsKeywords;
|
||||
}();
|
||||
|
||||
var isOperatorChar = /[+\-*&%=<>!?|~^]/;
|
||||
|
||||
function chain(stream, state, f) {
|
||||
state.tokenize = f;
|
||||
return f(stream, state);
|
||||
}
|
||||
|
||||
function nextUntilUnescaped(stream, end) {
|
||||
var escaped = false, next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == end && !escaped)
|
||||
return false;
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
return escaped;
|
||||
}
|
||||
|
||||
// Used as scratch variables to communicate multiple values without
|
||||
// consing up tons of objects.
|
||||
var type, content;
|
||||
function ret(tp, style, cont) {
|
||||
type = tp; content = cont;
|
||||
return style;
|
||||
}
|
||||
|
||||
function jsTokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == '"' || ch == "'")
|
||||
return chain(stream, state, jsTokenString(ch));
|
||||
else if (/[\[\]{}\(\),;\:\.]/.test(ch))
|
||||
return ret(ch);
|
||||
else if (ch == "0" && stream.eat(/x/i)) {
|
||||
stream.eatWhile(/[\da-f]/i);
|
||||
return ret("number", "number");
|
||||
}
|
||||
else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
|
||||
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
|
||||
return ret("number", "number");
|
||||
}
|
||||
else if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
return chain(stream, state, jsTokenComment);
|
||||
}
|
||||
else if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
else if (state.lastType == "operator" || state.lastType == "keyword c" ||
|
||||
/^[\[{}\(,;:]$/.test(state.lastType)) {
|
||||
nextUntilUnescaped(stream, "/");
|
||||
stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
|
||||
return ret("regexp", "string-2");
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", null, stream.current());
|
||||
}
|
||||
}
|
||||
else if (ch == "#") {
|
||||
stream.skipToEnd();
|
||||
return ret("error", "error");
|
||||
}
|
||||
else if (isOperatorChar.test(ch)) {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", null, stream.current());
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
|
||||
return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
|
||||
ret("variable", "variable", word);
|
||||
}
|
||||
}
|
||||
|
||||
function jsTokenString(quote) {
|
||||
return function(stream, state) {
|
||||
if (!nextUntilUnescaped(stream, quote))
|
||||
state.tokenize = jsTokenBase;
|
||||
return ret("string", "string");
|
||||
};
|
||||
}
|
||||
|
||||
function jsTokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = jsTokenBase;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
|
||||
// Parser
|
||||
|
||||
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true};
|
||||
|
||||
function JSLexical(indented, column, type, align, prev, info) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.prev = prev;
|
||||
this.info = info;
|
||||
if (align != null) this.align = align;
|
||||
}
|
||||
|
||||
function inScope(state, varname) {
|
||||
for (var v = state.localVars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
}
|
||||
|
||||
function parseJS(state, style, type, content, stream) {
|
||||
var cc = state.cc;
|
||||
// Communicate our context to the combinators.
|
||||
// (Less wasteful than consing up a hundred closures on every call.)
|
||||
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
|
||||
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = true;
|
||||
|
||||
while(true) {
|
||||
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
|
||||
if (combinator(type, content)) {
|
||||
while(cc.length && cc[cc.length - 1].lex)
|
||||
cc.pop()();
|
||||
if (cx.marked) return cx.marked;
|
||||
if (type == "variable" && inScope(state, content)) return "variable-2";
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combinator utils
|
||||
|
||||
var cx = {state: null, column: null, marked: null, cc: null};
|
||||
function pass() {
|
||||
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
|
||||
}
|
||||
function cont() {
|
||||
pass.apply(null, arguments);
|
||||
return true;
|
||||
}
|
||||
function register(varname) {
|
||||
function inList(list) {
|
||||
for (var v = list; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
return false;
|
||||
}
|
||||
var state = cx.state;
|
||||
if (state.context) {
|
||||
cx.marked = "def";
|
||||
if (inList(state.localVars)) return;
|
||||
state.localVars = {name: varname, next: state.localVars};
|
||||
} else {
|
||||
if (inList(state.globalVars)) return;
|
||||
state.globalVars = {name: varname, next: state.globalVars};
|
||||
}
|
||||
}
|
||||
|
||||
// Combinators
|
||||
|
||||
var defaultVars = {name: "this", next: {name: "arguments"}};
|
||||
function pushcontext() {
|
||||
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
|
||||
cx.state.localVars = defaultVars;
|
||||
}
|
||||
function popcontext() {
|
||||
cx.state.localVars = cx.state.context.vars;
|
||||
cx.state.context = cx.state.context.prev;
|
||||
}
|
||||
function pushlex(type, info) {
|
||||
var result = function() {
|
||||
var state = cx.state;
|
||||
state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info);
|
||||
};
|
||||
result.lex = true;
|
||||
return result;
|
||||
}
|
||||
function poplex() {
|
||||
var state = cx.state;
|
||||
if (state.lexical.prev) {
|
||||
if (state.lexical.type == ")")
|
||||
state.indented = state.lexical.indented;
|
||||
state.lexical = state.lexical.prev;
|
||||
}
|
||||
}
|
||||
poplex.lex = true;
|
||||
|
||||
function expect(wanted) {
|
||||
return function(type) {
|
||||
if (type == wanted) return cont();
|
||||
else if (wanted == ";") return pass();
|
||||
else return cont(arguments.callee);
|
||||
};
|
||||
}
|
||||
|
||||
function statement(type) {
|
||||
if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
|
||||
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
|
||||
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
|
||||
if (type == "{") return cont(pushlex("}"), block, poplex);
|
||||
if (type == ";") return cont();
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
|
||||
poplex, statement, poplex);
|
||||
if (type == "variable") return cont(pushlex("stat"), maybelabel);
|
||||
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
|
||||
block, poplex, poplex);
|
||||
if (type == "case") return cont(expression, expect(":"));
|
||||
if (type == "default") return cont(expect(":"));
|
||||
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
|
||||
statement, poplex, popcontext);
|
||||
return pass(pushlex("stat"), expression, expect(";"), poplex);
|
||||
}
|
||||
function expression(type) {
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "keyword c") return cont(maybeexpression);
|
||||
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator);
|
||||
if (type == "operator") return cont(expression);
|
||||
if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
|
||||
if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
|
||||
return cont();
|
||||
}
|
||||
function maybeexpression(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expression);
|
||||
}
|
||||
|
||||
function maybeoperator(type, value) {
|
||||
if (type == "operator") {
|
||||
if (/\+\+|--/.test(value)) return cont(maybeoperator);
|
||||
if (value == "?") return cont(expression, expect(":"), expression);
|
||||
return cont(expression);
|
||||
}
|
||||
if (type == ";") return;
|
||||
if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
|
||||
if (type == ".") return cont(property, maybeoperator);
|
||||
if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
|
||||
}
|
||||
function maybelabel(type) {
|
||||
if (type == ":") return cont(poplex, statement);
|
||||
return pass(maybeoperator, expect(";"), poplex);
|
||||
}
|
||||
function property(type) {
|
||||
if (type == "variable") {cx.marked = "property"; return cont();}
|
||||
}
|
||||
function objprop(type, value) {
|
||||
if (type == "variable") {
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(getterSetter);
|
||||
} else if (type == "number" || type == "string") {
|
||||
cx.marked = type + " property";
|
||||
}
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
|
||||
}
|
||||
function getterSetter(type) {
|
||||
if (type == ":") return cont(expression);
|
||||
if (type != "variable") return cont(expect(":"), expression);
|
||||
cx.marked = "property";
|
||||
return cont(functiondef);
|
||||
}
|
||||
function commasep(what, end) {
|
||||
function proceed(type) {
|
||||
if (type == ",") return cont(what, proceed);
|
||||
if (type == end) return cont();
|
||||
return cont(expect(end));
|
||||
}
|
||||
return function(type) {
|
||||
if (type == end) return cont();
|
||||
else return pass(what, proceed);
|
||||
};
|
||||
}
|
||||
function block(type) {
|
||||
if (type == "}") return cont();
|
||||
return pass(statement, block);
|
||||
}
|
||||
function maybetype(type) {
|
||||
if (type == ":") return cont(typedef);
|
||||
return pass();
|
||||
}
|
||||
function typedef(type) {
|
||||
if (type == "variable"){cx.marked = "variable-3"; return cont();}
|
||||
return pass();
|
||||
}
|
||||
function vardef1(type, value) {
|
||||
if (type == "variable") {
|
||||
register(value);
|
||||
return isTS ? cont(maybetype, vardef2) : cont(vardef2);
|
||||
}
|
||||
return pass();
|
||||
}
|
||||
function vardef2(type, value) {
|
||||
if (value == "=") return cont(expression, vardef2);
|
||||
if (type == ",") return cont(vardef1);
|
||||
}
|
||||
function forspec1(type) {
|
||||
if (type == "var") return cont(vardef1, expect(";"), forspec2);
|
||||
if (type == ";") return cont(forspec2);
|
||||
if (type == "variable") return cont(formaybein);
|
||||
return cont(forspec2);
|
||||
}
|
||||
function formaybein(_type, value) {
|
||||
if (value == "in") return cont(expression);
|
||||
return cont(maybeoperator, forspec2);
|
||||
}
|
||||
function forspec2(type, value) {
|
||||
if (type == ";") return cont(forspec3);
|
||||
if (value == "in") return cont(expression);
|
||||
return cont(expression, expect(";"), forspec3);
|
||||
}
|
||||
function forspec3(type) {
|
||||
if (type != ")") cont(expression);
|
||||
}
|
||||
function functiondef(type, value) {
|
||||
if (type == "variable") {register(value); return cont(functiondef);}
|
||||
if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
|
||||
}
|
||||
function funarg(type, value) {
|
||||
if (type == "variable") {register(value); return isTS ? cont(maybetype) : cont();}
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
return {
|
||||
tokenize: jsTokenBase,
|
||||
lastType: null,
|
||||
cc: [],
|
||||
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
|
||||
localVars: parserConfig.localVars,
|
||||
globalVars: parserConfig.globalVars,
|
||||
context: parserConfig.localVars && {vars: parserConfig.localVars},
|
||||
indented: 0
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.sol()) {
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = false;
|
||||
state.indented = stream.indentation();
|
||||
}
|
||||
if (stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if (type == "comment") return style;
|
||||
state.lastType = type;
|
||||
return parseJS(state, style, type, content, stream);
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize == jsTokenComment) return CodeMirror.Pass;
|
||||
if (state.tokenize != jsTokenBase) return 0;
|
||||
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
|
||||
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
|
||||
var type = lexical.type, closing = firstChar == type;
|
||||
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0);
|
||||
else if (type == "form" && firstChar == "{") return lexical.indented;
|
||||
else if (type == "form") return lexical.indented + indentUnit;
|
||||
else if (type == "stat")
|
||||
return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? indentUnit : 0);
|
||||
else if (lexical.info == "switch" && !closing)
|
||||
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
|
||||
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
|
||||
else return lexical.indented + (closing ? 0 : indentUnit);
|
||||
},
|
||||
|
||||
electricChars: ":{}",
|
||||
|
||||
jsonMode: jsonMode
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/javascript", "javascript");
|
||||
CodeMirror.defineMIME("text/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
|
||||
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
|
||||
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
|
|
@ -0,0 +1,328 @@
|
|||
CodeMirror.defineMode("xml", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
|
||||
|
||||
var Kludges = parserConfig.htmlMode ? {
|
||||
autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
|
||||
'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
|
||||
'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
|
||||
'track': true, 'wbr': true},
|
||||
implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
|
||||
'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
|
||||
'th': true, 'tr': true},
|
||||
contextGrabbers: {
|
||||
'dd': {'dd': true, 'dt': true},
|
||||
'dt': {'dd': true, 'dt': true},
|
||||
'li': {'li': true},
|
||||
'option': {'option': true, 'optgroup': true},
|
||||
'optgroup': {'optgroup': true},
|
||||
'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
|
||||
'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
|
||||
'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
|
||||
'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
|
||||
'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
|
||||
'rp': {'rp': true, 'rt': true},
|
||||
'rt': {'rp': true, 'rt': true},
|
||||
'tbody': {'tbody': true, 'tfoot': true},
|
||||
'td': {'td': true, 'th': true},
|
||||
'tfoot': {'tbody': true},
|
||||
'th': {'td': true, 'th': true},
|
||||
'thead': {'tbody': true, 'tfoot': true},
|
||||
'tr': {'tr': true}
|
||||
},
|
||||
doNotIndent: {"pre": true},
|
||||
allowUnquoted: true,
|
||||
allowMissing: true
|
||||
} : {
|
||||
autoSelfClosers: {},
|
||||
implicitlyClosed: {},
|
||||
contextGrabbers: {},
|
||||
doNotIndent: {},
|
||||
allowUnquoted: false,
|
||||
allowMissing: false
|
||||
};
|
||||
var alignCDATA = parserConfig.alignCDATA;
|
||||
|
||||
// Return variables for tokenizers
|
||||
var tagName, type;
|
||||
|
||||
function inText(stream, state) {
|
||||
function chain(parser) {
|
||||
state.tokenize = parser;
|
||||
return parser(stream, state);
|
||||
}
|
||||
|
||||
var ch = stream.next();
|
||||
if (ch == "<") {
|
||||
if (stream.eat("!")) {
|
||||
if (stream.eat("[")) {
|
||||
if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
|
||||
else return null;
|
||||
}
|
||||
else if (stream.match("--")) return chain(inBlock("comment", "-->"));
|
||||
else if (stream.match("DOCTYPE", true, true)) {
|
||||
stream.eatWhile(/[\w\._\-]/);
|
||||
return chain(doctype(1));
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
else if (stream.eat("?")) {
|
||||
stream.eatWhile(/[\w\._\-]/);
|
||||
state.tokenize = inBlock("meta", "?>");
|
||||
return "meta";
|
||||
}
|
||||
else {
|
||||
var isClose = stream.eat("/");
|
||||
tagName = "";
|
||||
var c;
|
||||
while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
|
||||
if (!tagName) return "error";
|
||||
type = isClose ? "closeTag" : "openTag";
|
||||
state.tokenize = inTag;
|
||||
return "tag";
|
||||
}
|
||||
}
|
||||
else if (ch == "&") {
|
||||
var ok;
|
||||
if (stream.eat("#")) {
|
||||
if (stream.eat("x")) {
|
||||
ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
|
||||
} else {
|
||||
ok = stream.eatWhile(/[\d]/) && stream.eat(";");
|
||||
}
|
||||
} else {
|
||||
ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
|
||||
}
|
||||
return ok ? "atom" : "error";
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(/[^&<]/);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function inTag(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
|
||||
state.tokenize = inText;
|
||||
type = ch == ">" ? "endTag" : "selfcloseTag";
|
||||
return "tag";
|
||||
}
|
||||
else if (ch == "=") {
|
||||
type = "equals";
|
||||
return null;
|
||||
}
|
||||
else if (/[\'\"]/.test(ch)) {
|
||||
state.tokenize = inAttribute(ch);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(/[^\s\u00a0=<>\"\']/);
|
||||
return "word";
|
||||
}
|
||||
}
|
||||
|
||||
function inAttribute(quote) {
|
||||
return function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
if (stream.next() == quote) {
|
||||
state.tokenize = inTag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "string";
|
||||
};
|
||||
}
|
||||
|
||||
function inBlock(style, terminator) {
|
||||
return function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
if (stream.match(terminator)) {
|
||||
state.tokenize = inText;
|
||||
break;
|
||||
}
|
||||
stream.next();
|
||||
}
|
||||
return style;
|
||||
};
|
||||
}
|
||||
function doctype(depth) {
|
||||
return function(stream, state) {
|
||||
var ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == "<") {
|
||||
state.tokenize = doctype(depth + 1);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == ">") {
|
||||
if (depth == 1) {
|
||||
state.tokenize = inText;
|
||||
break;
|
||||
} else {
|
||||
state.tokenize = doctype(depth - 1);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "meta";
|
||||
};
|
||||
}
|
||||
|
||||
var curState, curStream, setStyle;
|
||||
function pass() {
|
||||
for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
|
||||
}
|
||||
function cont() {
|
||||
pass.apply(null, arguments);
|
||||
return true;
|
||||
}
|
||||
|
||||
function pushContext(tagName, startOfLine) {
|
||||
var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
|
||||
curState.context = {
|
||||
prev: curState.context,
|
||||
tagName: tagName,
|
||||
indent: curState.indented,
|
||||
startOfLine: startOfLine,
|
||||
noIndent: noIndent
|
||||
};
|
||||
}
|
||||
function popContext() {
|
||||
if (curState.context) curState.context = curState.context.prev;
|
||||
}
|
||||
|
||||
function element(type) {
|
||||
if (type == "openTag") {
|
||||
curState.tagName = tagName;
|
||||
curState.tagStart = curStream.column();
|
||||
return cont(attributes, endtag(curState.startOfLine));
|
||||
} else if (type == "closeTag") {
|
||||
var err = false;
|
||||
if (curState.context) {
|
||||
if (curState.context.tagName != tagName) {
|
||||
if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
|
||||
popContext();
|
||||
}
|
||||
err = !curState.context || curState.context.tagName != tagName;
|
||||
}
|
||||
} else {
|
||||
err = true;
|
||||
}
|
||||
if (err) setStyle = "error";
|
||||
return cont(endclosetag(err));
|
||||
}
|
||||
return cont();
|
||||
}
|
||||
function endtag(startOfLine) {
|
||||
return function(type) {
|
||||
var tagName = curState.tagName;
|
||||
curState.tagName = curState.tagStart = null;
|
||||
if (type == "selfcloseTag" ||
|
||||
(type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase()))) {
|
||||
maybePopContext(tagName.toLowerCase());
|
||||
return cont();
|
||||
}
|
||||
if (type == "endTag") {
|
||||
maybePopContext(tagName.toLowerCase());
|
||||
pushContext(tagName, startOfLine);
|
||||
return cont();
|
||||
}
|
||||
return cont();
|
||||
};
|
||||
}
|
||||
function endclosetag(err) {
|
||||
return function(type) {
|
||||
if (err) setStyle = "error";
|
||||
if (type == "endTag") { popContext(); return cont(); }
|
||||
setStyle = "error";
|
||||
return cont(arguments.callee);
|
||||
};
|
||||
}
|
||||
function maybePopContext(nextTagName) {
|
||||
var parentTagName;
|
||||
while (true) {
|
||||
if (!curState.context) {
|
||||
return;
|
||||
}
|
||||
parentTagName = curState.context.tagName.toLowerCase();
|
||||
if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
|
||||
!Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
|
||||
return;
|
||||
}
|
||||
popContext();
|
||||
}
|
||||
}
|
||||
|
||||
function attributes(type) {
|
||||
if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
|
||||
if (type == "endTag" || type == "selfcloseTag") return pass();
|
||||
setStyle = "error";
|
||||
return cont(attributes);
|
||||
}
|
||||
function attribute(type) {
|
||||
if (type == "equals") return cont(attvalue, attributes);
|
||||
if (!Kludges.allowMissing) setStyle = "error";
|
||||
else if (type == "word") setStyle = "attribute";
|
||||
return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
|
||||
}
|
||||
function attvalue(type) {
|
||||
if (type == "string") return cont(attvaluemaybe);
|
||||
if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
|
||||
setStyle = "error";
|
||||
return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
|
||||
}
|
||||
function attvaluemaybe(type) {
|
||||
if (type == "string") return cont(attvaluemaybe);
|
||||
else return pass();
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, tagStart: null, context: null};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (!state.tagName && stream.sol()) {
|
||||
state.startOfLine = true;
|
||||
state.indented = stream.indentation();
|
||||
}
|
||||
if (stream.eatSpace()) return null;
|
||||
|
||||
setStyle = type = tagName = null;
|
||||
var style = state.tokenize(stream, state);
|
||||
state.type = type;
|
||||
if ((style || type) && style != "comment") {
|
||||
curState = state; curStream = stream;
|
||||
while (true) {
|
||||
var comb = state.cc.pop() || element;
|
||||
if (comb(type || style)) break;
|
||||
}
|
||||
}
|
||||
state.startOfLine = false;
|
||||
return setStyle || style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter, fullLine) {
|
||||
var context = state.context;
|
||||
if ((state.tokenize != inTag && state.tokenize != inText) ||
|
||||
context && context.noIndent)
|
||||
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
|
||||
if (state.tagName) return state.tagStart + indentUnit * multilineTagIndentFactor;
|
||||
if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
|
||||
if (context && /^<\//.test(textAfter))
|
||||
context = context.prev;
|
||||
while (context && !context.startOfLine)
|
||||
context = context.prev;
|
||||
if (context) return context.indent + indentUnit;
|
||||
else return 0;
|
||||
},
|
||||
|
||||
electricChars: "/",
|
||||
|
||||
configuration: parserConfig.htmlMode ? "html" : "xml"
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/xml", "xml");
|
||||
CodeMirror.defineMIME("application/xml", "xml");
|
||||
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
|
||||
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'af', {
|
||||
toolbar: 'Bron',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'ar', {
|
||||
toolbar: 'المصدر',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'bg', {
|
||||
toolbar: 'Източник',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'bn', {
|
||||
toolbar: 'সোর্স',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'bs', {
|
||||
toolbar: 'HTML kôd',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'ca', {
|
||||
toolbar: 'Codi font',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'cs', {
|
||||
toolbar: 'Zdroj',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'cy', {
|
||||
toolbar: 'HTML',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'da', {
|
||||
toolbar: 'Kilde',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'de', {
|
||||
toolbar: 'Quellcode',
|
||||
searchCode: 'Quellcode durchsuchen',
|
||||
autoFormat: 'Auswahl formatieren',
|
||||
commentSelectedRange: 'Auswahl auskommentieren',
|
||||
uncommentSelectedRange: 'Auskommentierung entferen',
|
||||
autoCompleteToggle: 'HTML Tag Autvervollständigen de-/aktivieren'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'el', {
|
||||
toolbar: 'HTML κώδικας',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'en-au', {
|
||||
toolbar: 'Source',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'en-ca', {
|
||||
toolbar: 'Source',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'en-gb', {
|
||||
toolbar: 'Source',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'en', {
|
||||
toolbar: 'Source',
|
||||
searchCode: 'Search Source',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection',
|
||||
autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'eo', {
|
||||
toolbar: 'Fonto',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'es', {
|
||||
toolbar: 'Fuente HTML',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'et', {
|
||||
toolbar: 'Lähtekood',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.html or http://ckeditor.com/license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang( 'codemirror', 'eu', {
|
||||
toolbar: 'HTML Iturburua',
|
||||
autoFormat: 'Format Selection',
|
||||
commentSelectedRange: 'Comment Selection',
|
||||
uncommentSelectedRange: 'Uncomment Selection'
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue