Conflicts:
	app/controllers/repositories_controller.rb
	db/schema.rb
This commit is contained in:
nwb 2014-07-11 09:08:50 +08:00
commit 9b3ffc90ba
1091 changed files with 49039 additions and 489 deletions

View File

@ -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)

View File

@ -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
===============================================================================
0708CKEditor插件加载方法
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 点击“查询”(就是确定的功能)

View File

@ -62,6 +62,7 @@ class AttachmentsController < ApplicationController
end
rescue => e
redirect_to "http://" + (Setting.host_name.to_s) +"/file_not_found.html"
return
end
#更新资源文件类型

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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']

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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" > *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</span></span>
<span class="info" style="width: 10px"><%= text_field_tag :class_period, @course.class_period, :placeholder => "在此输入课时" %></span> <span>&nbsp;<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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</span></span>
<span class="info" style="width: 10px"><%= text_field_tag :class_period, @course.class_period, :placeholder => "在此输入课时" %></span> <span>&nbsp;<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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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"> *&nbsp;&nbsp;</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)%>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</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 %>

View File

@ -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 %>

View File

@ -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(){

View File

@ -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>

View File

@ -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'%>

View File

@ -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>

View File

@ -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
}

View File

@ -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) {

View File

@ -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>

View File

@ -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

View File

@ -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: 项目得分

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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|

View File

@ -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) ? ' *' : '&nbsp;&nbsp;'}".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))

3
plugins/redmine_ckeditor/.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "app/assets/javascripts/ckeditor-releases"]
path = app/assets/javascripts/ckeditor-releases
url = git://github.com/ckeditor/ckeditor-releases.git

View File

@ -0,0 +1,6 @@
source 'https://rubygems.org'
gem 'rich', '1.4.6'
gem 'kaminari'
gem 'htmlentities'
gem 'paperclip', '~> 3.5.4'

View File

@ -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]

View File

@ -0,0 +1,5 @@
//
//= require rich/editor/ckeditor_path
//= require ckeditor-releases/ckeditor
//= require rich/editor/rich_editor
//= require rich/editor/rich_picker

View File

@ -0,0 +1,4 @@
//= require fileuploader
//= require rich/browser/extensions
//= require rich/browser/uploader
//= require rich/browser/filebrowser

View File

@ -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

View File

@ -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 %>

View File

@ -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");

View File

@ -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>

View File

@ -0,0 +1,2 @@
<%= render :file => "messages/quote" %>
CKEDITOR.instances['message_content'].setData($('#message_content').val());

View File

@ -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>

View File

@ -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 %>

View File

@ -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;
}

View File

@ -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;
}
}

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

View File

@ -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; });
}
});
})();

View File

@ -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;
}
})();

View File

@ -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;
}
})();

View File

@ -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);
});
})();

View File

@ -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');
};
}());

View File

@ -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);});
})();

View File

@ -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)};
};

View File

@ -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
});
};
};

View File

@ -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]);
}
}
};
})();

View File

@ -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 });
});
});
})();

View File

@ -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));
});
});
})();

View File

@ -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();
}};
}
})();

View File

@ -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);};
})();

View File

@ -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 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

View File

@ -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"
});
})();

View File

@ -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");

View File

@ -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 });

View File

@ -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});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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'
});

View File

@ -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