Merge branch 'sw_new_course' into dev_hjq
This commit is contained in:
commit
4fd90464d9
1
Gemfile
1
Gemfile
|
@ -6,6 +6,7 @@ unless RUBY_PLATFORM =~ /w32/
|
|||
gem 'iconv'
|
||||
end
|
||||
|
||||
gem 'grack', path:'./lib/grack'
|
||||
gem 'rest-client'
|
||||
gem "mysql2", "= 0.3.18"
|
||||
gem 'redis-rails'
|
||||
|
|
|
@ -127,19 +127,18 @@ update
|
|||
end
|
||||
else # 原逻辑
|
||||
##xianbo
|
||||
params[:repository_scm] = "Git"
|
||||
@root_path=RepositoriesHelper::ROOT_PATH
|
||||
@repository_name=User.current.login.to_s+"/"+params[:repository][:identifier]+".git"
|
||||
@project_path=@root_path+"htdocs/"+@repository_name
|
||||
@repository_tag=params[:repository][:upassword] || params[:repository][:password]
|
||||
@repository_tag=params[:repository][:upassword] || params[:repository][:password] || '1234'
|
||||
@repo_name=User.current.login.to_s+"_"+params[:repository][:identifier]
|
||||
logger.info "htpasswd -mb "+@root_path+"htdocs/user.passwd "+@repo_name+": "+@repository_tag
|
||||
logger.info "the value of create repository"+@root_path+": "+@repository_name+": "+@project_path+": "+@repo_name
|
||||
attrs = pickup_extra_info
|
||||
if((@repository_tag!="")&¶ms[:repository_scm]=="Git")
|
||||
params[:repository][:url]=@project_path
|
||||
end
|
||||
params[:repository][:url]=@project_path
|
||||
###xianbo
|
||||
@repository = Repository.factory(params[:repository_scm])
|
||||
@repository = Repository.factory(params[:repository_scm]||"Git")
|
||||
@repository.safe_attributes = params[:repository]
|
||||
if attrs[:attrs_extra].keys.any?
|
||||
@repository.merge_extra_info(attrs[:attrs_extra])
|
||||
|
@ -278,7 +277,8 @@ update
|
|||
@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.to_s+
|
||||
# @repos_url = "http://"+@repository.login.to_s+"_"+@repository.identifier.to_s+"@"+ip.to_s+
|
||||
@repos_url = "http://#{Setting.host_name}/#{@repository.login.to_s}/#{@repository.identifier.to_s}.git"
|
||||
@repository.url.slice(project_path_cut, @repository.url.length).to_s
|
||||
if @course_tag == 1
|
||||
render :action => 'show', :layout => 'base_courses'
|
||||
|
|
|
@ -52,7 +52,7 @@ class UsersController < ApplicationController
|
|||
:watch_contests, :info, :watch_projects, :show_score, :topic_score_index, :project_score_index,
|
||||
:activity_score_index, :influence_score_index, :score_index,:show_new_score, :topic_new_score_index, :project_new_score_index,
|
||||
:activity_new_score_index, :influence_new_score_index, :score_new_index,:user_projects_index,:user_resource,
|
||||
:user_courses4show,:user_projects4show,:user_course_activities,:user_project_activities,:user_feedback4show,:user_visitorlist,:user_messages]
|
||||
:user_courses4show,:user_projects4show,:user_course_activities,:user_project_activities,:user_feedback4show,:user_visitorlist,:user_messages,:edit_brief_introduction]
|
||||
before_filter :auth_user_extension, only: :show
|
||||
#before_filter :rest_user_score, only: :show
|
||||
#before_filter :select_entry, only: :user_projects
|
||||
|
@ -177,7 +177,7 @@ class UsersController < ApplicationController
|
|||
return
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html{render :layout=>'base_users_new'}
|
||||
format.html{render :layout=>'new_base_user'}
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -584,7 +584,7 @@ class UsersController < ApplicationController
|
|||
end
|
||||
|
||||
def show
|
||||
render :layout=>'base_users_new'
|
||||
render :layout=>'new_base_user'
|
||||
end
|
||||
|
||||
def show_old
|
||||
|
@ -933,13 +933,13 @@ class UsersController < ApplicationController
|
|||
end
|
||||
end
|
||||
@type = params[:type] || 1
|
||||
@limit = 10
|
||||
@limit = 15
|
||||
@is_remote = true
|
||||
@obj_count = @attachments.count
|
||||
@obj_pages = Paginator.new @obj_count, @limit, params['page'] || 1
|
||||
@offset ||= @obj_pages.offset
|
||||
@atta_count = @attachments.count
|
||||
@atta_pages = Paginator.new @atta_count, @limit, params['page'] || 1
|
||||
@offset ||= @atta_pages.offset
|
||||
#@curse_attachments_all = @all_attachments[@offset, @limit]
|
||||
@attachments = paginateHelper @attachments,10
|
||||
@attachments = paginateHelper @attachments,15
|
||||
respond_to do |format|
|
||||
format.js
|
||||
end
|
||||
|
@ -989,13 +989,13 @@ class UsersController < ApplicationController
|
|||
end
|
||||
end
|
||||
@type = params[:type]
|
||||
@limit = 10
|
||||
@limit = 15
|
||||
@is_remote = true
|
||||
@obj_count = @attachments.count
|
||||
@obj_pages = Paginator.new @obj_count, @limit, params['page'] || 1
|
||||
@offset ||= @obj_pages.offset
|
||||
@atta_count = @attachments.count
|
||||
@atta_pages = Paginator.new @atta_count, @limit, params['page'] || 1
|
||||
@offset ||= @atta_pages.offset
|
||||
#@curse_attachments_all = @all_attachments[@offset, @limit]
|
||||
@attachments = paginateHelper @attachments,10
|
||||
@attachments = paginateHelper @attachments,15
|
||||
respond_to do |format|
|
||||
format.js
|
||||
end
|
||||
|
@ -1362,6 +1362,16 @@ class UsersController < ApplicationController
|
|||
@user = User.find(params[:id])
|
||||
end
|
||||
|
||||
#修改个人简介
|
||||
def edit_brief_introduction
|
||||
if @user && @user.extensions
|
||||
@user.extensions.update_column("brief_introduction",params[:brief_introduction])
|
||||
end
|
||||
respond_to do |format|
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
# 资源库 分为全部 课程资源 项目资源 附件
|
||||
def user_resource
|
||||
#确定container_type
|
||||
|
@ -1405,13 +1415,13 @@ class UsersController < ApplicationController
|
|||
end
|
||||
end
|
||||
@type = params[:type]
|
||||
@limit = 10
|
||||
@limit = 15
|
||||
@is_remote = true
|
||||
@obj_count = @attachments.count
|
||||
@obj_pages = Paginator.new @obj_count, @limit, params['page'] || 1
|
||||
@offset ||= @obj_pages.offset
|
||||
@atta_count = @attachments.count
|
||||
@atta_pages = Paginator.new @atta_count, @limit, params['page'] || 1
|
||||
@offset ||= @atta_pages.offset
|
||||
#@curse_attachments_all = @all_attachments[@offset, @limit]
|
||||
@attachments = paginateHelper @attachments,10
|
||||
@attachments = paginateHelper @attachments,15
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.html {render :layout => 'base_users_new'}
|
||||
|
@ -1436,7 +1446,7 @@ class UsersController < ApplicationController
|
|||
elsif params[:type] == "2" #课程资源
|
||||
if User.current.id.to_i == params[:id].to_i
|
||||
user_course_ids = User.current.courses.map { |c| c.id}
|
||||
@attachments = Attachment.where("(author_id = #{params[:id]} and container_type = 'Course') or (container_type = 'Course' and container_id in (#{user_course_ids.empty? ? '0': user_course_ids.join(',')})) ").order("created_on desc")
|
||||
@attachments = Attachment.where("(author_id = #{params[:id]} and container_type = 'Course') or (container_type = 'Course' and container_id in (#{user_course_ids.empty? ? '0': user_course_ids.join(',')})) and (filename like '%#{search}%') ").order("created_on desc")
|
||||
else
|
||||
user_course_ids = User.find(params[:id]).courses.visible.map { |c| c.id} #如果课程私有资源,那么要看这个资源的课程是不是在 这个user的所有我可见的课程中
|
||||
@attachments = Attachment.where("((author_id = #{params[:id]} and is_public = 1 and container_type = 'Course') "+
|
||||
|
@ -1457,13 +1467,13 @@ class UsersController < ApplicationController
|
|||
end
|
||||
end
|
||||
@type = params[:type]
|
||||
@limit = 10
|
||||
@limit = 15
|
||||
@is_remote = true
|
||||
@obj_count = @attachments.count
|
||||
@obj_pages = Paginator.new @obj_count, @limit, params['page'] || 1
|
||||
@offset ||= @obj_pages.offset
|
||||
@atta_count = @attachments.count
|
||||
@atta_pages = Paginator.new @atta_count, @limit, params['page'] || 1
|
||||
@offset ||= @atta_pages.offset
|
||||
#@curse_attachments_all = @all_attachments[@offset, @limit]
|
||||
@attachments = paginateHelper @attachments,10
|
||||
@attachments = paginateHelper @attachments,15
|
||||
respond_to do |format|
|
||||
format.js
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
module RepositoriesHelper
|
||||
if Rails.env.development?
|
||||
ROOT_PATH="/tmp/" if Rails.env.development?
|
||||
ROOT_PATH="/private/tmp/"
|
||||
else
|
||||
ROOT_PATH="/home/pdl/redmine-2.3.2-0/apache2/"
|
||||
end
|
||||
|
|
|
@ -4,4 +4,27 @@ class CourseActivity < ActiveRecord::Base
|
|||
belongs_to :course_act ,:polymorphic => true
|
||||
belongs_to :course
|
||||
belongs_to :user
|
||||
has_many :user_acts, :class_name => 'UserAcivity',:as =>:act
|
||||
after_save :add_user_activity
|
||||
before_destroy :destroy_user_activity
|
||||
|
||||
#在个人动态里面增加当前动态
|
||||
def add_user_activity
|
||||
user_activity = UserActivity.where("act_type = '#{self.class.to_s}' and act_id = '#{self.id}'").first
|
||||
if user_activity
|
||||
user_activity.save
|
||||
else
|
||||
user_activity = UserActivity.new
|
||||
user_activity.act_id = self.id
|
||||
user_activity.act_type = self.class.to_s
|
||||
user_activity.container_type = "Course"
|
||||
user_activity.container_id = self.course_id
|
||||
user_activity.save
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_user_activity
|
||||
user_activity = UserActivity.where("act_type = '#{self.class.to_s}' and act_id = '#{self.id}'")
|
||||
user_activity.destroy_all
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,5 +19,27 @@ class ForgeActivity < ActiveRecord::Base
|
|||
validates :project_id,presence: true
|
||||
validates :forge_act_id,presence: true
|
||||
validates :forge_act_type, presence: true
|
||||
has_many :user_acts, :class_name => 'UserAcivity',:as =>:act
|
||||
after_save :add_user_activity
|
||||
before_destroy :destroy_user_activity
|
||||
|
||||
#在个人动态里面增加当前动态
|
||||
def add_user_activity
|
||||
user_activity = UserActivity.where("act_type = '#{self.class.to_s}' and act_id = '#{self.id}'").first
|
||||
if user_activity
|
||||
user_activity.save
|
||||
else
|
||||
user_activity = UserActivity.new
|
||||
user_activity.act_id = self.id
|
||||
user_activity.act_type = self.class.to_s
|
||||
user_activity.container_type = "Project"
|
||||
user_activity.container_id = self.project_id
|
||||
user_activity.save
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_user_activity
|
||||
user_activity = UserActivity.where("act_type = '#{self.class.to_s}' and act_id = '#{self.id}'")
|
||||
user_activity.destroy_all
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
class UserActivity < ActiveRecord::Base
|
||||
attr_accessible :act_type,:act_id,:container_type,:container_id
|
||||
# 虚拟关联---项目动态表/课程动态表
|
||||
belongs_to :act ,:polymorphic => true
|
||||
# 虚拟关联---项目/课程
|
||||
belongs_to :container ,:polymorphic => true
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
<div class="navHomepage">
|
||||
<div class="navHomepageLogo fl">
|
||||
<%=link_to image_tag("../images/logo.png",width:"51px", height: "45px",class: "mt3"), user_activities_path(User.current.id)%>
|
||||
</div>
|
||||
<div class="fl">
|
||||
<ul>
|
||||
<li class="navHomepageMenu fl">
|
||||
<a href="javascript:void(0);" class="homepageWhite f16">首页</a>
|
||||
</li>
|
||||
<li class="navHomepageMenu fl">
|
||||
<a href="javascript:void(0);" class="homepageWhite f16">资源库</a></li>
|
||||
<li class="navHomepageMenu fl">
|
||||
<a href="javascript:void(0);" class="homepageWhite f16">作业</a>
|
||||
</li>
|
||||
<li class="navHomepageMenu fl">
|
||||
<a href="javascript:void(0);" class="homepageWhite f16">联系人</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="fl">
|
||||
<form class="navHomepageSearchBox">
|
||||
<input type="text" name="navHomepageSearch" class="navHomepageSearchInput" />
|
||||
<a href="javascript:void(0);" class="homepageSearchIcon"></a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="navHomepageProfile">
|
||||
<ul>
|
||||
<li class="homepageProfileMenuIcon">
|
||||
<%= link_to "<div class='mt5 mb8'>#{image_tag(url_to_avatar(User.current),:width =>"40",:height => "40",:alt=>"头像", :id => "nh_user_logo")}</div>".html_safe,user_activities_path(User.current.id)%>
|
||||
<ul class="topnav_login_list">
|
||||
<li><a href="javascript:void(0);" class="menuGrey">修改资料</a> </li>
|
||||
<li><a href="javascript:void(0);" class="menuGrey">账号设置</a> </li>
|
||||
<li><a href="javascript:void(0);" class="menuGrey">退出</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="navHomepageNews">
|
||||
<%= link_to image_tag("/images/news_icon_small.png" , :width => "21", :height => "24"), {:controller=> 'users', :action => 'user_messages', id: User.current.id, host: Setting.host_user} %>
|
||||
<% if User.current.count_new_message >0 %>
|
||||
<div class="newsActive"></div>
|
||||
<% end %>
|
||||
<div class="newsActive"></div>
|
||||
</div>
|
||||
</div>
|
|
@ -21,14 +21,15 @@
|
|||
</a>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="msgserver">
|
||||
<div class="mt5">
|
||||
<a target="hiddentab" href="http://wpa.qq.com/msgrd?v=1&uin=1554253403&site=qq&menu=yes" style="color: #15BCCF;">
|
||||
<%= l(:label_technical_support) %>白 羽</a>
|
||||
<iframe name="hiddentab" style="display: none"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
<div class="side_bottom"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="show_btn"><span>在线客服</span></div>
|
||||
<div class="show_btn">
|
||||
<span>在线客服</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<div class="navHomepage">
|
||||
<div class="navHomepageLogo fl">
|
||||
<%=link_to image_tag("../images/logo.png",weight:"51px", height: "45px",class: "mt3")%>
|
||||
</div>
|
||||
<div class="fl">
|
||||
<ul>
|
||||
<li class="navHomepageMenu fl"><a href="javascript:void(0);" class="homepageWhite f16">首页</a></li>
|
||||
<li class="navHomepageMenu fl"><a href="javascript:void(0);" class="homepageWhite f16">资源库</a></li>
|
||||
<li class="navHomepageMenu fl"><a href="javascript:void(0);" class="homepageWhite f16">作业</a></li>
|
||||
<li class="navHomepageMenu fl"><a href="javascript:void(0);" class="homepageWhite f16">联系人</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="fl">
|
||||
<form class="navHomepageSearchBox">
|
||||
<input type="text" name="navHomepageSearch" class="navHomepageSearchInput" />
|
||||
<a href="javascript:void(0);" class="homepageSearchIcon"></a>
|
||||
</form>
|
||||
</div>
|
||||
<div class="navHomepageProfile">
|
||||
<ul>
|
||||
<li class="homepageProfileMenuIcon">
|
||||
<a href="javascript:void(0);">
|
||||
<div class="mt5 mb8">
|
||||
<img src="images/homepageProfileImage.png" width="40" height="40" />
|
||||
</div>
|
||||
</a>
|
||||
<ul class="topnav_login_list">
|
||||
<li><a href="javascript:void(0);" class="menuGrey">修改资料</a> </li>
|
||||
<li><a href="javascript:void(0);" class="menuGrey">账号设置</a> </li>
|
||||
<li><a href="javascript:void(0);" class="menuGrey">退出</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="navHomepageNews">
|
||||
<a href="javascript:void(0);" class="homepageNewsIcon">
|
||||
<div class="newsActive"></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,10 @@
|
|||
<% if user.user_extensions && user.user_extensions.brief_introduction && !user.user_extensions.brief_introduction.empty? %>
|
||||
<%= user.user_extensions.brief_introduction %>
|
||||
<% else%>
|
||||
这位童鞋很懒,什么也没有留下~
|
||||
<% end %>
|
||||
<% if User.current == user%>
|
||||
<a href="javascript:void(0);" onclick="show_edit_user_introduction();">
|
||||
<img src="../images/signature_edit.png" width="12" height="12" />
|
||||
</a>
|
||||
<% end%>
|
|
@ -1,11 +1,7 @@
|
|||
<% if User.current.logged?%>
|
||||
<% if User.current == target%>
|
||||
<a href="<%= url_for(:controller => 'my', :action => 'account') %>" class="fr gz_btn mr10 ">编辑资料</a>
|
||||
<%else%>
|
||||
<%if(target.watched_by?(User.current))%>
|
||||
<a id="user_watch_id" href="<%= watch_path(:object_type=> 'user',:object_id=>target.id,:target_id=>target.id) %>" class="fr qx_btn mr10" data-method="delete" data-remote="true" title="取消关注">取消关注</a>
|
||||
<% else %>
|
||||
<a id="user_watch_id" href="<%= watch_path(:object_type=>'user',:object_id=>target.id,:target_id=>target.id) %>" class="fr gz_btn mr10" data-method="post" data-remote="true" title="添加关注">添加关注</a>
|
||||
<% end %>
|
||||
<% end%>
|
||||
<%if(target.watched_by?(User.current))%>
|
||||
<%= link_to "",watch_path(:object_type=> 'user',:object_id=>target.id,:target_id=>target.id),:class => "homepageFollow", :method => "delete",:remote => "true", :title => "取消关注"%>
|
||||
<% else %>
|
||||
<%= link_to "",watch_path(:object_type=> 'user',:object_id=>target.id,:target_id=>target.id),:class => "homepageFollowCancel", :method => "post",:remote => "true", :title => "添加关注"%>
|
||||
<% end %>
|
||||
<% end %>
|
|
@ -0,0 +1,212 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title><%= h html_title %></title>
|
||||
<meta name="description" content="<%= Redmine::Info.app_name %>" />
|
||||
<meta name="keywords" content="issue,bug,tracker" />
|
||||
<%= csrf_meta_tag %>
|
||||
<%= favicon %>
|
||||
<%= stylesheet_link_tag 'jquery/jquery-ui-1.9.2', 'new_public', 'user_leftside', :media => 'all' %>
|
||||
<%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %>
|
||||
<%= javascript_heads %>
|
||||
<%= javascript_include_tag "bootstrap","avatars","new_user"%>
|
||||
<%= heads_for_theme %>
|
||||
<%= call_hook :view_layouts_base_html_head %>
|
||||
<%= yield :header_tags -%>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navContainer">
|
||||
<% is_current_user = User.current.logged? && User.current == @user%>
|
||||
<% if User.current.logged? %>
|
||||
<%= render :partial => 'layouts/logined_header' %>
|
||||
<% else%>
|
||||
<%= render :partial => 'layouts/unlogin_header' %>
|
||||
<% end%>
|
||||
</div>
|
||||
|
||||
<div class="homepageContentContainer">
|
||||
<div class="homepageContent">
|
||||
<div class="homepageLeft" id="LSide">
|
||||
<div class="homepagePortraitContainer">
|
||||
<div class="homepagePortraitImage" id="homepage_portrait_image">
|
||||
<%= image_tag(url_to_avatar(@user),width:"206", height: "206", :id=>'nh_user_tx') %>
|
||||
<% if User.current.logged?%>
|
||||
<% if is_current_user%>
|
||||
<div id="edit_user_file_btn" class="none">
|
||||
<div class="homepageEditProfile">
|
||||
<a href="<%= url_for(:controller => 'my', :action => 'clear_user_avatar_temp') %>" data-remote="true" class="homepageEditProfileIcon"></a>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div id="watch_user_btn" class="none">
|
||||
<%= render :partial => 'layouts/user_watch_btn', :locals => {:target => @user} %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end%>
|
||||
</div>
|
||||
<div>
|
||||
<div class="homepageImageName hidden">
|
||||
<%= @user.login %>
|
||||
</div>
|
||||
<% if (@user.user_extensions && (@user.user_extensions.identity != 2) ) %>
|
||||
<div class="<%= @user.user_extensions.gender == 1 ? 'homepageImageSexWomen' : 'homepageImageSexMan' %> "></div>
|
||||
<% end %>
|
||||
<%= link_to("编辑资料", my_account_path, :class => "fr gz_btn mr10") if is_current_user%>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="homepageSignature">
|
||||
<p id="user_brief_introduction_show">
|
||||
<%= render :partial => 'layouts/user_brief_introduction', :locals => {:user => @user} %>
|
||||
</p>
|
||||
</div>
|
||||
<textarea class="homepageSignatureTextarea none" placeholder="请输入回复" id="user_brief_introduction_edit" onblur="edit_user_introduction('<%= edit_brief_introduction_user_path(@user.id)%>');"><%= @user.user_extensions.brief_introduction %></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div class="homepageImageBlock">
|
||||
<div>
|
||||
<%= link_to User.watched_by(@user.id).count.to_s, {:controller=>"users", :action=>"user_watchlist",:id=>@user.id},:class=>"homepageImageNumber" %>
|
||||
</div>
|
||||
<div class="homepageImageText">关注</div>
|
||||
</div>
|
||||
<div class="homepageVerDiv"></div>
|
||||
<div class="homepageImageBlock">
|
||||
<div>
|
||||
<%= link_to @user.watcher_users.count.to_s, {:controller=>"users", :action=>"user_fanslist",:id=>@user.id},:class=>"homepageImageNumber", :id => "user_fans_number"%>
|
||||
</div>
|
||||
<div class="homepageImageText">粉丝</div>
|
||||
</div>
|
||||
<div class="homepageVerDiv"></div>
|
||||
<div class="homepageImageBlock">
|
||||
<div>
|
||||
<%= link_to(format("%.2f" ,get_option_number(@user,1).total_score ).to_i,
|
||||
{:controller => 'users', :action => 'show_new_score', :remote => true, :id => @user.id }, :class => 'homepageImageNumber',:id => 'user_score') %>
|
||||
</div>
|
||||
<div class="homepageImageText">积分</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="homepageLeftMenuContainer">
|
||||
<div class="homepageLeftMenuBlock">
|
||||
<%= link_to "动态",user_activities_path(@user.id),:class => "homepageMenuText"%>
|
||||
</div>
|
||||
<div class="homepageLeftMenuBlock">
|
||||
<a href="javascript:void(0);" class="homepageMenuText">课程</a>
|
||||
<a href="javascript:void(0);" class="homepageMenuSetting">
|
||||
<img src="../images/menu_setting.png" width="14" height="14" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="homepageLeftMenuCourses">
|
||||
<ul>
|
||||
<% courses = @user.courses.visible.select("courses.*,(SELECT MAX(created_at) FROM `course_activities` WHERE course_activities.course_id = courses.id) AS a").order("a desc").limit(5)%>
|
||||
<% courses.each do |course|%>
|
||||
<li class="homepageLeftMenuCoursesLine">
|
||||
<a href="<%= url_for(:controller => 'courses', :action=>"show", :id=>course.id, :host=>Setting.host_course) %>" class="coursesLineGrey">
|
||||
<%= course.name %>
|
||||
</a>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if courses.size == 5%>
|
||||
<li class="homepageLeftMenuMore">
|
||||
<a href="javascript:void(0);" class="homepageLeftMenuMoreIcon"></a>
|
||||
</li>
|
||||
<% end%>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="homepageLeftMenuBlock">
|
||||
<a href="javascript:void(0);" class="homepageMenuText">项目</a>
|
||||
<a href="javascript:void(0);" class="homepageMenuSetting">
|
||||
<img src="../images/menu_setting.png" width="14" height="14" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="homepageLeftMenuCourses">
|
||||
<ul>
|
||||
<% projects = @user.projects.visible.select("projects.*,(SELECT MAX(created_at) FROM `forge_activities` WHERE forge_activities.project_id = projects.id) AS a").order("a desc").limit(5)%>
|
||||
<% projects.each do |project|%>
|
||||
<li class="homepageLeftMenuCoursesLine">
|
||||
<a href="<%= url_for(:controller => 'projects', :action=>"show", :id=>project.id, :host=>Setting.host_name) %>" class="coursesLineGrey">
|
||||
<%= project.name %>
|
||||
</a>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if projects.size == 5%>
|
||||
<li class="homepageLeftMenuMore">
|
||||
<a href="javascript:void(0);" class="homepageLeftMenuMoreIcon"></a>
|
||||
</li>
|
||||
<% end%>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="homepageLeftMenuBlock">
|
||||
<a href="javascript:void(0);" class="homepageMenuText">留言</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="homepageLeftLabelContainer">
|
||||
<div class="project_Label_New">
|
||||
<span class="homepageLabelText">标签</span>
|
||||
<div class="tag_h ml10" >
|
||||
<%= render :partial => 'tags/user_tag', :locals => {:obj => @user,:object_flag => "1"}%>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="homepageRight">
|
||||
<%= yield %>
|
||||
</div>
|
||||
</div>
|
||||
<%= render :partial => 'layouts/new_feedback' %>
|
||||
</div>
|
||||
|
||||
<div id="ajax-modal" style="display:none;"></div>
|
||||
<div id="ajax-indicator" style="display:none;">
|
||||
<span><%= l(:label_loading) %></span>
|
||||
</div>
|
||||
<div id="nh_tx_dialog_html" class="white_content" style="display:none;">
|
||||
<div>
|
||||
<div><a href="javascript:hideModal();" class="box_close"></a></div>
|
||||
<div class="cl"></div>
|
||||
<div class="pro_new">
|
||||
<h3 class="box_h3 mb10">头像设置</h3>
|
||||
<div class="uppicBox">
|
||||
<%= file_field_tag 'avatar[image]',
|
||||
:id => nil,
|
||||
:class => 'uppic_btn',
|
||||
:style => 'width:70px;',#added by young
|
||||
:size => "1",
|
||||
:multiple => false,
|
||||
:onchange => 'addInputAvatar(this);',
|
||||
:data => {
|
||||
:max_file_size => Setting.attachment_max_size.to_i.kilobytes,
|
||||
:max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)),
|
||||
:max_concurrent_uploads => Redmine::Configuration['max_concurrent_ajax_uploads'].to_i,
|
||||
:file_type => Redmine::Configuration['pic_types'].to_s,
|
||||
:type_support_message => l(:error_pic_type),
|
||||
:upload_path => upload_avatar_path(:format => 'js'),
|
||||
:description_placeholder => nil ,# l(:label_optional_description)
|
||||
:source_type => @user.class.to_s,
|
||||
:source_id => @user.id.to_s
|
||||
} %>
|
||||
<!--<br/>-->
|
||||
<!--<span>只支持jpg,png,gif,大小不超过5M</span>-->
|
||||
</div>
|
||||
<div class="showpicBox">
|
||||
<p>预览</p>
|
||||
<%= image_tag(url_to_avatar(@user), :style=>"width:96px;height:96px;",:class=>"mb5 mt10",:nhname=>'avatar_image') %>
|
||||
<span >96px*96px</span> <br />
|
||||
<div class="mb20"></div>
|
||||
<%= image_tag(url_to_avatar(@user), :style=>"width:48px;height:48px;",:class=>"mb5",:nhname=>'avatar_image') %>
|
||||
<br />
|
||||
<span>48px*48px</span> <br />
|
||||
</div>
|
||||
<div class="cl mb10"></div>
|
||||
<a href="javascript:hideModal();" class=" fr grey_btn mr15"> 取 消</a>
|
||||
<a href="<%= url_for(:controller => 'my', :action => 'save_user_avatar') %>" data-remote="true" class="blue_btn fr mr10">确 定</a>
|
||||
</div><!--talknew end-->
|
||||
<div class="cl"></div>
|
||||
</div><!--floatbox end-->
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,2 +1,3 @@
|
|||
$("#nh_user_tx").replaceWith('<%= image_tag(url_to_avatar(@user), :id=>'nh_user_tx',:style=>"width:214px;height:214px;overflow:hidden",:alt=>"头像") %>');
|
||||
$("#nh_user_logo").replaceWith('<%= image_tag(url_to_avatar(@user), :id=>'nh_user_logo',:width =>"40",:height => "40",:alt=>"头像") %>');
|
||||
hideModal();
|
|
@ -62,15 +62,6 @@
|
|||
<%= labelled_form_for :repository, @repository, :url =>project_repositories_path(@project),:html => {:id => 'repository-form',:method=>"post"} do |f| %>
|
||||
<div id="pro_st_edit_ku" class="pro_st_edit_ku">
|
||||
<ul>
|
||||
<li >
|
||||
<label class="label02"><%=l(:label_scm)%>:</label>
|
||||
<%= select_tag('repository_scm',
|
||||
options_for_select(["Git"],@repository.class.name.demodulize),
|
||||
:data => {:remote => true, :method => 'get'})%>
|
||||
<% if @repository && ! @repository.class.scm_available %>
|
||||
<span class="c_grey"><%= l(:text_scm_command_not_available) %></span>
|
||||
<% end %>
|
||||
</li>
|
||||
<% unless judge_main_repository(@project) %>
|
||||
<li>
|
||||
<label class="label02"><%=l(:field_repository_is_default)%>:</label>
|
||||
|
@ -84,14 +75,9 @@
|
|||
<span class="c_grey"><%=l(:text_length_between,:min=>1,:max=>254)<<l(:text_project_identifier_info) %></span>
|
||||
<% end %>
|
||||
</li>
|
||||
<li >
|
||||
<label class="label02"><span class="c_red">*</span><%=l(:label_password)%></label>
|
||||
<%= f.password_field :upassword, :label=> "", :no_label => true %>
|
||||
<span class="c_grey"><%= l(:label_upassword_info)%></span>
|
||||
</li>
|
||||
<div class="cl"></div>
|
||||
</ul>
|
||||
<a href="#" onclick="$('#repository-form').submit();" class="blue_btn fl ml110"><%=l(:button_save)%></a>
|
||||
<a href="<%= settings_project_path(@project, :tab => 'repositories')%>" class="grey_btn fl ml10"><%=l(:button_cancel)%></a>
|
||||
</div><!--pro_st_edit_issues end-->
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
|
@ -33,8 +33,9 @@
|
|||
<div id="repos_git_more">
|
||||
<br>
|
||||
<div class=" c_dark f14">
|
||||
<p color="red">git 克隆和提交的用户名和密码为登录用户名和密码 </p>
|
||||
<p>项目代码请设置好正确的编码方式(utf-8),否则中文会出现乱码。</p>
|
||||
<p>通过cmd命令提示符进入代码对应文件夹的根目录,假设当前用户的登录名为user,版本库名称为demo,需要操作的版本库分支为branch。
|
||||
<p>通过cmd命令提示符进入代码对应文件夹的根目录,
|
||||
如果是首次提交代码,执行如下命令:</p>
|
||||
</div>
|
||||
<div class="repos_explain">
|
||||
|
@ -45,19 +46,19 @@
|
|||
<p>git commit -m "first commit"</p>
|
||||
|
||||
<p>git remote add origin
|
||||
http://user_demo@repository.trustie.net/user/demo.git
|
||||
<%= @repos_url %>
|
||||
</p>
|
||||
|
||||
<p>git config http.postBuffer 524288000 #设置本地post缓存为500MB</p>
|
||||
|
||||
<p>git push -u origin branch:branch</p>
|
||||
<p>git push -u origin master</p>
|
||||
</div>
|
||||
<!--repos_explain end-->
|
||||
<div class="c_dark f14">
|
||||
<p>已经有本地库,还没有配置远程地址,打开命令行执行如下:</p>
|
||||
</div>
|
||||
<div class="repos_explain">
|
||||
<p>git remote add origin http://user_demo@repository.trustie.net/user/demo.git</p>
|
||||
<p>git remote add origin <%= @repos_url %></p>
|
||||
|
||||
<p>git add .</p>
|
||||
|
||||
|
@ -65,14 +66,14 @@
|
|||
|
||||
<p>git config http.postBuffer 524288000 #设置本地post缓存为500MB</p>
|
||||
|
||||
<p>git push -u origin branch:branch</p>
|
||||
<p>git push -u origin master</p>
|
||||
</div>
|
||||
<!--repos_explain end-->
|
||||
<div class="c_dark f14">
|
||||
<p>已有远程地址,创建一个远程分支,并切换到该分支,打开命令行执行如下:</p>
|
||||
</div>
|
||||
<div class="repos_explain">
|
||||
<p>git clone http://user_demo@repository.trustie.net/user/demo.git</p>
|
||||
<p>git clone <%= @repos_url %></p>
|
||||
|
||||
<p>git push</p>
|
||||
|
||||
|
@ -86,7 +87,7 @@
|
|||
</div>
|
||||
<div class="repos_explain">
|
||||
<p>git remote add trustie
|
||||
http://user_demo@repository.trustie.net/user/demo.git
|
||||
<%= @repos_url %>
|
||||
</p>
|
||||
|
||||
<p>git add .</p>
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
$("#user_brief_introduction_show").html("<%= escape_javascript render(:partial => "layouts/user_brief_introduction", :locals => {:user => @user}) %>");
|
||||
$("#user_brief_introduction_show").show();
|
||||
$("#user_brief_introduction_edit").hide();
|
|
@ -1,2 +1,2 @@
|
|||
$("#resources_list").html('<%= escape_javascript( render :partial => 'resources_list' ,:locals=>{ :attachments => @attachments})%>');
|
||||
$("#pages").html('<%= pagination_links_full @obj_pages, @obj_count, :per_page_links => false, :remote => @is_remote, :flag => true %>');
|
||||
$("#pages").html('<%= pagination_links_full @atta_pages, @atta_count, :per_page_links => false, :remote => @is_remote, :flag => true %>');
|
|
@ -1,40 +1,221 @@
|
|||
<%= javascript_include_tag "/assets/kindeditor/kindeditor",'/assets/kindeditor/pasteimg',"user" %>
|
||||
<% @center_flag = (User.current == @user) %>
|
||||
<div class="top_new">
|
||||
<span class="<%= (@user.user_extensions.identity == 0 && @user.allowed_to?(:add_course, nil, :global => true)) ? 'top_new_bg' : 'top_newcourses_bg'%> fl"></span>
|
||||
<% if @user.allowed_to?(:add_project, nil, :global => true) %>
|
||||
<a href="<%= url_for(:controller => 'projects', :action => 'new',:host=>Setting.host_name) %>" class="bgreen_n_btn fr ml10 mt2" target="_blank">新建项目</a>
|
||||
<% else %>
|
||||
<a href="<%= join_project_projects_path %>" data-remote ="true" class="bgreen_n_btn fr mt2">加入项目</a>
|
||||
<% end %>
|
||||
|
||||
<% if @user.user_extensions.identity == 0 && @user.allowed_to?(:add_course, nil, :global => true) %>
|
||||
<a href="<%= url_for(:controller => 'courses', :action => 'new',:host=>Setting.host_course) %>" class="bgreen_n_btn fr mt2" target="_blank">新建课程</a>
|
||||
<% else %>
|
||||
<!--<a href="<%#= url_for(:controller => 'courses', :action => 'join_private_courses',:host=>Setting.host_course) %>" data-remote ="true" class="green_n_btn fr mt2">加入课程</a>-->
|
||||
<a href="<%= join_private_courses_courses_path %>" data-remote ="true" class="bgreen_n_btn fr mt2">加入课程</a>
|
||||
<% end %>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
|
||||
<div id="RSide" class="fl">
|
||||
|
||||
<div class="users_courses_box line_box mb10" nhname="list_more_div" style="display:none;">
|
||||
<h4 class="users_h4">课程动态</h4>
|
||||
<div nhname="container" data-nodatamsg="暂无动态" data-url="<%= url_for(:controller => 'users', :action => 'user_course_activities') %>" data-isclose="0" data-currpage="0" data-hasmore="1"></div>
|
||||
<div class="message_list_more">
|
||||
<a nhname="expand" href="javascript:void(0)" class="c_blue02">点击展开更多</a> <a nhname="close" style="display:none" href="javascript:void(0)" class="c_lgrey fr">收起</a>
|
||||
<div class="resources">
|
||||
<div class="homepageRightBanner">
|
||||
<div class="NewsBannerName">最新动态</div>
|
||||
<ul class="resourcesSelect">
|
||||
<li class="resourcesSelected"><a href="javascript:void(0);" class="resourcesIcon"></a>
|
||||
<ul class="homepagePostType">
|
||||
<li>
|
||||
<ul class="homepagePostTypeHomework fl">
|
||||
<li class="f14">课程动态</li>
|
||||
<li><a href="javascript:void(0);" class="homepagePostTypeAssignment postTypeGrey">作业动态</a></li>
|
||||
<li><a href="javascript:void(0);" class="homepagePostTypeNotice postTypeGrey">通知动态</a></li>
|
||||
<li><a href="javascript:void(0);" class="homepagePostTypeForum postTypeGrey">论坛动态</a></li>
|
||||
<li><a href="javascript:void(0);" class="homepagePostTypeQuiz postTypeGrey">问卷动态</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<ul class="homepagePostTypeProject fl">
|
||||
<li class="f14">项目动态</li>
|
||||
<li><a href="javascript:void(0);" class="homepagePostTypeQuestion postTypeGrey">问题动态</a></li>
|
||||
<li><a href="javascript:void(0);" class="homepagePostTypeForum postTypeGrey">论坛动态</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="homepagePostBrief">
|
||||
<div class="homepagePostPortrait"><a href="javascript:void(0);"><img src="images/homepageImage.jpg" width="90" height="90" alt="用户头像" /></a></div>
|
||||
<div class="homepagePostDes">
|
||||
<div class="homepagePostTo"><a href="javascript:void(0);" class="newsBlue mr15">尹教授</a> TO <a href="javascript:void(0);" class="newsBlue ml15">分布式计算环境(课程名称)</a></div>
|
||||
<div class="homepagePostTitle"><a href="javascript:void(0);" class="postGrey">ckeditor值设置的默认在光标聚焦控件后应自动消失的处理(作业名称)</a></div>
|
||||
<div class="homepagePostSubmitContainer">
|
||||
<div class="homepagePostSubmit"><a href="javascript:void(0);" class="c_blue">提交(10)</a></div>
|
||||
<div class="homepagePostDeadline">截止时间:2015-08-20</div>
|
||||
</div>
|
||||
<div class="homepagePostIntro">(作业描述)系统中有多个ckeditor,且每个ckeditor的id未知,怎么样做到当光标聚焦某个ckeditor的文本框中,该编辑器的默认值应自动消失的处理;网络拓扑图开发;</div>
|
||||
<div class="homepagePostSetting">
|
||||
<ul>
|
||||
<li class="homepagePostSettingIcon">
|
||||
<ul class="homepagePostSettiongText">
|
||||
<li><a href="javascript:void(0);" class="postOptionLink">编辑</a></li>
|
||||
<li><a href="javascript:void(0);" class="postOptionLink">复制</a></li>
|
||||
<li><a href="javascript:void(0);" class="postOptionLink">删除</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="homepagePostReply">
|
||||
<div class="homepagePostReplyBanner">
|
||||
<div class="homepagePostReplyBannerCount">回复(5)</div>
|
||||
<div class="homepagePostReplyBannerTime">2015-07-28</div>
|
||||
<div class="homepagePostReplyBannerMore"><a href="javascript:void(0);" class="replyGrey">点击展开更多回复</a></div>
|
||||
</div>
|
||||
<div class="homepagePostReplyInputContainer">
|
||||
<textarea class="homepagePostReplyInput" placeholder="请输入回复"></textarea>
|
||||
</div>
|
||||
<div class="homepagePostReplyInputContainer">
|
||||
<div class="homepagePostReplyEmotion"><a href="javascript:void(0);" class="replyGrey">表情</a></div>
|
||||
<div class="homepagePostReplyCancel"><a href="javascript:void(0);" class="postReplyCancel">取消</a></div>
|
||||
<div class="homepagePostReplySubmit"><a href="javascript:void(0);" class="postReplySubmit">发送</a></div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="homepagePostReplyContainer">
|
||||
<div class="homepagePostReplyPortrait"><a href="javascript:void(0);"><img src="images/homepageImage.jpg" width="45" height="45" alt="用户头像" /></a></div>
|
||||
<div class="homepagePostReplyDes">
|
||||
<div class="homepagePostReplyPublisher"><a href="javascript:void(0);" class="newsBlue mr10 f14">尹教授</a> 2015-08-01<a href="javascript:void(0);" class="replyGrey fr ml10">删除</a><a href="javascript:void(0);" class="newsBlue fr">回复</a></div>
|
||||
<div class="homepagePostReplyContent">请大家说下软件工程是什么!</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="homepagePostReplyContainer">
|
||||
<div class="homepagePostReplyPortrait"><a href="javascript:void(0);"><img src="images/homepageImage.jpg" width="45" height="45" alt="用户头像" /></a></div>
|
||||
<div class="homepagePostReplyDes">
|
||||
<div class="homepagePostReplyPublisher"><a href="javascript:void(0);" class="newsBlue mr10 f14">Tang 学生</a> 2015-08-02<a href="javascript:void(0);" class="replyGrey fr ml10">删除</a><a href="javascript:void(0);" class="newsBlue fr">回复</a></div>
|
||||
<div class="homepagePostReplyContent">软件工程是一门研究用工程化方法构建和维护有效的、实用的和高质量的软件的学科。它涉及程序设计语言、数据库、软件开发工具、系统平台、标准、设计模式等方面。</div>
|
||||
<div class="homepagePostReplyInputContainer2">
|
||||
<textarea class="homepagePostReplyInput2" placeholder="请输入回复"></textarea>
|
||||
</div>
|
||||
<div class="homepagePostReplyInputContainer2 mb10">
|
||||
<div class="homepagePostReplyEmotion"><a href="javascript:void(0);" class="replyGrey">表情</a></div>
|
||||
<div class="homepagePostReplyCancel"><a href="javascript:void(0);" class="postReplyCancel">取消</a></div>
|
||||
<div class="homepagePostReplySubmit"><a href="javascript:void(0);" class="postReplySubmit">发送</a></div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="homepagePostReplyContainer borderBottomNone">
|
||||
<div class="homepagePostReplyPortrait"><a href="javascript:void(0);"><img src="images/homepageImage.jpg" width="45" height="45" alt="用户头像" /></a></div>
|
||||
<div class="homepagePostReplyDes">
|
||||
<div class="homepagePostReplyPublisher"><a href="javascript:void(0);" class="newsBlue mr15 f14">尹教授</a><span class="f14">回复</span><a href="javascript:void(0);" class="newsBlue mr10 ml15 f14">Tang学生</a>刚刚<a href="javascript:void(0);" class="replyGrey fr ml10">删除</a><a href="javascript:void(0);" class="newsBlue fr">回复</a></div>
|
||||
<div class="homepagePostReplyContent">回答非常好!</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="users_courses_box line_box mb10" nhname="list_more_div" style="display:none;">
|
||||
<h4 class="users_h4">项目动态</h4>
|
||||
<div nhname="container" data-nodatamsg="暂无动态" data-url="<%= url_for(:controller => 'users', :action => 'user_project_activities') %>" data-isclose="0" data-currpage="0" data-hasmore="1"></div>
|
||||
<div class="message_list_more">
|
||||
<a nhname="expand" href="javascript:void(0)" class="c_blue02">点击展开更多</a> <a nhname="close" style="display:none" href="javascript:void(0)" class="c_lgrey fr">收起</a>
|
||||
</div>
|
||||
<div class="resources mt15">
|
||||
<div class="homepagePostBrief">
|
||||
<div class="homepagePostPortrait"><a href="javascript:void(0);"><img src="images/homepageImage.jpg" width="90" height="90" alt="用户头像" /></a></div>
|
||||
<div class="homepagePostDes">
|
||||
<div class="homepagePostTo"><a href="javascript:void(0);" class="newsBlue mr15">尹教授</a> TO <a href="javascript:void(0);" class="newsBlue ml15 mr5">黄井泉</a><span class="c_blue">,</span><a href="javascript:void(0);" class="newsBlue ml5">陈正东</a></div>
|
||||
<div class="homepagePostTitle"><a href="javascript:void(0);" class="postGrey">假期开心吗?(讨论区内容)</a></div>
|
||||
<div class="homepagePostSubmitContainer">
|
||||
<div class="homepagePostDeadline">时间:2015-07-31</div>
|
||||
</div>
|
||||
<div class="homepagePostSetting">
|
||||
<ul>
|
||||
<li class="homepagePostSettingIcon">
|
||||
<ul class="homepagePostSettiongText">
|
||||
<li><a href="javascript:void(0);" class="postOptionLink">编辑</a></li>
|
||||
<li><a href="javascript:void(0);" class="postOptionLink">复制</a></li>
|
||||
<li><a href="javascript:void(0);" class="postOptionLink">删除</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="homepagePostReply">
|
||||
<div class="homepagePostReplyBanner">
|
||||
<div class="homepagePostReplyBannerCount">回复(5)</div>
|
||||
<div class="homepagePostReplyBannerTime">2015-07-31</div>
|
||||
<div class="homepagePostReplyBannerMore"><a href="javascript:void(0);" class="replyGrey">点击展开更多回复</a></div>
|
||||
</div>
|
||||
<div class="homepagePostReplyInputContainer">
|
||||
<textarea class="homepagePostReplyInput" placeholder="请输入回复"></textarea>
|
||||
</div>
|
||||
<div class="homepagePostReplyInputContainer">
|
||||
<div class="homepagePostReplyEmotion"><a href="javascript:void(0);" class="replyGrey">表情</a></div>
|
||||
<div class="homepagePostReplyCancel"><a href="javascript:void(0);" class="postReplyCancel">取消</a></div>
|
||||
<div class="homepagePostReplySubmit"><a href="javascript:void(0);" class="postReplySubmit">发送</a></div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="homepagePostReplyContainer">
|
||||
<div class="homepagePostReplyPortrait"><a href="javascript:void(0);"><img src="images/homepageImage.jpg" width="45" height="45" alt="用户头像" /></a></div>
|
||||
<div class="homepagePostReplyDes">
|
||||
<div class="homepagePostReplyPublisher"><a href="javascript:void(0);" class="newsBlue mr10 f14">黄井泉 学生</a> 2015-08-01<a href="javascript:void(0);" class="replyGrey fr ml10">删除</a><a href="javascript:void(0);" class="newsBlue fr">回复</a></div>
|
||||
<div class="homepagePostReplyContent">很开心!</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="homepagePostReplyContainer borderBottomNone">
|
||||
<div class="homepagePostReplyPortrait"><a href="javascript:void(0);"><img src="images/homepageImage.jpg" width="45" height="45" alt="用户头像" /></a></div>
|
||||
<div class="homepagePostReplyDes">
|
||||
<div class="homepagePostReplyPublisher"><a href="javascript:void(0);" class="newsBlue mr10 f14">陈正东 学生</a> 2015-08-02<a href="javascript:void(0);" class="replyGrey fr ml10">删除</a><a href="javascript:void(0);" class="newsBlue fr">回复</a></div>
|
||||
<div class="homepagePostReplyContent">假期好热,没出去。</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="resources mt15">
|
||||
<div class="homepagePostBrief">
|
||||
<div class="homepagePostPortrait"><a href="javascript:void(0);"><img src="images/homepageImage.jpg" width="90" height="90" alt="用户头像" /></a></div>
|
||||
<div class="homepagePostDes">
|
||||
<div class="homepagePostTo"><a href="javascript:void(0);" class="newsBlue mr15">尹教授</a> TO <a href="javascript:void(0);" class="newsBlue ml15">Trustie Forge(项目名称)</a></div>
|
||||
<div class="homepagePostTitle"><a href="javascript:void(0);" class="postGrey">上传资源未显示在项目动态中(缺陷标题)</a><span class="homepagePostProjectState">正常</span></div>
|
||||
<div class="homepagePostSubmitContainer">
|
||||
<div class="homepagePostAssignTo">指派给 <a href="javascript:void(0);" class="newsBlue mr15">苏稳</a></div>
|
||||
<div class="homepagePostDeadline">时间:2015-08-20</div>
|
||||
</div>
|
||||
<div class="homepagePostIntro">(缺陷描述)系统中有多个ckeditor,且每个ckeditor的id未知,怎么样做到当光标聚焦某个ckeditor的文本框中,该编辑器的默认值应自动消失的处理;网络拓扑图开发;</div>
|
||||
<div class="mt10"><a href="javascript:void(0);" class="homepagePostFileAtt newsBlue">文件附件.zip</a><span class="postAttSize">(123KB)</span></div>
|
||||
<div><a href="javascript:void(0);" class="homepagePostImageAtt newsBlue">图片附件.png</a><span class="postAttSize">(123KB)</span></div>
|
||||
<div class="homepagePostSetting">
|
||||
<ul>
|
||||
<li class="homepagePostSettingIcon">
|
||||
<ul class="homepagePostSettiongText">
|
||||
<li><a href="javascript:void(0);" class="postOptionLink">编辑</a></li>
|
||||
<li><a href="javascript:void(0);" class="postOptionLink">复制</a></li>
|
||||
<li><a href="javascript:void(0);" class="postOptionLink">删除</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="homepagePostReply">
|
||||
<div class="homepagePostReplyBanner">
|
||||
<div class="homepagePostReplyBannerCount">回复(5)</div>
|
||||
<div class="homepagePostReplyBannerTime">2015-07-26</div>
|
||||
<div class="homepagePostReplyBannerMore"><a href="javascript:void(0);" class="replyGrey">点击展开更多回复</a></div>
|
||||
</div>
|
||||
<div class="homepagePostReplyInputContainer">
|
||||
<textarea class="homepagePostReplyInput" placeholder="请输入回复"></textarea>
|
||||
</div>
|
||||
<div class="homepagePostReplyInputContainer">
|
||||
<div class="homepagePostReplyEmotion"><a href="javascript:void(0);" class="replyGrey">表情</a></div>
|
||||
<div class="homepagePostReplyCancel"><a href="javascript:void(0);" class="postReplyCancel">取消</a></div>
|
||||
<div class="homepagePostReplySubmit"><a href="javascript:void(0);" class="postReplySubmit">发送</a></div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="homepagePostReplyContainer">
|
||||
<div class="homepagePostReplyPortrait"><a href="javascript:void(0);"><img src="images/homepageImage.jpg" width="45" height="45" alt="用户头像" /></a></div>
|
||||
<div class="homepagePostReplyDes">
|
||||
<div class="homepagePostReplyPublisher"><a href="javascript:void(0);" class="newsBlue mr10 f14">尹教授</a> 2015-08-01<a href="javascript:void(0);" class="replyGrey fr ml10">删除</a><a href="javascript:void(0);" class="newsBlue fr">回复</a></div>
|
||||
<div class="homepagePostReplyContent">请大家说下软件工程是什么!</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="homepagePostReplyContainer">
|
||||
<div class="homepagePostReplyPortrait"><a href="javascript:void(0);"><img src="images/homepageImage.jpg" width="45" height="45" alt="用户头像" /></a></div>
|
||||
<div class="homepagePostReplyDes">
|
||||
<div class="homepagePostReplyPublisher"><a href="javascript:void(0);" class="newsBlue mr10 f14">Tang 学生</a> 2015-08-01<a href="javascript:void(0);" class="replyGrey fr ml10">删除</a><a href="javascript:void(0);" class="newsBlue fr">回复</a></div>
|
||||
<div class="homepagePostReplyContent">软件工程是一门研究用工程化方法构建和维护有效的、实用的和高质量的软件的学科。它涉及程序设计语言、数据库、软件开发工具、系统平台、标准、设计模式等方面。</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 美化设置,勿删! -->
|
||||
<div id="RSide" class="rside_back">
|
||||
|
||||
</div>
|
|
@ -105,7 +105,7 @@
|
|||
</div>
|
||||
<div>
|
||||
<ul class="wlist" id="pages">
|
||||
<%= pagination_links_full @obj_pages, @obj_count, :per_page_links => false, :remote => @is_remote, :flag => true%>
|
||||
<%= pagination_links_full @atta_pages, @atta_count, :per_page_links => false, :remote => @is_remote, :flag => true%>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
$("#search_div").html('<%= escape_javascript( render :partial => 'resource_search_form',:locals => {:user=>@user,:type=>@type} ) %>');
|
||||
$("#resources_list").html('<%= escape_javascript( render :partial => 'resources_list' ,:locals=>{ :attachments => @attachments})%>');
|
||||
$("#pages").html('<%= pagination_links_full @obj_pages, @obj_count, :per_page_links => false, :remote => @is_remote, :flag => true %>');
|
||||
$("#pages").html('<%= pagination_links_full @atta_pages, @atta_count, :per_page_links => false, :remote => @is_remote, :flag => true %>');
|
|
@ -2,3 +2,4 @@
|
|||
closeModal();
|
||||
$("#resources_list").html('<%= escape_javascript( render :partial => 'resources_list' ,:locals=>{ :attachments => @attachments})%>');
|
||||
|
||||
$("#pages").html('<%= pagination_links_full @atta_pages, @atta_count, :per_page_links => false, :remote => @is_remote, :flag => true %>');
|
|
@ -1,2 +1,2 @@
|
|||
$("#resources_list").html('<%= escape_javascript( render :partial => 'resources_list' ,:locals=>{ :attachments => @attachments})%>');
|
||||
$("#pages").html('<%= pagination_links_full @obj_pages, @obj_count, :per_page_links => false, :remote => @is_remote, :flag => true %>');
|
||||
$("#pages").html('<%= pagination_links_full @atta_pages, @atta_count, :per_page_links => false, :remote => @is_remote, :flag => true %>');
|
|
@ -1,57 +1,15 @@
|
|||
<% if( params[:object_type] == 'user') %>
|
||||
//点击头像下面的添加关注按钮
|
||||
<% if( params[:target_id] == params[:object_id] ) %>
|
||||
<% target = User.find_by_id(params[:target_id]) %>
|
||||
//btn
|
||||
var btn_html = "<%= escape_javascript( render( :partial => 'layouts/user_watch_btn', :locals => {:target => target} ) )%>";
|
||||
$('#user_watch_id').replaceWith(btn_html);
|
||||
//count
|
||||
$("*[nh_name='fans_count']").html("<%= target.watcher_users.count.to_s %>");
|
||||
//left list
|
||||
var list_left_html = "<%= escape_javascript( render( :partial => 'layouts/user_fans_list', :locals => {:user => target} ) )%>";
|
||||
$('#fans_nav_list').replaceWith(list_left_html);
|
||||
//list
|
||||
if( $("#nh_fans_list") != undefined && $("#nh_fans_list").length != 0 ){
|
||||
<% if( opt == 'add') %>
|
||||
var list_html = "<%= escape_javascript( render( :partial => 'users/user_fans_item', :locals => {:item=>User.current,:target => target} ) )%>";
|
||||
$("#nh_fans_list").after(list_html);
|
||||
$("#nodata").hide();
|
||||
<% else %>
|
||||
$("#fans_item_<%= User.current.id %>",$("#nh_fans_list").parent('div')).remove();
|
||||
if( $('>div',$("#nh_fans_list").parent('div')).length == 1 ){
|
||||
$("#nodata").show();
|
||||
}
|
||||
<% end %>
|
||||
}
|
||||
|
||||
$("#watch_user_btn").html("<%= escape_javascript render(:partial => "layouts/user_watch_btn", :locals => {:target => watched.first}) %>");
|
||||
$("#user_fans_number").html("<%= watched.first.watcher_users.count.to_s%>");
|
||||
//在当前用户的粉丝、关注页面
|
||||
<% elsif( params[:target_id] == User.current.id.to_s )%>
|
||||
<% target = User.find_by_id(params[:target_id]) %>
|
||||
<% item = User.find_by_id(params[:object_id]) %>
|
||||
//count
|
||||
$("*[nh_name='watcher_count']").html("<%= User.watched_by(target.id).count.to_s %>");
|
||||
//left list
|
||||
var list_left_html = "<%= escape_javascript( render( :partial => 'layouts/user_watch_list', :locals => {:user => target} ) )%>";
|
||||
$('#watcher_nav_list').replaceWith(list_left_html);
|
||||
//list
|
||||
if( $("#nh_wacth_list") != undefined && $("#nh_wacth_list").length != 0 ){
|
||||
<% if( opt == 'delete') %>
|
||||
$("#fans_item_<%= item.id %>",$("#nh_wacth_list").parent('div')).remove();
|
||||
if( $('>div',$("#nh_wacth_list").parent('div')).length == 1 ){
|
||||
$("#nodata").show();
|
||||
}
|
||||
<% end %>
|
||||
}else if($("#nh_fans_list") != undefined && $("#nh_fans_list").length != 0){
|
||||
var list_html = "<%= escape_javascript( render( :partial => 'users/user_fans_item', :locals => {:item=>item,:target => target} ) )%>";
|
||||
$('#fans_item_<%= item.id %>').replaceWith(list_html);
|
||||
}
|
||||
|
||||
//在其他用户的粉丝、关注页面
|
||||
<% else %>
|
||||
<% target = User.find_by_id(params[:target_id]) %>
|
||||
<% item = User.find_by_id(params[:object_id]) %>
|
||||
//list
|
||||
var list_html = "<%= escape_javascript( render( :partial => 'users/user_fans_item', :locals => {:item=>item,:target => target} ) )%>";
|
||||
$('#fans_item_<%= item.id %>').replaceWith(list_html);
|
||||
<% end %>
|
||||
|
||||
<% end %>
|
||||
<% else %>
|
||||
|
||||
<% selector = ".#{watcher_css(watched)}" %>
|
||||
|
|
|
@ -197,9 +197,12 @@ default:
|
|||
#max_concurrent_ajax_uploads: 2
|
||||
#pic_types: "bmp,jpeg,jpg,png,gif"
|
||||
|
||||
repository_root_path: '/tmp/htdocs'
|
||||
|
||||
# specific configuration options for production environment
|
||||
# that overrides the default ones
|
||||
production:
|
||||
repository_root_path: '/home/pdl/redmine-2.3.2-0/apache2/htdocs'
|
||||
cookie_domain: ".trustie.net"
|
||||
rmagick_font_path: /usr/share/fonts/ipa-mincho/ipam.ttf
|
||||
email_delivery:
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
RedmineApp::Application.routes.draw do
|
||||
mount Mobile::API => '/api'
|
||||
|
||||
# Enable Grack support
|
||||
mount Trustie::Grack.new, at: '/', constraints: lambda { |request| /[-\/\w\.]+\.git\//.match(request.path_info) }, via: [:get, :post]
|
||||
|
||||
resources :homework_users
|
||||
resources :no_uses
|
||||
delete 'no_uses', :to => 'no_uses#delete'
|
||||
|
@ -345,6 +348,7 @@ RedmineApp::Application.routes.draw do
|
|||
match 'file_score_index', :to => 'projects#file_score_index', :via => [:get, :post]
|
||||
match 'code_submit_score_index', :to => 'projects#code_submit_score_index', :via => [:get, :post]
|
||||
match 'projects_topic_score_index', :to => 'projects#projects_topic_score_index', :via => [:get, :post]
|
||||
get 'edit_brief_introduction'
|
||||
get "user_resource"
|
||||
get "resource_search"
|
||||
post "user_resource_create"
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
class CreateUserActivity < ActiveRecord::Migration
|
||||
def up
|
||||
create_table :user_activities do |t|
|
||||
t.string :act_type
|
||||
t.integer :act_id
|
||||
t.string :container_type
|
||||
t.integer :container_id
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :user_activities
|
||||
end
|
||||
end
|
|
@ -0,0 +1,37 @@
|
|||
class AboutUserActivities < ActiveRecord::Migration
|
||||
def up
|
||||
forge_count = ForgeActivity.all.count / 30 + 2
|
||||
transaction do
|
||||
for i in 1 ... forge_count do i
|
||||
ForgeActivity.page(i).per(30).each do |activity|
|
||||
user_activity = UserActivity.new
|
||||
user_activity.act_id = activity.id
|
||||
user_activity.act_type = activity.class.to_s
|
||||
user_activity.container_type = "Project"
|
||||
user_activity.container_id = activity.project_id
|
||||
user_activity.created_at = activity.created_at
|
||||
user_activity.save
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
course_count = CourseActivity.all.count / 30 + 2
|
||||
transaction do
|
||||
for i in 1 ... course_count do i
|
||||
CourseActivity.page(i).per(30).each do |activity|
|
||||
user_activity = UserActivity.new
|
||||
user_activity.act_id = activity.id
|
||||
user_activity.act_type = activity.class.to_s
|
||||
user_activity.container_type = "Course"
|
||||
user_activity.container_id = activity.course_id
|
||||
user_activity.created_at = activity.created_at
|
||||
user_activity.save
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
language: ruby
|
||||
env:
|
||||
- TRAVIS=true
|
||||
branches:
|
||||
only:
|
||||
- 'master'
|
||||
rvm:
|
||||
- 1.9.3-p327
|
||||
- 2.0.0
|
||||
before_script:
|
||||
- "bundle install"
|
||||
- "git submodule init"
|
||||
- "git submodule update"
|
||||
script: "bundle exec rake"
|
|
@ -0,0 +1,16 @@
|
|||
2.0.2
|
||||
- Revert MR that broke smart HTTP clients.
|
||||
|
||||
2.0.1
|
||||
- Make sure child processes get reaped after popen, again.
|
||||
|
||||
2.0.0
|
||||
- Use safer shell commands and avoid Dir.chdir
|
||||
- Restrict the environment for shell commands
|
||||
- Make Grack::Server thread-safe (zimbatm)
|
||||
- Make sure child processes get reaped after popen
|
||||
- Verify requested path is actually a Git directory (Ryan Canty)
|
||||
|
||||
|
||||
1.1.0
|
||||
- Modifies service_rpc to use chunked transfer (https://github.com/gitlabhq/grack/pull/1)
|
|
@ -0,0 +1,10 @@
|
|||
source "http://ruby.taobao.org"
|
||||
|
||||
gemspec
|
||||
|
||||
group :development do
|
||||
gem 'byebug'
|
||||
gem 'rake'
|
||||
gem 'pry'
|
||||
gem 'rack-test'
|
||||
end
|
|
@ -0,0 +1,37 @@
|
|||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
gitlab-grack (2.0.2)
|
||||
rack (~> 1.5.1)
|
||||
|
||||
GEM
|
||||
remote: http://ruby.taobao.org/
|
||||
specs:
|
||||
byebug (4.0.5)
|
||||
columnize (= 0.9.0)
|
||||
coderay (1.1.0)
|
||||
columnize (0.9.0)
|
||||
metaclass (0.0.1)
|
||||
method_source (0.8.2)
|
||||
mocha (0.14.0)
|
||||
metaclass (~> 0.0.1)
|
||||
pry (0.10.1)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
rack (1.5.2)
|
||||
rack-test (0.6.2)
|
||||
rack (>= 1.0)
|
||||
rake (10.1.0)
|
||||
slop (3.6.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
byebug
|
||||
gitlab-grack!
|
||||
mocha (~> 0.11)
|
||||
pry
|
||||
rack-test
|
||||
rake
|
|
@ -0,0 +1,95 @@
|
|||
Grack - Ruby/Rack Git Smart-HTTP Server Handler
|
||||
===============================================
|
||||
|
||||
[![Build Status](https://travis-ci.org/gitlabhq/grack.png)](https://travis-ci.org/gitlabhq/grack)
|
||||
[![Code Climate](https://codeclimate.com/github/gitlabhq/grack.png)](https://codeclimate.com/github/gitlabhq/grack)
|
||||
|
||||
This project aims to replace the builtin git-http-backend CGI handler
|
||||
distributed with C Git with a Rack application. This reason for doing this
|
||||
is to allow far more webservers to be able to handle Git smart http requests.
|
||||
|
||||
The default git-http-backend only runs as a CGI script, and specifically is
|
||||
only targeted for Apache 2.x usage (it requires PATH_INFO to be set and
|
||||
specifically formatted). So, instead of trying to get it to work with
|
||||
other CGI capable webservers (Lighttpd, etc), we can get it running on nearly
|
||||
every major and minor webserver out there by making it Rack capable. Rack
|
||||
applications can run with the following handlers:
|
||||
|
||||
* CGI
|
||||
* FCGI
|
||||
* Mongrel (and EventedMongrel and SwiftipliedMongrel)
|
||||
* WEBrick
|
||||
* SCGI
|
||||
* LiteSpeed
|
||||
* Thin
|
||||
|
||||
These web servers include Rack handlers in their distributions:
|
||||
|
||||
* Ebb
|
||||
* Fuzed
|
||||
* Phusion Passenger (which is mod_rack for Apache and for nginx)
|
||||
* Unicorn
|
||||
* Puma
|
||||
|
||||
With [Warbler](http://caldersphere.rubyforge.org/warbler/classes/Warbler.html),
|
||||
and JRuby, we can also generate a WAR file that can be deployed in any Java
|
||||
web application server (Tomcat, Glassfish, Websphere, JBoss, etc).
|
||||
|
||||
Since the git-http-backend is really just a simple wrapper for the upload-pack
|
||||
and receive-pack processes with the '--stateless-rpc' option, it does not
|
||||
actually re-implement very much.
|
||||
|
||||
Dependencies
|
||||
========================
|
||||
* Ruby - http://www.ruby-lang.org
|
||||
* Rack - http://rack.rubyforge.org
|
||||
* A Rack-compatible web server
|
||||
* Git >= 1.7 (currently the 'pu' branch)
|
||||
* Mocha (only for running the tests)
|
||||
|
||||
Quick Start
|
||||
========================
|
||||
$ gem install rack
|
||||
$ (edit config.ru to set git project path)
|
||||
$ rackup --host 127.0.0.1 -p 8080 config.ru
|
||||
$ git clone http://127.0.0.1:8080/schacon/grit.git
|
||||
|
||||
Contributing
|
||||
========================
|
||||
If you would like to contribute to the Grack project, I prefer to get
|
||||
pull-requests via GitHub. You should include tests for whatever functionality
|
||||
you add. Just fork this project, push your changes to your fork and click
|
||||
the 'pull request' button. To run the tests, you first need to install the
|
||||
'mocha' mocking library and initialize the submodule.
|
||||
|
||||
$ sudo gem install mocha
|
||||
$ git submodule init
|
||||
$ git submodule update
|
||||
|
||||
Then you should be able to run the tests with a 'rake' command. You can also
|
||||
run coverage tests with 'rake rcov' if you have rcov installed.
|
||||
|
||||
License
|
||||
========================
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2009 Scott Chacon <schacon@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env rake
|
||||
require "bundler/gem_tasks"
|
||||
|
||||
task :default => :test
|
||||
|
||||
desc "Run the tests."
|
||||
task :test do
|
||||
Dir.glob("tests/*_test.rb").each do |f|
|
||||
system "ruby #{f}"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Run test coverage."
|
||||
task :rcov do
|
||||
system "rcov tests/*_test.rb -i lib/git_http.rb -x rack -x Library -x tests"
|
||||
system "open coverage/index.html"
|
||||
end
|
||||
|
||||
namespace :grack do
|
||||
desc "Start Grack"
|
||||
task :start do
|
||||
system('./bin/testserver')
|
||||
end
|
||||
end
|
||||
|
||||
desc "Start everything."
|
||||
multitask :start => [ 'grack:start' ]
|
|
@ -0,0 +1,6 @@
|
|||
#! /bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd $(dirname "$0")/..
|
||||
exec /usr/bin/env bundle exec pry -Ilib -r grack
|
|
@ -0,0 +1,24 @@
|
|||
#! /usr/bin/env ruby
|
||||
libdir = File.absolute_path( File.join( File.dirname(__FILE__), '../lib' ) )
|
||||
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
||||
|
||||
Bundler.require(:default, :development)
|
||||
|
||||
|
||||
require 'grack'
|
||||
require 'rack'
|
||||
root = File.absolute_path( File.join( File.dirname(__FILE__), '../examples' ) )
|
||||
app = Grack::Server.new({
|
||||
project_root: root,
|
||||
upload_pack: true,
|
||||
receive_pack:true
|
||||
})
|
||||
|
||||
app1= Rack::Builder.new do
|
||||
use Grack::Auth do |username, password|
|
||||
[username, password] == ['123', '455']
|
||||
end
|
||||
run app
|
||||
end
|
||||
|
||||
Rack::Server.start app: app1, Port: 3001
|
|
@ -0,0 +1 @@
|
|||
ref: refs/heads/master
|
|
@ -0,0 +1,6 @@
|
|||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = true
|
||||
ignorecase = true
|
||||
precomposeunicode = true
|
|
@ -0,0 +1 @@
|
|||
Unnamed repository; edit this file 'description' to name the repository.
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message taken by
|
||||
# applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit. The hook is
|
||||
# allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "applypatch-msg".
|
||||
|
||||
. git-sh-setup
|
||||
test -x "$GIT_DIR/hooks/commit-msg" &&
|
||||
exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
|
||||
:
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message.
|
||||
# Called by "git commit" with one argument, the name of the file
|
||||
# that has the commit message. The hook should exit with non-zero
|
||||
# status after issuing an appropriate message if it wants to stop the
|
||||
# commit. The hook is allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "commit-msg".
|
||||
|
||||
# Uncomment the below to add a Signed-off-by line to the message.
|
||||
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
||||
# hook is more suited to it.
|
||||
#
|
||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
||||
|
||||
# This example catches duplicate Signed-off-by lines.
|
||||
|
||||
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||
echo >&2 Duplicate Signed-off-by lines.
|
||||
exit 1
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to prepare a packed repository for use over
|
||||
# dumb transports.
|
||||
#
|
||||
# To enable this hook, rename this file to "post-update".
|
||||
|
||||
exec git update-server-info
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed
|
||||
# by applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-applypatch".
|
||||
|
||||
. git-sh-setup
|
||||
test -x "$GIT_DIR/hooks/pre-commit" &&
|
||||
exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
|
||||
:
|
|
@ -0,0 +1,49 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git commit" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message if
|
||||
# it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-commit".
|
||||
|
||||
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||
then
|
||||
against=HEAD
|
||||
else
|
||||
# Initial commit: diff against an empty tree object
|
||||
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
||||
fi
|
||||
|
||||
# If you want to allow non-ASCII filenames set this variable to true.
|
||||
allownonascii=$(git config --bool hooks.allownonascii)
|
||||
|
||||
# Redirect output to stderr.
|
||||
exec 1>&2
|
||||
|
||||
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||
# them from being added to the repository. We exploit the fact that the
|
||||
# printable range starts at the space character and ends with tilde.
|
||||
if [ "$allownonascii" != "true" ] &&
|
||||
# Note that the use of brackets around a tr range is ok here, (it's
|
||||
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||
# the square bracket bytes happen to fall in the designated range.
|
||||
test $(git diff --cached --name-only --diff-filter=A -z $against |
|
||||
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||
then
|
||||
cat <<\EOF
|
||||
Error: Attempt to add a non-ASCII file name.
|
||||
|
||||
This can cause problems if you want to work with people on other platforms.
|
||||
|
||||
To be portable it is advisable to rename the file.
|
||||
|
||||
If you know what you are doing you can disable this check using:
|
||||
|
||||
git config hooks.allownonascii true
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If there are whitespace errors, print the offending file names and fail.
|
||||
exec git diff-index --check --cached $against --
|
|
@ -0,0 +1,53 @@
|
|||
#!/bin/sh
|
||||
|
||||
# An example hook script to verify what is about to be pushed. Called by "git
|
||||
# push" after it has checked the remote status, but before anything has been
|
||||
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
||||
#
|
||||
# This hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- Name of the remote to which the push is being done
|
||||
# $2 -- URL to which the push is being done
|
||||
#
|
||||
# If pushing without using a named remote those arguments will be equal.
|
||||
#
|
||||
# Information about the commits which are being pushed is supplied as lines to
|
||||
# the standard input in the form:
|
||||
#
|
||||
# <local ref> <local sha1> <remote ref> <remote sha1>
|
||||
#
|
||||
# This sample shows how to prevent push of commits where the log message starts
|
||||
# with "WIP" (work in progress).
|
||||
|
||||
remote="$1"
|
||||
url="$2"
|
||||
|
||||
z40=0000000000000000000000000000000000000000
|
||||
|
||||
while read local_ref local_sha remote_ref remote_sha
|
||||
do
|
||||
if [ "$local_sha" = $z40 ]
|
||||
then
|
||||
# Handle delete
|
||||
:
|
||||
else
|
||||
if [ "$remote_sha" = $z40 ]
|
||||
then
|
||||
# New branch, examine all commits
|
||||
range="$local_sha"
|
||||
else
|
||||
# Update to existing branch, examine new commits
|
||||
range="$remote_sha..$local_sha"
|
||||
fi
|
||||
|
||||
# Check for WIP commit
|
||||
commit=`git rev-list -n 1 --grep '^WIP' "$range"`
|
||||
if [ -n "$commit" ]
|
||||
then
|
||||
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,169 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2006, 2008 Junio C Hamano
|
||||
#
|
||||
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
||||
# its job, and can prevent the command from running by exiting with
|
||||
# non-zero status.
|
||||
#
|
||||
# The hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- the upstream the series was forked from.
|
||||
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
||||
#
|
||||
# This sample shows how to prevent topic branches that are already
|
||||
# merged to 'next' branch from getting rebased, because allowing it
|
||||
# would result in rebasing already published history.
|
||||
|
||||
publish=next
|
||||
basebranch="$1"
|
||||
if test "$#" = 2
|
||||
then
|
||||
topic="refs/heads/$2"
|
||||
else
|
||||
topic=`git symbolic-ref HEAD` ||
|
||||
exit 0 ;# we do not interrupt rebasing detached HEAD
|
||||
fi
|
||||
|
||||
case "$topic" in
|
||||
refs/heads/??/*)
|
||||
;;
|
||||
*)
|
||||
exit 0 ;# we do not interrupt others.
|
||||
;;
|
||||
esac
|
||||
|
||||
# Now we are dealing with a topic branch being rebased
|
||||
# on top of master. Is it OK to rebase it?
|
||||
|
||||
# Does the topic really exist?
|
||||
git show-ref -q "$topic" || {
|
||||
echo >&2 "No such branch $topic"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Is topic fully merged to master?
|
||||
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
||||
if test -z "$not_in_master"
|
||||
then
|
||||
echo >&2 "$topic is fully merged to master; better remove it."
|
||||
exit 1 ;# we could allow it, but there is no point.
|
||||
fi
|
||||
|
||||
# Is topic ever merged to next? If so you should not be rebasing it.
|
||||
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
||||
only_next_2=`git rev-list ^master ${publish} | sort`
|
||||
if test "$only_next_1" = "$only_next_2"
|
||||
then
|
||||
not_in_topic=`git rev-list "^$topic" master`
|
||||
if test -z "$not_in_topic"
|
||||
then
|
||||
echo >&2 "$topic is already up-to-date with master"
|
||||
exit 1 ;# we could allow it, but there is no point.
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
||||
/usr/bin/perl -e '
|
||||
my $topic = $ARGV[0];
|
||||
my $msg = "* $topic has commits already merged to public branch:\n";
|
||||
my (%not_in_next) = map {
|
||||
/^([0-9a-f]+) /;
|
||||
($1 => 1);
|
||||
} split(/\n/, $ARGV[1]);
|
||||
for my $elem (map {
|
||||
/^([0-9a-f]+) (.*)$/;
|
||||
[$1 => $2];
|
||||
} split(/\n/, $ARGV[2])) {
|
||||
if (!exists $not_in_next{$elem->[0]}) {
|
||||
if ($msg) {
|
||||
print STDERR $msg;
|
||||
undef $msg;
|
||||
}
|
||||
print STDERR " $elem->[1]\n";
|
||||
}
|
||||
}
|
||||
' "$topic" "$not_in_next" "$not_in_master"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
################################################################
|
||||
|
||||
This sample hook safeguards topic branches that have been
|
||||
published from being rewound.
|
||||
|
||||
The workflow assumed here is:
|
||||
|
||||
* Once a topic branch forks from "master", "master" is never
|
||||
merged into it again (either directly or indirectly).
|
||||
|
||||
* Once a topic branch is fully cooked and merged into "master",
|
||||
it is deleted. If you need to build on top of it to correct
|
||||
earlier mistakes, a new topic branch is created by forking at
|
||||
the tip of the "master". This is not strictly necessary, but
|
||||
it makes it easier to keep your history simple.
|
||||
|
||||
* Whenever you need to test or publish your changes to topic
|
||||
branches, merge them into "next" branch.
|
||||
|
||||
The script, being an example, hardcodes the publish branch name
|
||||
to be "next", but it is trivial to make it configurable via
|
||||
$GIT_DIR/config mechanism.
|
||||
|
||||
With this workflow, you would want to know:
|
||||
|
||||
(1) ... if a topic branch has ever been merged to "next". Young
|
||||
topic branches can have stupid mistakes you would rather
|
||||
clean up before publishing, and things that have not been
|
||||
merged into other branches can be easily rebased without
|
||||
affecting other people. But once it is published, you would
|
||||
not want to rewind it.
|
||||
|
||||
(2) ... if a topic branch has been fully merged to "master".
|
||||
Then you can delete it. More importantly, you should not
|
||||
build on top of it -- other people may already want to
|
||||
change things related to the topic as patches against your
|
||||
"master", so if you need further changes, it is better to
|
||||
fork the topic (perhaps with the same name) afresh from the
|
||||
tip of "master".
|
||||
|
||||
Let's look at this example:
|
||||
|
||||
o---o---o---o---o---o---o---o---o---o "next"
|
||||
/ / / /
|
||||
/ a---a---b A / /
|
||||
/ / / /
|
||||
/ / c---c---c---c B /
|
||||
/ / / \ /
|
||||
/ / / b---b C \ /
|
||||
/ / / / \ /
|
||||
---o---o---o---o---o---o---o---o---o---o---o "master"
|
||||
|
||||
|
||||
A, B and C are topic branches.
|
||||
|
||||
* A has one fix since it was merged up to "next".
|
||||
|
||||
* B has finished. It has been fully merged up to "master" and "next",
|
||||
and is ready to be deleted.
|
||||
|
||||
* C has not merged to "next" at all.
|
||||
|
||||
We would want to allow C to be rebased, refuse A, and encourage
|
||||
B to be deleted.
|
||||
|
||||
To compute (1):
|
||||
|
||||
git rev-list ^master ^topic next
|
||||
git rev-list ^master next
|
||||
|
||||
if these match, topic has not merged in next at all.
|
||||
|
||||
To compute (2):
|
||||
|
||||
git rev-list master..topic
|
||||
|
||||
if this is empty, it is fully merged to "master".
|
|
@ -0,0 +1,36 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to prepare the commit log message.
|
||||
# Called by "git commit" with the name of the file that has the
|
||||
# commit message, followed by the description of the commit
|
||||
# message's source. The hook's purpose is to edit the commit
|
||||
# message file. If the hook fails with a non-zero status,
|
||||
# the commit is aborted.
|
||||
#
|
||||
# To enable this hook, rename this file to "prepare-commit-msg".
|
||||
|
||||
# This hook includes three examples. The first comments out the
|
||||
# "Conflicts:" part of a merge commit.
|
||||
#
|
||||
# The second includes the output of "git diff --name-status -r"
|
||||
# into the message, just before the "git status" output. It is
|
||||
# commented because it doesn't cope with --amend or with squashed
|
||||
# commits.
|
||||
#
|
||||
# The third example adds a Signed-off-by line to the message, that can
|
||||
# still be edited. This is rarely a good idea.
|
||||
|
||||
case "$2,$3" in
|
||||
merge,)
|
||||
/usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
|
||||
|
||||
# ,|template,)
|
||||
# /usr/bin/perl -i.bak -pe '
|
||||
# print "\n" . `git diff --cached --name-status -r`
|
||||
# if /^#/ && $first++ == 0' "$1" ;;
|
||||
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
|
@ -0,0 +1,128 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to blocks unannotated tags from entering.
|
||||
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
|
||||
#
|
||||
# To enable this hook, rename this file to "update".
|
||||
#
|
||||
# Config
|
||||
# ------
|
||||
# hooks.allowunannotated
|
||||
# This boolean sets whether unannotated tags will be allowed into the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowdeletetag
|
||||
# This boolean sets whether deleting tags will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowmodifytag
|
||||
# This boolean sets whether a tag may be modified after creation. By default
|
||||
# it won't be.
|
||||
# hooks.allowdeletebranch
|
||||
# This boolean sets whether deleting branches will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.denycreatebranch
|
||||
# This boolean sets whether remotely creating branches will be denied
|
||||
# in the repository. By default this is allowed.
|
||||
#
|
||||
|
||||
# --- Command line
|
||||
refname="$1"
|
||||
oldrev="$2"
|
||||
newrev="$3"
|
||||
|
||||
# --- Safety check
|
||||
if [ -z "$GIT_DIR" ]; then
|
||||
echo "Don't run this script from the command line." >&2
|
||||
echo " (if you want, you could supply GIT_DIR then run" >&2
|
||||
echo " $0 <ref> <oldrev> <newrev>)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
||||
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Config
|
||||
allowunannotated=$(git config --bool hooks.allowunannotated)
|
||||
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
|
||||
denycreatebranch=$(git config --bool hooks.denycreatebranch)
|
||||
allowdeletetag=$(git config --bool hooks.allowdeletetag)
|
||||
allowmodifytag=$(git config --bool hooks.allowmodifytag)
|
||||
|
||||
# check for no description
|
||||
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
|
||||
case "$projectdesc" in
|
||||
"Unnamed repository"* | "")
|
||||
echo "*** Project description file hasn't been set" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Check types
|
||||
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
||||
zero="0000000000000000000000000000000000000000"
|
||||
if [ "$newrev" = "$zero" ]; then
|
||||
newrev_type=delete
|
||||
else
|
||||
newrev_type=$(git cat-file -t $newrev)
|
||||
fi
|
||||
|
||||
case "$refname","$newrev_type" in
|
||||
refs/tags/*,commit)
|
||||
# un-annotated tag
|
||||
short_refname=${refname##refs/tags/}
|
||||
if [ "$allowunannotated" != "true" ]; then
|
||||
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
|
||||
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,delete)
|
||||
# delete tag
|
||||
if [ "$allowdeletetag" != "true" ]; then
|
||||
echo "*** Deleting a tag is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,tag)
|
||||
# annotated tag
|
||||
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
|
||||
then
|
||||
echo "*** Tag '$refname' already exists." >&2
|
||||
echo "*** Modifying a tag is not allowed in this repository." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,commit)
|
||||
# branch
|
||||
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
|
||||
echo "*** Creating a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,delete)
|
||||
# delete branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/remotes/*,commit)
|
||||
# tracking branch
|
||||
;;
|
||||
refs/remotes/*,delete)
|
||||
# delete tracking branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# Anything else (is there anything else?)
|
||||
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Finished
|
||||
exit 0
|
|
@ -0,0 +1,6 @@
|
|||
# git ls-files --others --exclude-from=.git/info/exclude
|
||||
# Lines that start with '#' are comments.
|
||||
# For a project mostly in C, the following would be a good set of
|
||||
# exclude patterns (uncomment them if you want to use them):
|
||||
# *.[oa]
|
||||
# *~
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
x•ÍM
|
||||
à @á®=ÅìÁñgœ<67>Rz£Æ5B0÷o®Ðíƒ<C3AD>—Fïmúð˜g)@(†eCâš )‹c‘Í$Y)ÊEÆ$FÅkîã„zÅ£x1“eã>µÇö]Òèo@g½g
|
||||
<EFBFBD>à©Yku×û5ËJµ£Mõíæ/0
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
e1022324d23146d29075a3e7c6f637cb67f091b5
|
|
@ -0,0 +1,9 @@
|
|||
#! /usr/bin/env ruby
|
||||
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/lib')
|
||||
require 'lib/git_http'
|
||||
config = {
|
||||
:project_root => "/opt",
|
||||
:upload_pack => true,
|
||||
:receive_pack => false,
|
||||
}
|
||||
Rack::Handler::FastCGI.run(GitHttp::App.new(config))
|
|
@ -0,0 +1,20 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../lib/grack/version', __FILE__)
|
||||
|
||||
Gem::Specification.new do |gem|
|
||||
gem.authors = ["Scott Chacon"]
|
||||
gem.email = ["schacon@gmail.com"]
|
||||
gem.description = %q{Ruby/Rack Git Smart-HTTP Server Handler}
|
||||
gem.summary = %q{Ruby/Rack Git Smart-HTTP Server Handler}
|
||||
gem.homepage = "https://github.com/gitlabhq/grack"
|
||||
|
||||
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
||||
gem.files = `git ls-files`.split("\n")
|
||||
gem.test_files = `git ls-files -- tests/*`.split("\n")
|
||||
gem.name = "grack"
|
||||
gem.require_paths = ["lib"]
|
||||
gem.version = Grack::VERSION
|
||||
|
||||
gem.add_dependency("rack", "~> 1.4.5")
|
||||
gem.add_development_dependency("mocha", "~> 0.11")
|
||||
end
|
|
@ -0,0 +1,60 @@
|
|||
Installation
|
||||
========================
|
||||
|
||||
** This documentation is not finished yet. I haven't tested all of
|
||||
these and it's obviously incomplete - these are currently just notes.
|
||||
|
||||
FastCGI
|
||||
---------------------------------------
|
||||
Here is an example config from lighttpd server:
|
||||
----
|
||||
# main fastcgi entry
|
||||
$HTTP["url"] =~ "^/myapp/.+$" {
|
||||
fastcgi.server = ( "/myapp" =>
|
||||
( "localhost" =>
|
||||
( "bin-path" => "/var/www/localhost/cgi-bin/dispatch.fcgi",
|
||||
"docroot" => "/var/www/localhost/htdocs/myapp",
|
||||
"host" => "127.0.0.1",
|
||||
"port" => 1026,
|
||||
"check-local" => "disable"
|
||||
)
|
||||
)
|
||||
)
|
||||
} # HTTP[url]
|
||||
----
|
||||
You can use the examples/dispatch.fcgi file as your dispatcher.
|
||||
|
||||
(Example Apache setup?)
|
||||
|
||||
Installing in a Java application server
|
||||
---------------------------------------
|
||||
# install Warbler
|
||||
$ sudo gem install warbler
|
||||
$ cd gitsmart
|
||||
$ (edit config.ru)
|
||||
$ warble
|
||||
$ cp gitsmart.war /path/to/java/autodeploy/dir
|
||||
|
||||
Unicorn
|
||||
---------------------------------------
|
||||
With Unicorn (http://unicorn.bogomips.org/) you can just run 'unicorn'
|
||||
in the directory with the config.ru file.
|
||||
|
||||
Thin
|
||||
---------------------------------------
|
||||
thin.yml
|
||||
---
|
||||
pid: /home/deploy/myapp/server/thin.pid
|
||||
log: /home/deploy/myapp/logs/thin.log
|
||||
timeout: 30
|
||||
port: 7654
|
||||
max_conns: 1024
|
||||
chdir: /home/deploy/myapp/site_files
|
||||
rackup: /home/deploy/myapp/server/config.ru
|
||||
max_persistent_conns: 512
|
||||
environment: production
|
||||
address: 127.0.0.1
|
||||
servers: 1
|
||||
daemonize: true
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
require "grack/bundle"
|
||||
|
||||
module Grack
|
||||
|
||||
end
|
|
@ -0,0 +1,37 @@
|
|||
require 'rack/auth/basic'
|
||||
require 'rack/auth/abstract/handler'
|
||||
require 'rack/auth/abstract/request'
|
||||
|
||||
module Grack
|
||||
class Auth < Rack::Auth::Basic
|
||||
def call(env)
|
||||
@env = env
|
||||
@request = Rack::Request.new(env)
|
||||
@auth = Request.new(env)
|
||||
|
||||
if not @auth.provided?
|
||||
unauthorized
|
||||
elsif not @auth.basic?
|
||||
bad_request
|
||||
else
|
||||
result = if (access = valid?(@auth) and access == true)
|
||||
@env['REMOTE_USER'] = @auth.username
|
||||
@app.call(env)
|
||||
else
|
||||
if access == '404'
|
||||
render_not_found
|
||||
elsif access == '403'
|
||||
render_no_access
|
||||
else
|
||||
unauthorized
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
end# method call
|
||||
|
||||
# def valid?
|
||||
# false
|
||||
# end
|
||||
end# class Auth
|
||||
end# module Grack
|
|
@ -0,0 +1,19 @@
|
|||
require 'rack/builder'
|
||||
require 'grack/auth'
|
||||
require 'grack/server'
|
||||
|
||||
module Grack
|
||||
module Bundle
|
||||
extend self
|
||||
|
||||
def new(config)
|
||||
Rack::Builder.new do
|
||||
use Grack::Auth do |username, password|
|
||||
yield(username, password)
|
||||
end
|
||||
run Grack::Server.new(config)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,85 @@
|
|||
module Grack
|
||||
class Git
|
||||
attr_reader :repo
|
||||
|
||||
def initialize(git_path, repo_path)
|
||||
@git_path = git_path
|
||||
@repo = repo_path
|
||||
end
|
||||
|
||||
def update_server_info
|
||||
execute(%W(update-server-info))
|
||||
end
|
||||
|
||||
def command(cmd)
|
||||
[@git_path || 'git'] + cmd
|
||||
end
|
||||
|
||||
def capture(cmd)
|
||||
# _Not_ the same as `IO.popen(...).read`
|
||||
# By using a block we tell IO.popen to close (wait for) the child process
|
||||
# after we are done reading its output.
|
||||
if RUBY_VERSION.start_with?("2")
|
||||
IO.popen(popen_env, cmd, popen_options) { |p| p.read }
|
||||
else
|
||||
IO.popen(cmd, popen_options) { |p| p.read }
|
||||
end
|
||||
end
|
||||
|
||||
def execute(cmd)
|
||||
cmd = command(cmd)
|
||||
if block_given?
|
||||
|
||||
if RUBY_VERSION.start_with?("2")
|
||||
IO.popen(popen_env, cmd, File::RDWR, popen_options) do |pipe|
|
||||
yield(pipe)
|
||||
end
|
||||
else
|
||||
IO.popen(cmd, File::RDWR, popen_options) do |pipe|
|
||||
yield(pipe)
|
||||
end
|
||||
end
|
||||
else
|
||||
capture(cmd).chomp
|
||||
end
|
||||
end
|
||||
|
||||
def popen_options
|
||||
{ chdir: repo, unsetenv_others: true }
|
||||
end
|
||||
|
||||
def popen_env
|
||||
{ 'PATH' => ENV['PATH'], 'GL_ID' => ENV['GL_ID'] }
|
||||
end
|
||||
|
||||
def config_setting(service_name)
|
||||
service_name = service_name.gsub('-', '')
|
||||
setting = config("http.#{service_name}")
|
||||
|
||||
if service_name == 'uploadpack'
|
||||
setting != 'false'
|
||||
else
|
||||
setting == 'true'
|
||||
end
|
||||
end
|
||||
|
||||
def config(config_name)
|
||||
execute(%W(config #{config_name}))
|
||||
end
|
||||
|
||||
def valid_repo?
|
||||
return false unless File.exists?(repo) && File.realpath(repo) == repo
|
||||
|
||||
match = execute(%W(rev-parse --git-dir)).match(/\.$|\.git$/)
|
||||
|
||||
if RUBY_VERSION.start_with?("2")
|
||||
if match.to_s == '.git'
|
||||
# Since the parent could be a git repo, we want to make sure the actual repo contains a git dir.
|
||||
return false unless Dir.entries(repo).include?('.git')
|
||||
end
|
||||
end
|
||||
|
||||
match
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,308 @@
|
|||
require 'zlib'
|
||||
require 'rack/request'
|
||||
require 'rack/response'
|
||||
require 'rack/utils'
|
||||
require 'time'
|
||||
|
||||
require 'grack/git'
|
||||
|
||||
module Grack
|
||||
class Server
|
||||
attr_reader :git
|
||||
|
||||
SERVICES = [
|
||||
["POST", 'service_rpc', "(.*?)/git-upload-pack$", 'upload-pack'],
|
||||
["POST", 'service_rpc', "(.*?)/git-receive-pack$", 'receive-pack'],
|
||||
|
||||
["GET", 'get_info_refs', "(.*?)/info/refs$"],
|
||||
["GET", 'get_text_file', "(.*?)/HEAD$"],
|
||||
["GET", 'get_text_file', "(.*?)/objects/info/alternates$"],
|
||||
["GET", 'get_text_file', "(.*?)/objects/info/http-alternates$"],
|
||||
["GET", 'get_info_packs', "(.*?)/objects/info/packs$"],
|
||||
["GET", 'get_text_file', "(.*?)/objects/info/[^/]*$"],
|
||||
["GET", 'get_loose_object', "(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$"],
|
||||
["GET", 'get_pack_file', "(.*?)/objects/pack/pack-[0-9a-f]{40}\\.pack$"],
|
||||
["GET", 'get_idx_file', "(.*?)/objects/pack/pack-[0-9a-f]{40}\\.idx$"],
|
||||
]
|
||||
|
||||
def initialize(config = false)
|
||||
set_config(config)
|
||||
end
|
||||
|
||||
def set_config(config)
|
||||
@config = config || {}
|
||||
end
|
||||
|
||||
def set_config_setting(key, value)
|
||||
@config[key] = value
|
||||
end
|
||||
|
||||
def call(env)
|
||||
dup._call(env)
|
||||
end
|
||||
|
||||
def _call(env)
|
||||
@env = env
|
||||
@req = Rack::Request.new(env)
|
||||
|
||||
cmd, path, @reqfile, @rpc = match_routing
|
||||
|
||||
return render_method_not_allowed if cmd == 'not_allowed'
|
||||
return render_not_found unless cmd
|
||||
|
||||
@git = get_git(env["REP_PATH"] || path)
|
||||
return render_not_found unless git.valid_repo?
|
||||
|
||||
self.method(cmd).call
|
||||
end
|
||||
|
||||
# ---------------------------------
|
||||
# actual command handling functions
|
||||
# ---------------------------------
|
||||
|
||||
# Uses chunked (streaming) transfer, otherwise response
|
||||
# blocks to calculate Content-Length header
|
||||
# http://en.wikipedia.org/wiki/Chunked_transfer_encoding
|
||||
|
||||
CRLF = "\r\n"
|
||||
|
||||
def service_rpc
|
||||
return render_no_access unless has_access?(@rpc, true)
|
||||
|
||||
input = read_body
|
||||
|
||||
@res = Rack::Response.new
|
||||
@res.status = 200
|
||||
@res["Content-Type"] = "application/x-git-%s-result" % @rpc
|
||||
@res["Transfer-Encoding"] = "chunked"
|
||||
@res["Cache-Control"] = "no-cache"
|
||||
|
||||
@res.finish do
|
||||
git.execute([@rpc, '--stateless-rpc', git.repo]) do |pipe|
|
||||
pipe.write(input)
|
||||
pipe.close_write
|
||||
|
||||
while block = pipe.read(8192) # 8KB at a time
|
||||
@res.write encode_chunk(block) # stream it to the client
|
||||
end
|
||||
|
||||
@res.write terminating_chunk
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def encode_chunk(chunk)
|
||||
size_in_hex = chunk.size.to_s(16)
|
||||
[size_in_hex, CRLF, chunk, CRLF].join
|
||||
end
|
||||
|
||||
def terminating_chunk
|
||||
[0, CRLF, CRLF].join
|
||||
end
|
||||
|
||||
def get_info_refs
|
||||
service_name = get_service_type
|
||||
return dumb_info_refs unless has_access?(service_name)
|
||||
|
||||
refs = git.execute([service_name, '--stateless-rpc', '--advertise-refs', git.repo])
|
||||
|
||||
@res = Rack::Response.new
|
||||
@res.status = 200
|
||||
@res["Content-Type"] = "application/x-git-%s-advertisement" % service_name
|
||||
hdr_nocache
|
||||
|
||||
@res.write(pkt_write("# service=git-#{service_name}\n"))
|
||||
@res.write(pkt_flush)
|
||||
@res.write(refs)
|
||||
|
||||
@res.finish
|
||||
end
|
||||
|
||||
def dumb_info_refs
|
||||
git.update_server_info
|
||||
send_file(@reqfile, "text/plain; charset=utf-8") do
|
||||
hdr_nocache
|
||||
end
|
||||
end
|
||||
|
||||
def get_info_packs
|
||||
# objects/info/packs
|
||||
send_file(@reqfile, "text/plain; charset=utf-8") do
|
||||
hdr_nocache
|
||||
end
|
||||
end
|
||||
|
||||
def get_loose_object
|
||||
send_file(@reqfile, "application/x-git-loose-object") do
|
||||
hdr_cache_forever
|
||||
end
|
||||
end
|
||||
|
||||
def get_pack_file
|
||||
send_file(@reqfile, "application/x-git-packed-objects") do
|
||||
hdr_cache_forever
|
||||
end
|
||||
end
|
||||
|
||||
def get_idx_file
|
||||
send_file(@reqfile, "application/x-git-packed-objects-toc") do
|
||||
hdr_cache_forever
|
||||
end
|
||||
end
|
||||
|
||||
def get_text_file
|
||||
send_file(@reqfile, "text/plain") do
|
||||
hdr_nocache
|
||||
end
|
||||
end
|
||||
|
||||
# ------------------------
|
||||
# logic helping functions
|
||||
# ------------------------
|
||||
|
||||
# some of this borrowed from the Rack::File implementation
|
||||
def send_file(reqfile, content_type)
|
||||
reqfile = File.join(git.repo, reqfile)
|
||||
return render_not_found unless File.exists?(reqfile)
|
||||
|
||||
return render_not_found unless reqfile == File.realpath(reqfile)
|
||||
|
||||
# reqfile looks legit: no path traversal, no leading '|'
|
||||
|
||||
@res = Rack::Response.new
|
||||
@res.status = 200
|
||||
@res["Content-Type"] = content_type
|
||||
@res["Last-Modified"] = File.mtime(reqfile).httpdate
|
||||
|
||||
yield
|
||||
|
||||
if size = File.size?(reqfile)
|
||||
@res["Content-Length"] = size.to_s
|
||||
@res.finish do
|
||||
File.open(reqfile, "rb") do |file|
|
||||
while part = file.read(8192)
|
||||
@res.write part
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
body = [File.read(reqfile)]
|
||||
size = Rack::Utils.bytesize(body.first)
|
||||
@res["Content-Length"] = size
|
||||
@res.write body
|
||||
@res.finish
|
||||
end
|
||||
end
|
||||
|
||||
def get_git(path)
|
||||
# root = @config[:project_root] || Dir.pwd
|
||||
# path = File.join(root, path)
|
||||
Grack::Git.new(@config[:git_path], path)
|
||||
end
|
||||
|
||||
def get_service_type
|
||||
service_type = @req.params['service']
|
||||
return false unless service_type
|
||||
return false if service_type[0, 4] != 'git-'
|
||||
service_type.gsub('git-', '')
|
||||
end
|
||||
|
||||
def match_routing
|
||||
cmd = nil
|
||||
path = nil
|
||||
|
||||
SERVICES.each do |method, handler, match, rpc|
|
||||
next unless m = Regexp.new(match).match(@req.path_info)
|
||||
|
||||
return ['not_allowed'] unless method == @req.request_method
|
||||
|
||||
cmd = handler
|
||||
path = m[1]
|
||||
file = @req.path_info.sub(path + '/', '')
|
||||
|
||||
return [cmd, path, file, rpc]
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def has_access?(rpc, check_content_type = false)
|
||||
if check_content_type
|
||||
conten_type = "application/x-git-%s-request" % rpc
|
||||
return false unless @req.content_type == conten_type
|
||||
end
|
||||
|
||||
return false unless ['upload-pack', 'receive-pack'].include?(rpc)
|
||||
|
||||
if rpc == 'receive-pack'
|
||||
return @config[:receive_pack] if @config.include?(:receive_pack)
|
||||
end
|
||||
|
||||
if rpc == 'upload-pack'
|
||||
return @config[:upload_pack] if @config.include?(:upload_pack)
|
||||
end
|
||||
|
||||
git.config_setting(rpc)
|
||||
end
|
||||
|
||||
def read_body
|
||||
if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/
|
||||
Zlib::GzipReader.new(@req.body).read
|
||||
else
|
||||
@req.body.read
|
||||
end
|
||||
end
|
||||
|
||||
# --------------------------------------
|
||||
# HTTP error response handling functions
|
||||
# --------------------------------------
|
||||
|
||||
PLAIN_TYPE = { "Content-Type" => "text/plain" }
|
||||
|
||||
def render_method_not_allowed
|
||||
if @env['SERVER_PROTOCOL'] == "HTTP/1.1"
|
||||
[405, PLAIN_TYPE, ["Method Not Allowed"]]
|
||||
else
|
||||
[400, PLAIN_TYPE, ["Bad Request"]]
|
||||
end
|
||||
end
|
||||
|
||||
def render_not_found
|
||||
[404, PLAIN_TYPE, ["Not Found"]]
|
||||
end
|
||||
|
||||
def render_no_access
|
||||
[403, PLAIN_TYPE, ["Forbidden"]]
|
||||
end
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# packet-line handling functions
|
||||
# ------------------------------
|
||||
|
||||
def pkt_flush
|
||||
'0000'
|
||||
end
|
||||
|
||||
def pkt_write(str)
|
||||
(str.size + 4).to_s(16).rjust(4, '0') + str
|
||||
end
|
||||
|
||||
# ------------------------
|
||||
# header writing functions
|
||||
# ------------------------
|
||||
|
||||
def hdr_nocache
|
||||
@res["Expires"] = "Fri, 01 Jan 1980 00:00:00 GMT"
|
||||
@res["Pragma"] = "no-cache"
|
||||
@res["Cache-Control"] = "no-cache, max-age=0, must-revalidate"
|
||||
end
|
||||
|
||||
def hdr_cache_forever
|
||||
now = Time.now().to_i
|
||||
@res["Date"] = now.to_s
|
||||
@res["Expires"] = (now + 31536000).to_s;
|
||||
@res["Cache-Control"] = "public, max-age=31536000";
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
module Grack
|
||||
VERSION = "2.0.2"
|
||||
end
|
|
@ -0,0 +1,264 @@
|
|||
require 'rack'
|
||||
require 'rack/test'
|
||||
require 'test/unit'
|
||||
require 'mocha'
|
||||
require 'digest/sha1'
|
||||
|
||||
require_relative '../lib/grack/server.rb'
|
||||
require_relative '../lib/grack/git.rb'
|
||||
require 'pp'
|
||||
|
||||
class GitHttpTest < Test::Unit::TestCase
|
||||
include Rack::Test::Methods
|
||||
|
||||
def example
|
||||
File.expand_path(File.dirname(__FILE__))
|
||||
end
|
||||
|
||||
def app
|
||||
config = {
|
||||
:project_root => example,
|
||||
:upload_pack => true,
|
||||
:receive_pack => true,
|
||||
}
|
||||
Grack::Server.new(config)
|
||||
end
|
||||
|
||||
def test_upload_pack_advertisement
|
||||
get "/example/info/refs?service=git-upload-pack"
|
||||
assert_equal 200, r.status
|
||||
assert_equal "application/x-git-upload-pack-advertisement", r.headers["Content-Type"]
|
||||
assert_equal "001e# service=git-upload-pack", r.body.split("\n").first
|
||||
assert_match 'multi_ack_detailed', r.body
|
||||
end
|
||||
|
||||
def test_no_access_wrong_content_type_up
|
||||
post "/example/git-upload-pack"
|
||||
assert_equal 403, r.status
|
||||
end
|
||||
|
||||
def test_no_access_wrong_content_type_rp
|
||||
post "/example/git-receive-pack"
|
||||
assert_equal 403, r.status
|
||||
end
|
||||
|
||||
def test_no_access_wrong_method_rcp
|
||||
get "/example/git-upload-pack"
|
||||
assert_equal 400, r.status
|
||||
end
|
||||
|
||||
def test_no_access_wrong_command_rcp
|
||||
post "/example/git-upload-packfile"
|
||||
assert_equal 404, r.status
|
||||
end
|
||||
|
||||
def test_no_access_wrong_path_rcp
|
||||
Grack::Git.any_instance.stubs(:valid_repo?).returns(false)
|
||||
post "/example-wrong/git-upload-pack"
|
||||
assert_equal 404, r.status
|
||||
end
|
||||
|
||||
def test_upload_pack_rpc
|
||||
Grack::Git.any_instance.stubs(:valid_repo?).returns(true)
|
||||
IO.stubs(:popen).returns(MockProcess.new)
|
||||
post "/example/git-upload-pack", {}, {"CONTENT_TYPE" => "application/x-git-upload-pack-request"}
|
||||
assert_equal 200, r.status
|
||||
assert_equal "application/x-git-upload-pack-result", r.headers["Content-Type"]
|
||||
end
|
||||
|
||||
def test_receive_pack_advertisement
|
||||
get "/example/info/refs?service=git-receive-pack"
|
||||
assert_equal 200, r.status
|
||||
assert_equal "application/x-git-receive-pack-advertisement", r.headers["Content-Type"]
|
||||
assert_equal "001f# service=git-receive-pack", r.body.split("\n").first
|
||||
assert_match 'report-status', r.body
|
||||
assert_match 'delete-refs', r.body
|
||||
assert_match 'ofs-delta', r.body
|
||||
end
|
||||
|
||||
def test_recieve_pack_rpc
|
||||
Grack::Git.any_instance.stubs(:valid_repo?).returns(true)
|
||||
IO.stubs(:popen).yields(MockProcess.new)
|
||||
post "/example/git-receive-pack", {}, {"CONTENT_TYPE" => "application/x-git-receive-pack-request"}
|
||||
assert_equal 200, r.status
|
||||
assert_equal "application/x-git-receive-pack-result", r.headers["Content-Type"]
|
||||
end
|
||||
|
||||
def test_info_refs_dumb
|
||||
get "/example/.git/info/refs"
|
||||
assert_equal 200, r.status
|
||||
end
|
||||
|
||||
def test_info_packs
|
||||
get "/example/.git/objects/info/packs"
|
||||
assert_equal 200, r.status
|
||||
assert_match /P pack-(.*?).pack/, r.body
|
||||
end
|
||||
|
||||
def test_loose_objects
|
||||
path, content = write_test_objects
|
||||
get "/example/.git/objects/#{path}"
|
||||
assert_equal 200, r.status
|
||||
assert_equal content, r.body
|
||||
remove_test_objects
|
||||
end
|
||||
|
||||
def test_pack_file
|
||||
path, content = write_test_objects
|
||||
get "/example/.git/objects/pack/pack-#{content}.pack"
|
||||
assert_equal 200, r.status
|
||||
assert_equal content, r.body
|
||||
remove_test_objects
|
||||
end
|
||||
|
||||
def test_index_file
|
||||
path, content = write_test_objects
|
||||
get "/example/.git/objects/pack/pack-#{content}.idx"
|
||||
assert_equal 200, r.status
|
||||
assert_equal content, r.body
|
||||
remove_test_objects
|
||||
end
|
||||
|
||||
def test_text_file
|
||||
get "/example/.git/HEAD"
|
||||
assert_equal 200, r.status
|
||||
assert_equal 41, r.body.size # submodules have detached head
|
||||
end
|
||||
|
||||
def test_no_size_avail
|
||||
File.stubs('size?').returns(false)
|
||||
get "/example/.git/HEAD"
|
||||
assert_equal 200, r.status
|
||||
assert_equal 46, r.body.size # submodules have detached head
|
||||
end
|
||||
|
||||
def test_config_upload_pack_off
|
||||
a1 = app
|
||||
a1.set_config_setting(:upload_pack, false)
|
||||
session = Rack::Test::Session.new(a1)
|
||||
session.get "/example/info/refs?service=git-upload-pack"
|
||||
assert_equal 404, session.last_response.status
|
||||
end
|
||||
|
||||
def test_config_receive_pack_off
|
||||
a1 = app
|
||||
a1.set_config_setting(:receive_pack, false)
|
||||
session = Rack::Test::Session.new(a1)
|
||||
session.get "/example/info/refs?service=git-receive-pack"
|
||||
assert_equal 404, session.last_response.status
|
||||
end
|
||||
|
||||
def test_config_bad_service
|
||||
get "/example/info/refs?service=git-receive-packfile"
|
||||
assert_equal 404, r.status
|
||||
end
|
||||
|
||||
def test_git_config_receive_pack
|
||||
app1 = Grack::Server.new({:project_root => example})
|
||||
app1.instance_variable_set(:@git, Grack::Git.new('git', example ))
|
||||
session = Rack::Test::Session.new(app1)
|
||||
git = Grack::Git
|
||||
git.any_instance.stubs(:config).with('http.receivepack').returns('')
|
||||
session.get "/example/info/refs?service=git-receive-pack"
|
||||
assert_equal 404, session.last_response.status
|
||||
|
||||
git.any_instance.stubs(:config).with('http.receivepack').returns('true')
|
||||
session.get "/example/info/refs?service=git-receive-pack"
|
||||
assert_equal 200, session.last_response.status
|
||||
|
||||
git.any_instance.stubs(:config).with('http.receivepack').returns('false')
|
||||
session.get "/example/info/refs?service=git-receive-pack"
|
||||
assert_equal 404, session.last_response.status
|
||||
end
|
||||
|
||||
def test_git_config_upload_pack
|
||||
app1 = Grack::Server.new({:project_root => example})
|
||||
# app1.instance_variable_set(:@git, Grack::Git.new('git', example ))
|
||||
session = Rack::Test::Session.new(app1)
|
||||
git = Grack::Git
|
||||
git.any_instance.stubs(:config).with('http.uploadpack').returns('')
|
||||
session.get "/example/info/refs?service=git-upload-pack"
|
||||
assert_equal 200, session.last_response.status
|
||||
|
||||
git.any_instance.stubs(:config).with('http.uploadpack').returns('true')
|
||||
session.get "/example/info/refs?service=git-upload-pack"
|
||||
assert_equal 200, session.last_response.status
|
||||
|
||||
git.any_instance.stubs(:config).with('http.uploadpack').returns('false')
|
||||
session.get "/example/info/refs?service=git-upload-pack"
|
||||
assert_equal 404, session.last_response.status
|
||||
end
|
||||
|
||||
def test_send_file
|
||||
app1 = app
|
||||
app1.instance_variable_set(:@git, Grack::Git.new('git', Dir.pwd))
|
||||
# Reject path traversal
|
||||
assert_equal 404, app1.send_file('tests/../tests', 'text/plain').first
|
||||
# Reject paths starting with '|', avoid File.read('|touch /tmp/pawned; ls /tmp')
|
||||
assert_equal 404, app1.send_file('|tests', 'text/plain').first
|
||||
end
|
||||
|
||||
def test_get_git
|
||||
# Guard against non-existent directories
|
||||
git1 = Grack::Git.new('git', 'foobar')
|
||||
assert_equal false, git1.valid_repo?
|
||||
# Guard against path traversal
|
||||
git2 = Grack::Git.new('git', '/../tests')
|
||||
assert_equal false, git2.valid_repo?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def r
|
||||
last_response
|
||||
end
|
||||
|
||||
def write_test_objects
|
||||
content = Digest::SHA1.hexdigest('gitrocks')
|
||||
base = File.join(File.expand_path(File.dirname(__FILE__)), 'example', '.git', 'objects')
|
||||
obj = File.join(base, '20')
|
||||
Dir.mkdir(obj) rescue nil
|
||||
file = File.join(obj, content[0, 38])
|
||||
File.open(file, 'w') { |f| f.write(content) }
|
||||
pack = File.join(base, 'pack', "pack-#{content}.pack")
|
||||
File.open(pack, 'w') { |f| f.write(content) }
|
||||
idx = File.join(base, 'pack', "pack-#{content}.idx")
|
||||
File.open(idx, 'w') { |f| f.write(content) }
|
||||
["20/#{content[0,38]}", content]
|
||||
end
|
||||
|
||||
def remove_test_objects
|
||||
content = Digest::SHA1.hexdigest('gitrocks')
|
||||
base = File.join(File.expand_path(File.dirname(__FILE__)), 'example', '.git', 'objects')
|
||||
obj = File.join(base, '20')
|
||||
file = File.join(obj, content[0, 38])
|
||||
pack = File.join(base, 'pack', "pack-#{content}.pack")
|
||||
idx = File.join(base, 'pack', "pack-#{content}.idx")
|
||||
File.unlink(file)
|
||||
File.unlink(pack)
|
||||
File.unlink(idx)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class MockProcess
|
||||
def initialize
|
||||
@counter = 0
|
||||
end
|
||||
|
||||
def write(data)
|
||||
end
|
||||
|
||||
def read(data = nil)
|
||||
''
|
||||
end
|
||||
|
||||
def eof?
|
||||
@counter += 1
|
||||
@counter > 1 ? true : false
|
||||
end
|
||||
|
||||
def close_write
|
||||
true
|
||||
end
|
||||
end
|
|
@ -1,2 +1,3 @@
|
|||
require 'trustie/utils'
|
||||
require 'trustie/utils/image'
|
||||
require 'trustie/grack/grack'
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
#coding=utf-8
|
||||
#
|
||||
require 'rack/auth/basic'
|
||||
require 'rack/auth/abstract/handler'
|
||||
require 'rack/auth/abstract/request'
|
||||
|
||||
module Grack
|
||||
|
||||
class Auth < Rack::Auth::Basic
|
||||
DOWNLOAD_COMMANDS = %w{ git-upload-pack git-upload-archive }
|
||||
PUSH_COMMANDS = %w{ git-receive-pack }
|
||||
|
||||
attr_accessor :user, :repository
|
||||
def call(env)
|
||||
@env = env
|
||||
@request = Rack::Request.new(env)
|
||||
@auth = Request.new(env)
|
||||
|
||||
if not @auth.provided?
|
||||
unauthorized
|
||||
elsif not @auth.basic?
|
||||
bad_request
|
||||
else
|
||||
result = if (access = valid?(@auth) and access == true)
|
||||
@env['REMOTE_USER'] = @auth.username
|
||||
env['REP_PATH'] = repository.root_url
|
||||
@app.call(env)
|
||||
else
|
||||
if access == '404'
|
||||
render_not_found
|
||||
elsif access == '403'
|
||||
#render_no_access
|
||||
unauthorized
|
||||
else
|
||||
unauthorized
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
end# method call
|
||||
|
||||
|
||||
def render_not_found
|
||||
[404, {"Content-Type" => "text/plain"}, ["Not Found"]]
|
||||
end
|
||||
|
||||
def valid?(auth)
|
||||
self.repository = auth_rep
|
||||
return "404" unless repository
|
||||
username, password = auth.credentials
|
||||
self.user = auth_user(username, password)
|
||||
return '403' unless user
|
||||
access = auth_request
|
||||
puts "access #{access}"
|
||||
access
|
||||
end
|
||||
|
||||
def auth_rep
|
||||
rep = nil
|
||||
match = @request.path_info.match(/(\/.+\.git)\//)
|
||||
if match
|
||||
rep = Repository.where("root_url like ?", "%#{match[1]}").first
|
||||
end
|
||||
rep
|
||||
end
|
||||
|
||||
def auth_user(username, password)
|
||||
u, last_login_on = User.try_to_login(username, password)
|
||||
unless u && (u.member_of?(repository.project) || u.admin?)
|
||||
u = nil
|
||||
end
|
||||
u
|
||||
end
|
||||
|
||||
def auth_request
|
||||
case git_cmd
|
||||
when *DOWNLOAD_COMMANDS
|
||||
user != nil
|
||||
when *PUSH_COMMANDS
|
||||
unless user
|
||||
false
|
||||
else
|
||||
### 只有Manager和Development才有push权限
|
||||
repository.project.members.where(user_id: user.id).first.roles.any?{|r| r.name == 'Manager' || r.name == 'Developer'}
|
||||
end
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def git_cmd
|
||||
if @request.get?
|
||||
@request.params['service']
|
||||
elsif @request.post?
|
||||
File.basename(@request.path)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
end# class Auth
|
||||
end# module Grack
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
require_relative 'auth'
|
||||
|
||||
module Trustie
|
||||
module Grack
|
||||
|
||||
def self.new
|
||||
Rack::Builder.new do
|
||||
use ::Grack::Auth
|
||||
run ::Grack::Server.new(
|
||||
project_root: Redmine::Configuration['repository_root_path'] || "/home/pdl/redmine-2.3.2-0/apache2/htdocs",
|
||||
upload_pack: true,
|
||||
receive_pack:true
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -5157,7 +5157,7 @@ KEditor.prototype = {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
statusbar.last().css('visibility', 'hidden');
|
||||
if(statusbar.last()) {statusbar.last().css('visibility', 'hidden');}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 518 B |
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,46 @@
|
|||
$(function(){
|
||||
$("#RSide").css("min-height",$("#LSide").height()-40).css("padding","10px");
|
||||
|
||||
//头像相关
|
||||
$("#homepage_portrait_image").live("mouseover",function(){
|
||||
$("#edit_user_file_btn").show();
|
||||
$("#watch_user_btn").show();
|
||||
}).live("mouseout",function(){
|
||||
$("#edit_user_file_btn").hide();
|
||||
$("#watch_user_btn").hide();
|
||||
});
|
||||
});
|
||||
|
||||
//编辑个人简介
|
||||
function show_edit_user_introduction() {
|
||||
$("#user_brief_introduction_show").hide();
|
||||
$("#user_brief_introduction_edit").show();
|
||||
$("#user_brief_introduction_edit").focus();
|
||||
}
|
||||
|
||||
//编辑个人简介完成之后提交
|
||||
function edit_user_introduction(url){
|
||||
$.get(
|
||||
url,
|
||||
{ brief_introduction: $("#user_brief_introduction_edit").val() },
|
||||
function (data) {
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$(function(){
|
||||
$(".newsType").mouseover(function(){
|
||||
$(".resourcesIcon").css({background:"url(images/resource_icon_list.png) 0px -25px no-repeat"});
|
||||
});
|
||||
$(".newsType").mouseout(function(){
|
||||
$(".resourcesIcon").css({background:"url(images/resource_icon_list.png) 0px 0px no-repeat"});
|
||||
});
|
||||
$(".resourcesSelected").mouseover(function(){
|
||||
$(".resourcesIcon").css({background:"url(images/resource_icon_list.png) 0px -25px no-repeat"});
|
||||
});
|
||||
$(".resourcesSelected").mouseout(function(){
|
||||
$(".resourcesIcon").css({background:"url(images/resource_icon_list.png) 0px 0px no-repeat"});
|
||||
});
|
||||
});
|
||||
//个人动态 end
|
|
@ -258,4 +258,19 @@ $(function(){
|
|||
init_list_more_div(params)
|
||||
});
|
||||
});
|
||||
|
||||
$(function(){
|
||||
$(".newsType").mouseover(function(){
|
||||
$(".resourcesIcon").css({background:"url(images/resource_icon_list.png) 0px -25px no-repeat"});
|
||||
});
|
||||
$(".newsType").mouseout(function(){
|
||||
$(".resourcesIcon").css({background:"url(images/resource_icon_list.png) 0px 0px no-repeat"});
|
||||
});
|
||||
$(".resourcesSelected").mouseover(function(){
|
||||
$(".resourcesIcon").css({background:"url(images/resource_icon_list.png) 0px -25px no-repeat"});
|
||||
});
|
||||
$(".resourcesSelected").mouseout(function(){
|
||||
$(".resourcesIcon").css({background:"url(images/resource_icon_list.png) 0px 0px no-repeat"});
|
||||
});
|
||||
});
|
||||
//个人动态 end
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,682 @@
|
|||
/* CSS Document */
|
||||
/* 2015-06-26 */
|
||||
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{ margin:0; padding:0;}
|
||||
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体"; font-size:12px;line-height:1.5; background:#eaebec;}
|
||||
div,img,tr,td,table{ border:0;}
|
||||
table,tr,td{border:0;cellspacing:0; cellpadding:0;}
|
||||
ol,ul,li{ list-style-type:none}
|
||||
a:link,a:visited{color:#7f7f7f;text-decoration:none;}
|
||||
a:hover,a:active{color:#000;}
|
||||
|
||||
/*常用*/
|
||||
.hidden{overflow:hidden; white-space: nowrap; text-overflow:ellipsis;}
|
||||
.none{display: none;}
|
||||
.rside_back{ width:670px; margin-left:10px; background:#fff; margin-bottom:10px;}
|
||||
.break_word{ word-break:break-all; word-wrap: break-word;}
|
||||
select,input,textarea{ border:1px solid #64bdd9; background:#fff; color:#000; padding-left:5px; }
|
||||
.sub_btn{ cursor:pointer; -moz-border-radius:3px; -webkit-border-radius:3px; border:1px solid #707070; color:#000; border-radius:3px; padding:1px 10px; background:#dbdbdb;}
|
||||
.sub_btn:hover{ background:#b5e2fa; color:#000; border:1px solid #3c7fb1;}
|
||||
table{ background:#fff;}
|
||||
.more{ font-weight:normal; color:#999; font-size:12px;}
|
||||
.no_line{ border-bottom:none;}
|
||||
.line{border-bottom:1px dashed #d4d4d4; padding-bottom:10px; margin-bottom:10px;}
|
||||
.no_border{ border:none;background:none;}
|
||||
.min_search{ width:150px; height:20px; border:1px solid #d0d0d0; color:#666; background:url(../images/public_icon.png) 135px -193px no-repeat; cursor:pointer;}
|
||||
|
||||
/* font & color */
|
||||
h2{ font-size:18px; color:#15bccf;}
|
||||
h3{ font-size:14px; color:#e8770d;}
|
||||
h4{ font-size:14px; color:#3b3b3b;}
|
||||
.f12{font-size:12px; font-weight:normal;}
|
||||
.f14{font-size:14px;}
|
||||
.f16{font-size:16px;}
|
||||
.f18{font-size:18px;}
|
||||
.fb{font-weight:bold;}
|
||||
.lh20{line-height:20px;}
|
||||
.lh22{line-height:22px;}
|
||||
.lh24{line-height:24px;}
|
||||
.lh26{line-height:26px;}
|
||||
.fmYh{font-family:"MicroSoft Yahei";}
|
||||
.font999{ color:#999;}
|
||||
.fontRed{color:#770000;}
|
||||
.text_c{ text-align:center;}
|
||||
|
||||
/* Float & Clear */
|
||||
.cl{ clear:both; overflow:hidden; }
|
||||
.fl{float:left;display:inline;}
|
||||
.fr{float:right;display:inline;}
|
||||
.f_l{ float:left;}
|
||||
.f_r{ float:right;}
|
||||
.clearfix:after{clear:both;content:".";display:block;font-size:0;height:0;line-height:0;visibility:hidden}
|
||||
.clearfix{clear:both;zoom:1}
|
||||
.break_word{ word-break:break-all; word-wrap: break-word;}
|
||||
.white_space{white-space:nowrap;}
|
||||
|
||||
/* Spacing */
|
||||
.ml2{ margin-left:2px;}
|
||||
.ml3{ margin-left:3px;}
|
||||
.ml4{ margin-left:4px;}
|
||||
.ml5{ margin-left:5px;}
|
||||
.ml8{ margin-left:8px;}
|
||||
.ml10{ margin-left:10px;}
|
||||
.ml15{ margin-left:15px;}
|
||||
.ml20{ margin-left:20px;}
|
||||
.ml40{ margin-left:40px;}
|
||||
.ml45{ margin-left:45px;}
|
||||
.ml55{ margin-left:55px;}
|
||||
.ml30{ margin-left:30px;}
|
||||
.ml60{ margin-left:60px;}
|
||||
.ml80{ margin-left:80px;}
|
||||
.ml90{ margin-left:90px;}
|
||||
.ml100{ margin-left:100px;}
|
||||
.ml110{ margin-left:110px;}
|
||||
.mr5{ margin-right:5px;}
|
||||
.mr45 {margin-right:45px;}
|
||||
.mr55{ margin-right:55px;}
|
||||
.mr10{ margin-right:10px;}
|
||||
.mr15 {margin-right:15px;}
|
||||
.mr20{ margin-right:20px;}
|
||||
.mr30{ margin-right:30px;}
|
||||
.mr40{ margin-right:40px;}
|
||||
.mw20{ margin: 0 20px;}
|
||||
.mt3{ margin-top:3px;}
|
||||
.mt5{ margin-top:5px;}
|
||||
.mt8{ margin-top:8px;}
|
||||
.mt10{ margin-top:10px;}
|
||||
.mt15 {margin-top:15px;}
|
||||
.mb4{ margin-bottom:4px;}
|
||||
.mb5{ margin-bottom:5px;}
|
||||
.mb8 {margin-bottom:8px;}
|
||||
.mb10{ margin-bottom:10px !important;}
|
||||
.mb20{ margin-bottom:20px;}
|
||||
.pl15{ padding-left:15px;}
|
||||
.w20{ width:20px;}
|
||||
.w60{ width:60px;}
|
||||
.w70{ width:70px;}
|
||||
.w90{ width:90px;}
|
||||
.w210{ width:210px;}
|
||||
.w150{ width:150px;}
|
||||
.w280{ width:280px;}
|
||||
.w430{ width:470px;}
|
||||
.w520{ width:520px;}
|
||||
.w543{ width:543px;}
|
||||
.w557{ width:557px;}
|
||||
.w583{ width:583px;}
|
||||
.w350{ width:350px;}
|
||||
.w610{ width:610px;}
|
||||
.w600{ width:600px;}
|
||||
.h22{ height:22px;}
|
||||
.h26{ height:26px;}
|
||||
.h50{ height:50px;}
|
||||
.h70{ height:70px;}
|
||||
.h150{ height:150px;}
|
||||
|
||||
/* Font & background Color */
|
||||
a.b_grey{ background: #F5F5F5;}
|
||||
a.b_dgrey{ background: #CCC;}
|
||||
a.c_orange{color:#ff5722;}
|
||||
a:hover.c_orange{color: #d33503;}
|
||||
a.c_lorange{color:#ff9900;}
|
||||
a:hover.c_lorange{color:#fff;}
|
||||
a.c_blue{ color:#15bccf;}
|
||||
a.c_dblue{ color:#09658c;}
|
||||
a:hover.c_dblue{ color:#15bccf;}
|
||||
a.c_white{ color:#fff;}
|
||||
a.c_dorange{ color:#fd6e2a;}
|
||||
a.c_dark{color: #3e4040;}
|
||||
a:hover.c_dark{color: #3ca5c6;}
|
||||
a.b_blue{background: #64bdd9;}
|
||||
a:hover.b_blue{background: #41a8c8;}
|
||||
a.b_green{background:#28be6c;}
|
||||
a:hover.b_green{background:#14ad5a;}
|
||||
a.c_blue02{color: #3ca5c6;}
|
||||
a:hover.c_blue02{color: #0781b4;}
|
||||
a.c_red{ color:#F00;}
|
||||
a:hover.c_red{ color: #C00;}
|
||||
a.c_purple{color: #426e9a;}
|
||||
a:hover.c_purple{color: #d33503;}
|
||||
a.c_green{ color:#28be6c;}
|
||||
|
||||
.b_grey{ background: #F5F5F5;}
|
||||
.b_dgrey{ background: #CCC;}
|
||||
.c_orange{color:#e8770d;}
|
||||
.c_dark{ color:#2d2d2d;}
|
||||
.c_lorange{ color:#ff9900;}
|
||||
.c_purple{color: #6883b6;}
|
||||
.c_blue{ color:#15bccf;}
|
||||
.c_red{ color:#F00;}
|
||||
.c_green{ color:#28be6c;}
|
||||
.c_dblue{ color:#09658c;}
|
||||
.b_blue{background:#64bdd9;}
|
||||
.b_green{background:#28be6c;}
|
||||
.b_w{ background:#fff;}
|
||||
|
||||
/* commonBtn */
|
||||
.grey_btn{ background:#d9d9d9; color:#656565; font-weight:normal; text-align:center;padding:2px 10px;}
|
||||
a.grey_btn{ background:#d9d9d9; color:#656565; font-weight:normal; text-align:center;padding:2px 10px;}
|
||||
a:hover.grey_btn{ background:#717171; color:#fff;}
|
||||
.grey_n_btn{ background:#d9d9d9; color:#656565; font-weight:normal;padding:2px 10px; text-align:center;}
|
||||
a.grey_n_btn{background:#d9d9d9; color:#656565;font-weight:normal; padding:2px 10px; text-align:center;}
|
||||
a:hover.grey_n_btn{ background:#717171; color:#fff;}
|
||||
.green_btn{ background:#28be6c; color:#fff; font-weight:normal;padding:2px 10px; text-align:center;}
|
||||
a.green_btn{background:#28be6c;color:#fff; font-weight:normal; padding:2px 10px; text-align:center;}
|
||||
a:hover.green_btn{ background:#14ad5a;}
|
||||
.blue_btn{ background:#64bdd9; color:#fff; font-weight:normal;padding:2px 10px; text-align:center;}
|
||||
a.blue_btn{background:#64bdd9;color:#fff; font-weight:normal; padding:2px 10px; text-align:center;}
|
||||
a:hover.blue_btn{ background:#329cbd;}
|
||||
a.orange_btn{ background:#ff5722;color:#fff; font-weight:normal; padding:2px 10px; text-align:center; }
|
||||
a:hover.orange_btn{ background:#d63502;}
|
||||
|
||||
.green_u_btn{border:1px solid #3cb761; padding:2px 10px; color:#3cb761;}
|
||||
a.green_u_btn{border:1px solid #3cb761; padding:2px 10px; color:#3cb761;}
|
||||
a:hover.green_u_btn{ background:#3cb761; color:#fff;}
|
||||
.orange_u_btn{border:1px solid #ff5d31; padding:2px 10px; color:#ff5d31;}
|
||||
a.orange_u_btn{border:1px solid #ff5d31; padding:2px 10px; color:#ff5d31;}
|
||||
a:hover.orange_u_btn{background:#ff5d31; color:#fff;}
|
||||
.bgreen_u_btn{border:1px solid #1abc9c; padding:2px 10px; color:#1abc9c;}
|
||||
a.bgreen_u_btn{border:1px solid #1abc9c; padding:2px 10px; color:#1abc9c;}
|
||||
a:hover.bgreen_u_btn{background:#1abc9c; color:#fff;}
|
||||
.blue_u_btn{border:1px solid #64bdd9; padding:2px 10px; color:#64bdd9;}
|
||||
a.blue_u_btn{border:1px solid #64bdd9; padding:2px 10px; color:#64bdd9;}
|
||||
a:hover.blue_u_btn{background:#64bdd9; color:#fff;}
|
||||
.blue_n_btn{ background:#64bdd9; color:#fff; font-weight:normal;padding:2px 10px; text-align:center;}
|
||||
a.blue_n_btn{background:#64bdd9;color:#fff;font-weight:normal; padding:2px 10px; text-align:center;}
|
||||
a:hover.blue_n_btn{ background:#329cbd;}
|
||||
.green_n_btn{background:#3cb761; padding:2px 10px; color:#fff;}
|
||||
a.green_n_btn{background:#3cb761; padding:2px 10px; color:#fff;}
|
||||
a:hover.green_n_btn{ background:#14ad5a;}
|
||||
.orange_n_btn{background:#ff5d31; padding:2px 10px; color:#fff;}
|
||||
a.orange_n_btn{background:#ff5d31; padding:2px 10px; color:#fff;}
|
||||
a:hover.orange_n_btn{background:#d63502;}
|
||||
.bgreen_n_btn{background:#1abc9c; padding:2px 10px; color:#fff;}
|
||||
a.bgreen_n_btn{background:#1abc9c; padding:2px 10px; color:#fff;}
|
||||
a:hover.bgreen_n_btn{background:#08a384;}
|
||||
|
||||
.nolink_btn{ background:#BCBCBC; color: #fff; padding:2px 5px;}
|
||||
.more_btn{-moz-border-radius:3px; -webkit-border-radius:3px; border:1px solid #9DCEFF; color:#9DCEFF; border-radius:3px; padding:0px 3px;}
|
||||
.upbtn{ margin:42px 0 0 10px; border:none; color:#999; width:150px;}
|
||||
.red_btn_cir{ background:#e74c3c; padding:1px 10px; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; color:#fff; font-weight:normal;font-size:12px;}
|
||||
.green_btn_cir{ background:#28be6c; padding:1px 10px; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; color:#fff; font-weight:normal;font-size:12px;}
|
||||
.blue_btn_cir{ background:#3498db; padding:1px 10px; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; color:#fff; font-weight:normal;font-size:12px;}
|
||||
.orange_btn_cir{ background:#e67e22; padding:1px 10px; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; color:#fff; font-weight:normal; font-size:12px;}
|
||||
.bgreen_btn_cir{ background:#1abc9c; padding:1px 10px; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; color:#fff; font-weight:normal; font-size:12px;}
|
||||
/* commonpic */
|
||||
.pic_date{ display:block; background:url(../images/public_icon.png) -31px 0 no-repeat; width:16px; height:15px; }
|
||||
.pic_add{ display:block; background:url(../images/public_icon.png) -31px -273px no-repeat; width:16px; height:15px; }
|
||||
.pic_sch{ display:block; background:url(../images/public_icon.png) -31px -195px no-repeat; width:16px; height:15px; }
|
||||
.pic_mes{ display:block; background:url(../images/public_icon.png) 0px -376px no-repeat; width:20px; height:15px; padding-left:18px;}
|
||||
.pic_img{ display:block; background:url(../images/public_icon.png) -31px -419px no-repeat; width:20px; height:15px; }
|
||||
.pic_del{ display:block; background:url(../images/public_icon.png) 0px -235px no-repeat; width:20px; height:15px; }
|
||||
.pic_del:hover{ background:url(../images/public_icon.png) -32px -235px no-repeat; }
|
||||
.pic_stats{display:block; background:url(../images/public_icon.png) 0px -548px no-repeat; width:20px; height:15px;}
|
||||
.pic_files{display:block; background:url(../images/public_icon.png) 0px -578px no-repeat; width:20px; height:15px;}
|
||||
.pic_text{display:block; background:url(../images/public_icon.png) 0px -609px no-repeat; width:20px; height:18px;}
|
||||
.pic_text02{display:block; background:url(../images/public_icon.png) 0px -642px no-repeat; width:20px; height:19px;}
|
||||
.pic_edit{display:block; background:url(../images/public_icon.png) 0px -32px no-repeat; width:20px; height:15px;}
|
||||
.pic_edit:hover{display:block; background:url(../images/public_icon.png) -32px -32px no-repeat; width:20px; height:15px;}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*框架主类容*/
|
||||
#Container{ width:1000px; margin:0 auto; }
|
||||
|
||||
/*头部导航*/
|
||||
#Header{ margin:10px 0; background:#15bccf; height:40px; -moz-border-radius:5px; -webkit-border-radius:5px; border-radius:5px; position: relative;}
|
||||
.logo{ margin:5px 10px; }
|
||||
#TopNav{}
|
||||
#TopNav ul li{ margin-top:8px;}
|
||||
.topnav_a a{ font-size:14px; font-weight:bold; color:#fff; margin-right:10px;}
|
||||
.topnav_a a:hover{color: #a1ebff;;}
|
||||
#userInfo {float:right; display:inline-block; width:130px; padding-top:5px;}
|
||||
.userInfoRow2 {margin-top:-5px;}
|
||||
.myPractice {display:inline-block;}
|
||||
a.parent {background: url(../images/arrowList.png) -30px 3px no-repeat; width:95px; padding-right:50px;}
|
||||
a.parent:hover {background: url(../images/arrowList.png) -30px -14px no-repeat; width:95px; padding-right:50px; color:#fe7d68;}
|
||||
a.linkToOrange:hover {color:#fe7d68;}
|
||||
#userInfo ul li {positon: relative;}
|
||||
#userInfo ul li ul {display:none;}
|
||||
#userInfo ul li:hover ul {display:block; position:absolute;}
|
||||
#userInfo ul li:hover ul li ul {display:none;}
|
||||
#userInfo ul li:hover ul li:hover ul {display:block; position:absolute; left:110px; top:6px; width:148px; border:1px solid #15bccf; background-color:#ffffff; padding:5px 0px;}
|
||||
#userInfo ul li:hover ul li:hover ul li {max-width:148px; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; display:block; padding: 0 10px; line-height:1.5; color:#15bccf;}
|
||||
#TopUser{}
|
||||
#TopUser ul li{ margin-top:8px;}
|
||||
.topuser_a a{ font-size:14px; font-weight:bold; color:#fff; margin-right:10px;}
|
||||
.topuser_a a:hover{color: #a1ebff;}
|
||||
#TopUser02{ }
|
||||
#TopUser02 li{ float: left;}
|
||||
#TopUser02 li a{ margin-right:10px;color: #FFF;text-align: center;}
|
||||
#TopUser02 li a:hover{color: #a1ebff;}
|
||||
#TopUser02 div{ position: absolute;visibility: hidden;background:#fff;border: 1px solid #15bccf;}
|
||||
#TopUser02 div a{position: relative;display: block;white-space: nowrap;text-align: left; line-height:1.9; margin-left:5px;background: #fff;color:#15bccf; font-weight:normal;}
|
||||
#TopUser02 div a:hover{ color:#e8770d; font-weight: bold;}
|
||||
|
||||
/*myctrip*/
|
||||
.userImage{position:absolute; right:140px; top:5px; width:30px;height:30px; background: url(../images/item.png) 2px 4px no-repeat; line-height:1.4;}
|
||||
a.topnav_login_a{color:#fff; display:inline-block;}
|
||||
a.topnav_login_a:hover {color:#a1ebff;}
|
||||
a.topnav_login_mes{color:#fff; width:10px;height:20px; padding-left:15px; background: url(../images/item.png) -84px -145px no-repeat; display:inline-block; vertical-align:top;}
|
||||
a.topnav_login_mes:hover {color:#a1ebff;}
|
||||
a.topnav_login_box{ color:#fff; font-size:14px; font-weight:bold; width:90px; display:inline-block;}
|
||||
.menuArrow {background:url(../images/item.png) -20px -40px no-repeat;}
|
||||
li.menuArrow:hover {background:url(../images/item.png) -20px -70px no-repeat;}
|
||||
a.topnav_login_box:hover {color:#a1ebff;}
|
||||
.navRow1 {margin:0; padding:0;}
|
||||
.navRow2 {margin:0; padding:0;}
|
||||
.topnav_login_list{ border:1px solid #15bccf; background:#fff; padding-left:10px; padding-bottom:10px; padding-top:8px; width:60px; left:-7px; position:absolute; z-index:9999; line-height:2;}
|
||||
.topnav_login_list a{color:#15bccf;}
|
||||
.topnav_login_list li{ }
|
||||
|
||||
/*主类容*/
|
||||
#Main{ background:#fff; margin-bottom:10px;}
|
||||
#content{}
|
||||
#content02{ background:#fff; padding:10px; margin-bottom:10px;}
|
||||
/*主类容搜索*/
|
||||
#TopBar{ height:60px; margin-bottom:10px; background:#fff;}
|
||||
.topbar_info02{ margin:5px 10px;width:480px; }
|
||||
.topbar_info02 p{color: #7f7f7f;}
|
||||
.search{ margin-top:8px; margin-left:71px;}
|
||||
.search_form{margin-top:8px;margin-left:72px;}
|
||||
.topbar_info{ width:350px; color:#5c5c5c; font-size:16px; margin-right:50px; line-height:1.3; padding-left:100px;}
|
||||
a.search_btn{ display:block; background:#15bccf; color:#fff; width:60px; height:24px; text-align:center; padding-top:3px;}
|
||||
a:hover.search_btn{ background: #0fa9bb;}
|
||||
.search_text{ border:1px solid #15bccf; background:#fff; width:220px; height:25px; padding-left:5px; }
|
||||
|
||||
/*资源库*/
|
||||
.resources {width:730px; background-color:#ffffff; padding:10px;}
|
||||
.resourcesBanner {width:730px; height:40px; background-color:#eaeaea; margin-bottom:10px;}
|
||||
.bannerName {background:#64bdd9; color:#ffffff; height:40px; line-height:40px; width:90px; text-align:center; font-weight:normal; vertical-align:middle; font-size: 16px; float:left;}
|
||||
.resourcesSelect {width:30px; height:34px; float:right; position:relative; margin-top:-6px;}
|
||||
.resourcesSelected {width:25px; height:20px; position:relative; background:url(images/resource_icon_list.png) 0px 0px no-repeat;}
|
||||
.resourcesSelected:hover { background:url(images/resource_icon_list.png) 0px -25px no-repeat;}
|
||||
.resourcesIcon {margin-top:15px; display:block; width:25px; height:20px;}
|
||||
.resourcesType {width:50px; background-color:#ffffff; float:left; list-style:none; position:absolute; border:1px solid #eaeaea; border-radius:5px; top:35px; padding:5px 10px; left:-30px; font-size:12px; color:#888888; display:none;}
|
||||
a.resourcesGrey {font-size:12px; color:#888888;}
|
||||
a.resourcesGrey:hover {font-size:12px; color:#15bccf;}
|
||||
.resourcesBanner ul li:hover ul.resourcesType {display:block;}
|
||||
ul li:hover ul {display:block;}
|
||||
.resourcesUploadBox {float:right; width:103px; height:34px; background-color:#64bdd9; line-height:34px; vertical-align:middle; text-align:center; margin-left:12px;}
|
||||
.uploadIcon {background:url(images/resource_icon_list.png) -35px 10px no-repeat; float:left; display:block; width:30px; height:30px; margin-left:-3px;}
|
||||
a.uploadText {color:#ffffff; font-size:14px;}
|
||||
.resourcesSearchloadBox {border:1px solid #e6e6e6; width:225px; float:right; background-color:#ffffff;}
|
||||
.searchResource {border:none; outline:none; background-color:#ffffff; width:184px; height:32px; padding-left:10px; display:block; float:left;}
|
||||
.searchIcon{width:31px; height:32px; background-color:#ffffff; background:url(images/resource_icon_list.png) -40px -15px no-repeat; display:block; float:left;}
|
||||
.resourcesSearchBanner {height:34px; margin-bottom:10px;}
|
||||
.resourcesListTab {width:730px; height:40px; background-color:#f6f6f6; border-bottom:1px solid #eaeaea; font-size:14px; color:#7a7a7a;}
|
||||
.resourcesListCheckbox {width:40px; height:40px; line-height:40px; text-align:center; vertical-align:middle;}
|
||||
.resourcesCheckbox {padding:0px; margin:0px; margin-top:14px; width:12px; height:12px;}
|
||||
.resourcesListName {width:135px; height:40px; line-height:40px; text-align:left;}
|
||||
.resourcesListSize {width:110px; height:40px; line-height:40px; text-align:center;}
|
||||
.resourcesListType {width:150px; height:40px; line-height:40px; text-align:center;}
|
||||
.resourcesListUploader {width:130px; height:40px; line-height:40px; text-align:center;}
|
||||
.resourcesListTime {width:165px; height:40px; line-height:40px; text-align:center;}
|
||||
.resourcesList {width:730px; height:39px; background-color:#ffffff; border-bottom:1px dashed #eaeaea; color:#9a9a9a; font-size:12px;}
|
||||
a.resourcesBlack {font-size:12px; color:#4c4c4c;}
|
||||
a.resourcesBlack:hover {font-size:12px; color:#000000;}
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
float: left;
|
||||
min-width: 80px;
|
||||
padding: 5px 0;
|
||||
margin: 2px 0 0;
|
||||
font-size: 12px;
|
||||
text-align: left;
|
||||
background-color: #fff;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
||||
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
||||
}
|
||||
.dropdown-menu > li > a {
|
||||
display: block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: normal;
|
||||
line-height: 1.5;
|
||||
color:#616060;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.dropdown-menu > li > a:hover{
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
background-color: #64bdd9;
|
||||
outline:none;
|
||||
}
|
||||
|
||||
/*发送资源弹窗*/
|
||||
/*.resourceShareContainer {width:100%; height:100%; background:#666; filter:alpha(opacity=50); opacity:0.5; -moz-opacity:0.5; position:absolute; left:0; top:0; z-index:-999;}*/
|
||||
.resourceSharePopup {width:300px; height:auto; border:3px solid #15bccf; padding-left:16px; padding-bottom:16px; background-color:#ffffff; position:absolute; top:50%; left:50%; margin-left:-150px; z-index:1000;}
|
||||
.sendText {font-size:16px; color:#15bccf; line-height:16px; padding-top:20px; width:140px; display:inline-block;}
|
||||
.resourcePopupClose {width:20px; height:20px; display:inline-block; float:right;}
|
||||
.resourceClose {background:url(images/resource_icon_list.png) 0px -40px no-repeat; width:20px; height:20px; display:inline-block;}
|
||||
.resourcesSearchBox {border:1px solid #e6e6e6; width:225px; height:25px; background-color:#ffffff; margin-top:12px; margin-bottom:15px;}
|
||||
.searchResourcePopup {border:none; outline:none; background-color:#ffffff; width:184px; height:25px; padding-left:10px; display:inline-block; float:left;}
|
||||
.searchIconPopup{width:31px; height:25px; background-color:#ffffff; background:url(images/resource_icon_list.png) -40px -18px no-repeat; display:inline-block; float:left;}
|
||||
.courseSend {width:260px; height:15px; line-height:15px; margin-bottom:10px;}
|
||||
.courseSendCheckbox {padding:0px; margin:0px; width:12px; height:12px; margin-right:10px; display:inline-block; margin-top:2px;}
|
||||
.sendCourseName {font-size:12px; color:#5f6060;}
|
||||
.courseSendSubmit {width:50px; height:25px; line-height:25px; text-align:center; vertical-align:middle; background-color:#64bdd9; margin-right:25px; float:left;}
|
||||
.courseSendCancel {width:50px; height:25px; line-height:25px; text-align:center; vertical-align:middle; background-color:#c1c1c1; float:left}
|
||||
a.sendSourceText {font-size:14px; color:#ffffff;}
|
||||
|
||||
/*上传资源弹窗*/
|
||||
.resourceUploadPopup {width:400px; height:auto; border:3px solid #15bccf; padding-left:16px; padding-bottom:16px; background-color:#ffffff; position:absolute; top:50%; left:50%; margin-left:-200px; z-index:1000;}
|
||||
.uploadText {font-size:16px; color:#15bccf; line-height:16px; padding-top:20px; width:140px; display:inline-block;}
|
||||
.uploadBoxContainer {height:33px; line-height:33px; margin-top:10px; position:relative;}
|
||||
.uploadBox {width:100px; height:33px; line-height:33px; text-align:center; vertical-align:middle; background-color:#64bdd9; border-radius:3px; float:left; margin-right:12px;}
|
||||
a.uploadIcon {background:url(images/resource_icon_list.png) 8px -60px no-repeat; width:100px; height:33px;}
|
||||
.chooseFile {color:#ffffff; display:block; margin-left:32px;}
|
||||
.uploadResourceIntr {width:250px; height:33px; float:left; line-height:33px; font-size:12px;}
|
||||
.uploadResourceName {width:250px; display:inline-block; line-height:15px; font-size:12px; color:#444444; margin-bottom:2px;}
|
||||
.uploadResourceIntr2 {width:250px; display:inline-block; line-height:15px; font-size:12px; color:#444444;}
|
||||
.uploadType {margin:10px 0; border:1px solid #e6e6e6; width:100px; height:30px; outline:none; font-size:12px; color:#888888;}
|
||||
.uploadKeyword {margin-bottom:10px; outline:none; border:1px solid #e6e6e6; height:30px; width:280px;}
|
||||
|
||||
|
||||
/*新个人主页框架css*/
|
||||
.navContainer {width:100%; margin:0 auto; background-color:#15bccf;}
|
||||
.homepageContentContainer {width:100%; margin:0 auto; background-color:#eaebed;}
|
||||
.homepageContent {width:1000px; background-color:#eaebed; margin:0 auto;}
|
||||
.navHomepage {width:1000px; height:54px; background-color:#15bccf; margin:0 auto;}
|
||||
.navHomepageLogo {width:60px; height:54px; line-height:54px; vertical-align:middle; margin-left:2px; margin-right:40px;}
|
||||
.navHomepageMenu {margin-right:40px;display:inline-block;height:54px; line-height:54px; vertical-align:middle;}
|
||||
.navHomepageSearchBox {width:380px; border:none; outline:none; height:32px; margin-top:11px; background-color:#ffffff;}
|
||||
.navHomepageSearchInput {width:345px; height:32px; outline:none; border:none; float:left; padding-left:5px;; margin:0;}
|
||||
.homepageSearchIcon {width:30px; height:32px; background:url(../images/nav_icon.png) -8px 3px no-repeat; float:left;}
|
||||
a.homepageSearchIcon:hover {background:url(../images/nav_icon.png) -49px 3px no-repeat;}
|
||||
.navHomepageNews {width:30px; display:block; float:right; margin-top:12px; position:relative;}
|
||||
.homepageNewsIcon {background:url(../images/nav_icon.png) -5px -85px no-repeat; width:30px; height:29px; display:block;}
|
||||
.newsActive {width:10px; height:10px; border-radius:50%; border:2px solid #ffffff; background-color:#ff0000; position:absolute; left:17px; top:5px;}
|
||||
.navHomepageProfile {width:65px; display:block; float:right; margin-left:33px;}
|
||||
.homepageProfileMenuIcon {background:url(../images/nav_icon.png) 30px -155px no-repeat; width:65px; height:54px; position:relative; display:inline-block;}
|
||||
.homepageProfileMenuIcon:hover {background:url(../images/nav_icon.png) 30px -122px no-repeat;}
|
||||
.navHomepageProfile ul li ul {display:none;}
|
||||
.navHomepageProfile ul li:hover ul {display:block;}
|
||||
.homepageLeft {width:240px; float:left; margin-right:10px; margin-bottom:10px;}
|
||||
.homepageRight {width:750px; float:left; margin-top:15px; margin-bottom:10px;}
|
||||
.homepagePortraitContainer {width:238px; border:1px solid #dddddd; background-color:#ffffff; margin-top:15px; padding-bottom:15px;}
|
||||
.homepagePortraitImage {width:206px; height:206px; padding:2px; margin:15px 13px 5px 13px;; position:relative; border:1px solid #cbcbcb;}
|
||||
.homepagePortraitImage:hover {border:1px solid #15bccf;}
|
||||
.homepageFollow {background:url(../images/homepage_icon.png) -10px -8px no-repeat; width:20px; height:20px; position:absolute; right:9px; top:9px;}
|
||||
.homepageFollowCancel {background:url(../images/homepage_icon.png) -178px -8px no-repeat; width:20px; height:20px; position:absolute; right:9px; top:9px;}
|
||||
.homepageEditProfile {width:20px; height:20px; border-radius:2px; background-color:#888888; position:absolute; right:9px; bottom:9px; font-size:12px; filter:alpha(opacity=50); -moz-opacity:0.5; opacity: 0.5;}
|
||||
.homepageEditProfileIcon {background:url(../images/homepage_icon.png) -11px -35px no-repeat; width:20px; height:20px; display:block;}
|
||||
.homepageImageName {font-size:16px; color:#484848; margin-left:15px; height:21px; float:left;max-width: 100px;}
|
||||
.homepageImageSexMan {width:20px; height:20px; background:url(../images/homepage_icon.png) -10px -112px no-repeat; float:left;}
|
||||
.homepageImageSexWomen {width: 20px;height: 20px;background: url(../images/homepage_icon.png) -10px -149px no-repeat;float: left;}
|
||||
.homepageSignatureTextarea {width:207px; height:80px; max-width:207px; max-height:80px; border:1px solid #d9d9d9; outline:none; margin:0px 0px 12px 15px;;}
|
||||
.homepageSignature {font-size:12px; color:#888888; margin-left:15px; margin-top:10px; margin-bottom:12px; width:208px;}
|
||||
.homepageImageBlock {margin:0 auto; width:78px; float:left; text-align:center; display:inline-block;}
|
||||
.homepageImageNumber {font-size:12px; color:#484848;}
|
||||
a.homepageImageNumber:hover {color:#15bccf;}
|
||||
.homepageImageText {font-size:12px; color:#888888;}
|
||||
.homepageVerDiv {height:28px; vertical-align:middle; width:1px; float:left; display:inline-block; background-color:#d1d1d1; margin-top:3px;}
|
||||
.homepageLeftMenuContainer {width:238px; border:1px solid #dddddd; border-bottom:none; background-color:#ffffff; margin-top:10px;}
|
||||
.homepageLeftMenuBlock {border-bottom:1px solid #dddddd; height:50px; line-height:50px; vertical-align:middle;}
|
||||
.homepageLeftMenuCourses {font-size:14px; border-bottom:1px solid #dddddd;}
|
||||
.homepageLeftMenuCoursesLine {padding-left:25px; height:38px; line-height:38px; vertical-align:middle;}
|
||||
.homepageLeftMenuCoursesLine:hover {background-color:#b3e0ee;}
|
||||
a.coursesLineGrey {color:#808080; display:block;}
|
||||
a.coursesLineGrey:hover {color:#ffffff;}
|
||||
.homepageLeftMenuMore {height:18px;}
|
||||
.homepageLeftMenuMore:hover {background-color:#b3e0ee;}
|
||||
.homepageLeftMenuMoreIcon {background:url(../images/homepage_icon.png) -74px -240px no-repeat; display:block; height:18px;}
|
||||
.homepageMenuSetting {display:inline-block; margin-left:155px;}
|
||||
a.homepageMenuText {color:#484848; font-size:16px; margin-left:20px;}
|
||||
.homepageLeftLabelContainer {width:238px; border:1px solid #dddddd; background-color:#ffffff; margin-top:10px;}
|
||||
.homepageLabelText {color:#484848; font-size:16px; margin-left:10px; margin-bottom:12px; display:block;}
|
||||
.homepageRightBanner {width:720px; height:34px; margin:0px auto; border-bottom:1px solid #e9e9e9;}
|
||||
.NewsBannerName {font-size:16px; color:#4b4b4b; display:block; background:url(../images/homepage_icon.png) -18px -230px no-repeat; width:150px; float:left; padding-left:15px; margin-top:4px;}
|
||||
.newsType {width:60px; background-color:#ffffff; float:left; list-style:none; position:absolute; border:1px solid #eaeaea; border-radius:5px; top:15px; padding:5px 10px; left:-40px; font-size:12px; color:#888888; display:none; line-height:2; z-index:9999;}
|
||||
.homepageRightBlock {}
|
||||
.homepageNewsList {width:710px; height:49px; line-height:49px; vertical-align:middle; border-bottom:1px dashed #eaeaea; margin-left:10px;}
|
||||
.homepageNewsPortrait {width:40px; display:block; margin-top:7px;}
|
||||
.homepageNewsPublisher {width:80px; max-width:80px; margin-right:10px; font-size:12px; color:#15bccf; display:block; padding-left:5px; overflow:hidden; white-space: nowrap; text-overflow:ellipsis; }
|
||||
.homepageNewsType {width:95px; font-size:12px; color:#888888; display:block;}
|
||||
.homepageNewsContent {width:395px; max-width:395px; margin-right:10px; font-size:12px; color:#4b4b4b; display:block; overflow:hidden; white-space: nowrap; text-overflow:ellipsis; }
|
||||
.homepageNewsTime {width:75px; font-size:12px; color:#888888; display:block; text-align:right;}
|
||||
a.homepageWhite {color:#ffffff;}
|
||||
a.homepageWhite:hover {color:#a1ebff}
|
||||
a.newsGrey {color:#4b4b4b;}
|
||||
a.newsGrey:hover {color:#000000;}
|
||||
a.replyGrey {color:#888888; display:block;}
|
||||
a.replyGrey:hover {color:#4b4b4b;}
|
||||
a.newsBlue {color:#15bccf;}
|
||||
a.newsBlue:hover {color:#0781b4;}
|
||||
a.menuGrey {color:#808080;}
|
||||
a.menuGrey:hover {color:#fe7d68;}
|
||||
|
||||
/*个人主页右部分*/
|
||||
.homepagePostType {width:180px; background-color:#ffffff; float:left; list-style:none; position:absolute; border:1px solid #eaeaea; border-radius:5px; top:15px; padding:5px 10px; left:-170px; font-size:12px; color:#4b4b4b; line-height:2; z-index:9999; display:none;}
|
||||
.homepagePostTypeHomework {width:100px;}
|
||||
.homepagePostTypeProject {width:80px;}
|
||||
a.homepagePostTypeAssignment {background:url(../images/homepage_icon.png) -93px -318px no-repeat; padding-left:23px;}
|
||||
a.homepagePostTypeNotice {background:url(../images/homepage_icon.png) -87px -280px no-repeat; padding-left:23px;}
|
||||
a.homepagePostTypeForum {background:url(../images/homepage_icon.png) -10px -310px no-repeat; padding-left:23px;}
|
||||
a.homepagePostTypeQuiz {background:url(../images/homepage_icon.png) -90px -124px no-repeat; padding-left:23px;}
|
||||
a.homepagePostTypeQuestion {background:url(../images/homepage_icon.png) -10px -273px no-repeat; padding-left:23px;}
|
||||
a.postTypeGrey {color:#888888;}
|
||||
a.postTypeGrey:hover {color:#15bccf;}
|
||||
.homepagePostBrief {width:710px; margin:20px auto 0px auto; position:relative;}
|
||||
.homepagePostPortrait {float:left; width:90px;}
|
||||
.homepagePostDes {float:left; width:600px; margin-left:20px;}
|
||||
.homepagePostTo {font-size:14px; color:#484848; margin-bottom:15px;}
|
||||
.homepagePostTitle {font-size:14px; color:#484848; margin-bottom:15px;}
|
||||
.homepagePostSubmitContainer {height:30px; margin-bottom:15px;}
|
||||
.homepagePostSubmit {font-size:14px; color:#888888; width:80px; height:30px; text-align:center; vertical-align:middle; line-height:30px; border:1px solid #dddddd; background-color:#eaeaea; float:left; margin-right:20px;}
|
||||
.homepagePostSubmit:hover {background-color:#d8d8d8;}
|
||||
.homepagePostIntro {font-size:12px; color:#888888;}
|
||||
.homepagePostDeadline {font-size:12px; color:#888888; float:left; height:30px; line-height:30px; vertical-align:middle;}
|
||||
.homepagePostReply {width:710px; margin:0px auto; background-color:#f1f1f1; margin-top:15px;}
|
||||
.homepagePostReplyBanner {width:708px; height:33px; border:1px solid #e4e4e4; line-height:33px; vertical-align:middle; font-size:12px; color:#888888;}
|
||||
.borderBottomNone {border-bottom:none !important;}
|
||||
.homepagePostReplyBannerCount{width:255px; display:inline-block; margin-left:20px;}
|
||||
.homepagePostReplyBannerTime{width:85px; display:inline-block;}
|
||||
.homepagePostReplyBannerMore{width:330px; display:inline-block; text-align:right;}
|
||||
.homepagePostReplyInputContainer {width:670px; margin:0px auto;}
|
||||
.homepagePostReplyInput {width:663px; height:45px; max-width:663px; max-height:45px; border:1px solid #d9d9d9; outline:none; margin:20px auto 10px auto;}
|
||||
.homepagePostReplyEmotion {background:url(../images/homepage_icon.png) -90px -88px no-repeat; width:70px; height:24px; float:left; padding-left:30px;}
|
||||
.homepagePostReplySubmit {float:right; width:45px; height:24px; text-align:center; line-height:24px; vertical-align:middle; font-size:12px; color:#ffffff; background-color:#15bccf;}
|
||||
.homepagePostReplySubmit:hover {background-color:#329cbd;}
|
||||
a.postReplySubmit {color:#ffffff; display:block;}
|
||||
.homepagePostReplyCancel {float:right; width:45px; height:24px; text-align:center; line-height:24px; vertical-align:middle; font-size:12px; color:#888888; background-color:#cecece; margin-left:8px;}
|
||||
.homepagePostReplyCancel:hover {background-color:#717171;}
|
||||
a.postReplyCancel {color:#888888; display:block;}
|
||||
a.postReplyCancel:hover {color:#ffffff;}
|
||||
.homepagePostReplyInputContainer2 {width:595px; margin:0px auto;}
|
||||
.homepagePostReplyInput2 {width:588px; height:45px; max-width:588px; max-height:45px; border:1px solid #d9d9d9; outline:none; margin:0px auto 10px auto;}
|
||||
.homepagePostReplyContainer {border-bottom:1px solid #e3e3e3; width:670px; margin:0px auto; margin-top:15px; min-height:65px;}
|
||||
.homepagePostSetting {position:absolute; width:20px; height:20px; right:0px; top:0px;}
|
||||
.homepagePostSettingIcon {background:url(../images/homepage_icon.png) -93px -5px no-repeat; width:20px; height:20px;}
|
||||
.homepagePostSettiongText {width:85px; line-height:2; font-size:12px; color:#616060; background-color:#ffffff; border:1px solid #eaeaea; border-radius:3px; position:absolute; left:-68px; top:20px; padding:5px 0px; display:none;}
|
||||
.homepagePostSettingIcon:hover {background:url(../images/homepage_icon.png) -93px -44px no-repeat;}
|
||||
a.postOptionLink {color:#616060; display:block; width:55px; padding:0px 15px;}
|
||||
a.postOptionLink:hover {color:#ffffff; background-color:#15bccf;}
|
||||
.homepagePostReplyPortrait {float:left; width:60px;}
|
||||
.homepagePostReplyDes {float:left; width:595px; margin-left:15px;}
|
||||
.homepagePostReplyPublisher {font-size:12px; color:#484848; margin-bottom:12px;}
|
||||
.homepagePostReplyContent {font-size:12px; color:#484848; margin-bottom:12px;}
|
||||
.homepagePostProjectState {width:42px; height:20px; line-height:20px; border-radius:1px; background-color:#28be6c; color:#ffffff; text-align:center; vertical-align:middle; font-size:12px; display:inline-block; margin-left:5px;}
|
||||
.homepagePostAssignTo {float:left; font-size:14px; color:#15bccf; height:30px; line-height:30px; vertical-align:middle;}
|
||||
.homepagePostFileAtt {height:22px; line-height:22px; vertical-align:middle; background:url(../images/homepage_icon.png) -85px -150px no-repeat; padding-left:35px; font-size:14px; margin-right:25px;}
|
||||
.homepagePostImageAtt {height:22px; line-height:22px; vertical-align:middle; background:url(../images/homepage_icon.png) -86px -195px no-repeat; padding-left:35px; font-size:14px; margin-right:25px;}
|
||||
.postAttSize {color:#888888; font-size:12px;}
|
||||
a.postGrey {color:#484848;}
|
||||
a.postGrey:hover {color:#000000;}
|
||||
a.gz_btn{display:block; background:url(../images/pic_uersall.png) -318px -25px no-repeat; width:53px; height:18px; border:1px solid #cdcdcd; color:#333333; padding:0px 0 0 18px;margin-top: 2px;margin-right: 15px;}
|
||||
a:hover.gz_btn{ color:#ff5722;}
|
||||
|
||||
|
||||
|
||||
/*底部*/
|
||||
#Footer{background-color:#ffffff; margin-bottom:10px; padding-bottom:15px; color:#666666;}
|
||||
.footerAboutContainer {width:auto; border-bottom:1px solid #efefef;}
|
||||
.footerAbout{ width:585px; margin:0 auto;height:35px; line-height:35px; border-bottom:1px solid #efefef; }
|
||||
.languageBox {width:55px; height:20px; margin-left:5px; outline:none; color:#666666; border:1px solid #d9d9d9;}
|
||||
.departments{ width:890px; margin:5px auto 0 auto;height:30px;line-height:30px;}
|
||||
.copyright{ width:375px; margin:0 auto;height:20px;line-height:20px;}
|
||||
a.f_grey {color:#666666;}
|
||||
a.f_grey:hover {color:#000000;}
|
||||
/*意见反馈*/
|
||||
html{ overflow-x:hidden;}
|
||||
.scrollsidebar{ position: fixed; bottom:1px; right:1px; background:none; }
|
||||
.side_content{width:154px; height:auto; overflow:hidden; float:left; }
|
||||
.side_content .side_list {width:154px;overflow:hidden;}
|
||||
.show_btn{ width:0; height:112px; overflow:hidden; float:left; margin-top:190px;cursor:pointer;}
|
||||
.show_btn span { display:none;}
|
||||
.close_btn{width:24px;height:24px;cursor:pointer;}
|
||||
.side_title,.side_bottom,.close_btn,.show_btn {background:url(../images/sidebar_bg.png) no-repeat; }
|
||||
.side_title {height:35px;}
|
||||
.side_bottom { height:8px;}
|
||||
.side_center {font-family:Verdana, Geneva, sans-serif; padding:0px 12px; font-size:12px;}
|
||||
.close_btn { float:right; display:block; width:21px; height:16px; margin:9px 10px 0 0; _margin:16px 5px 0 0;}
|
||||
.close_btn span { display:none;}
|
||||
.side_center .custom_service p { text-align:center; padding:6px 0; margin:0; vertical-align:middle;}
|
||||
.msgserver { margin-top:5px;}
|
||||
.msgserver a { background:url(../images/sidebar_bg.png) no-repeat -119px -112px; padding-left:22px; height:21px; display:block; }
|
||||
.opnionText{box-shadow:none; width:122px; height:180px; border-color: #DFDFDF; background:#fff; color:#999; padding:3px; font-size:12px;overflow:auto; background-attachment:fixed;border-style:solid;}
|
||||
a.opnionButton{ display:block; background:#15bccf; width:130px; height:23px; margin-top:5px; text-align:center; padding-top:3px;}
|
||||
a:hover.opnionButton{background: #0fa9bb; }
|
||||
/* blue skin as the default skin */
|
||||
.side_title {background-position:-195px 0;}
|
||||
.side_center {background:url(../images/blue_line.png) repeat-y center; }
|
||||
.side_bottom {background-position:-195px -50px;}
|
||||
a.close_btn {background-position:-44px 0;}
|
||||
a:hover.close_btn {background-position:-66px 0;}
|
||||
.show_btn {background-position:-119px 0;}
|
||||
.msgserver a {color:#15bccf; }
|
||||
.msgserver a:hover { text-decoration:underline; }
|
||||
|
||||
|
||||
/***** Ajax indicator ******/
|
||||
#ajax-indicator {
|
||||
position: absolute; /* fixed not supported by IE */
|
||||
background-color:#eee;
|
||||
border: 1px solid #bbb;
|
||||
top:35%;
|
||||
left:40%;
|
||||
width:20%;
|
||||
font-weight:bold;
|
||||
text-align:center;
|
||||
padding:0.6em;
|
||||
z-index:100000;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
html>body #ajax-indicator { position: fixed; }
|
||||
|
||||
#ajax-indicator span {
|
||||
background-position: 0% 40%;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(../images/loading.gif);
|
||||
padding-left: 26px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
div.modal {
|
||||
border-radius: 5px;
|
||||
background: #fff;
|
||||
z-index: 50;
|
||||
padding: 4px;
|
||||
}
|
||||
.ui-widget-content {
|
||||
border: 1px solid #ddd;
|
||||
color: #333;
|
||||
}
|
||||
.ui-widget {
|
||||
font-family: Verdana, sans-serif;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.ui-dialog .ui-dialog-content {
|
||||
position: relative;
|
||||
border: 0;
|
||||
padding: .5em 1em;
|
||||
background: none;
|
||||
overflow: auto;
|
||||
zoom: 1;
|
||||
}
|
||||
.ui-widget-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.ui-widget-overlay {
|
||||
background: #666 url(http://forge.trustie.net/stylesheets/jquery/images/xui-bg_diagonals-thick_20_666666_40x40.png.pagespeed.ic.9mfuw_R0z1.png) 50% 50% repeat;
|
||||
opacity: .5;
|
||||
filter: Alpha(Opacity=50);
|
||||
}
|
||||
/***** end Ajax indicator ******/
|
||||
|
||||
/***** Flash & error messages ****/
|
||||
#errorExplanation, div.flash, .nodata, .warning, .conflict {
|
||||
padding: 4px 4px 4px 30px;
|
||||
margin-bottom: 12px;
|
||||
font-size: 1.1em;
|
||||
border: 2px solid;
|
||||
}
|
||||
|
||||
div.flash {margin-top: 8px;}
|
||||
|
||||
div.flash.error, #errorExplanation {
|
||||
background: url(../images/exclamation.png) 8px 50% no-repeat;
|
||||
background-color: #ffe3e3;
|
||||
border-color: #dd0000;
|
||||
color: #880000;
|
||||
}
|
||||
|
||||
div.flash.notice {
|
||||
background: url(../images/true.png) 8px 5px no-repeat;
|
||||
background-color: #dfffdf;
|
||||
border-color: #9fcf9f;
|
||||
color: #005f00;
|
||||
}
|
||||
|
||||
div.flash.warning, .conflict {
|
||||
background: url(../images/warning.png) 8px 5px no-repeat;
|
||||
background-color: #FFEBC1;
|
||||
border-color: #FDBF3B;
|
||||
color: #A6750C;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.nodata, .warning {
|
||||
text-align: center;
|
||||
background-color: #FFEBC1;
|
||||
border-color: #FDBF3B;
|
||||
color: #A6750C;
|
||||
}
|
||||
|
||||
#errorExplanation ul { font-size: 0.9em;}
|
||||
#errorExplanation h2, #errorExplanation p { display: none; }
|
||||
|
||||
.conflict-details {font-size:80%;}
|
||||
/***** end Flash & error messages ****/
|
||||
|
||||
|
||||
/*弹出框*/
|
||||
.black_overlay{display:none;position:fixed;top:0px;left:0px;width:100%;height:100%;background-color:black;z-index:1001;-moz-opacity:0.8;opacity:.80;filter:alpha(opacity=80);}
|
||||
.white_content{display:none;position:fixed;top:15%;left:30%;width:420px;height: auto; margin-bottom:20px;padding:16px;border:3px solid #15bccf;background-color:white;z-index:1002;overflow:auto;}
|
||||
.white_content02{display:none;position:fixed;top:15%;left:30%;width:200px;height: auto; margin-bottom:20px;padding:10px;border:3px solid #15bccf;background-color:white;z-index:1002;overflow:auto;}
|
||||
.newhwork_content{ display:none;position:fixed;top:15%;left:30%;width:600px;height: auto; margin-bottom:20px;padding:16px;border:3px solid #15bccf;background-color:white;z-index:1002;overflow:auto;}
|
||||
.floatbox{ width:420px; border:3px solid #15bccf; background:#fff; padding:5px;}
|
||||
a.box_close{ display:block; float:right; width:16px; height:16px; background:url(../images/img_floatbox.png) 0 0 no-repeat;}
|
||||
a:hover.box_close{background:url(../images/img_floatbox.png) -22px 0 no-repeat;}
|
||||
|
||||
/*个人主页头像*/
|
||||
.white_content_users{display:none;position:fixed;top:45%;left:45%;width:210px;height: auto; margin-bottom:20px;padding:10px;border:3px solid #15bccf;background-color:white;z-index:1002;overflow:auto;}
|
||||
a.box_close{background:url(../images/img_floatbox.png) -22px 0 no-repeat;}
|
||||
.box_h3{ color:#15bccf; font-size:16px;}
|
||||
.uppicBox{ width:265px; height:265px; background:#f2f2f5; float:left; color:#666; text-align:center;}
|
||||
.showpicBox{width:133px; height:250px; background:#f2f2f5; float:left; margin-left:20px; text-align:center; padding-top:15px; color:#666;}
|
||||
.mr15{ margin-right:15px;}
|
||||
.uppic_btn{border:none; width:150px; background:none; margin-bottom:5px; color:#666; margin-top:105px;}
|
|
@ -0,0 +1,68 @@
|
|||
/* 2015-06-26 */
|
||||
.topbar_info02{ margin:5px 10px;width:480px; }
|
||||
.topbar_info02 p{color: #7f7f7f;}
|
||||
.search{ margin-top:8px; float:right; margin-right:5px;}
|
||||
/*信息*/
|
||||
.project_info{ background:#fff; padding:10px; padding-right:0px;width:222px; padding-right:8px; margin-bottom:10px;}
|
||||
.pr_info_id{ width:137px; color:#5a5a5a; font-size:14px; margin-top:5px;}
|
||||
.pr_info_logo{ border:1px solid #eaeaea; width:60px; height:60px; padding:1px;}
|
||||
.pr_info_logo:hover{ border:1px solid #64bdd9; }
|
||||
.pr_info_join{}
|
||||
a.pr_join_a{ color:#fff; display:block; padding:0 5px 0 3px; padding-top:2px; height:20px; margin-right:5px; float:left; text-align:center; background-color:#64bdd9; float:left; }
|
||||
a:hover.pr_join_a{ background:#41a8c8;}
|
||||
.pr_join_span{color: #fff; display:block; padding:0 5px; padding-top:2px; height:20px; margin-right:5px; float:left; text-align:center; background: #CCC;}
|
||||
.pr_setting{ display:block; background:url(../images/leftside.png) -1px 0 no-repeat; width:11px; height:11px; margin-top:3px; float:left; }
|
||||
.pr_copy{ display:block; background:url(../images/leftside.png) -1px -23px no-repeat; width:11px; height:11px; margin-top:3px; float:left; }
|
||||
.pr_close{ display:block; background:url(../images/leftside.png) -1px -49px no-repeat; width:11px; height:11px; margin-top:3px; float:left; }
|
||||
.pr_add{display:block; background:url(../images/leftside.png) 0px -71px no-repeat; width:11px; height:11px; margin-top:3px; float:left; }
|
||||
.pr_arrow{display:block; background:url(../images/leftside.png) 0px -90px no-repeat; width:11px; height:11px; margin-top:3px; float:left; }
|
||||
.pr_info_name{ color:#3e4040; font-size:14px; line-height:1.5;}
|
||||
.pr_info_name:hover{ color:#3ca5c6;}
|
||||
.pr_info_score{ font-size:14px; color:#3e4040; }
|
||||
.pr_info_score a{ color:#ff7143;}
|
||||
.pr_info_score a:hover{ color:#64bdd9;}
|
||||
|
||||
.img_private{ background:url(../images/img_project.png) 0 0 no-repeat; width:33px; height:16px; color:#fff; font-size:12px; padding-left:7px; }
|
||||
.info_foot_num{ color:#3ca5c6; }
|
||||
.pr_info_foot{ color:#7f7f7f; margin-top:5px; }
|
||||
.info_foot_num:hover{ color:#2390b2;}
|
||||
.info_box{background:#fff; padding:10px;width:220px; }
|
||||
.info_box ul li{ font-size:12px; color: #3e4040; line-height:1.7;}
|
||||
|
||||
/*左侧导航*/
|
||||
.subNavBox{width:240px; background:#fff;margin:10px 10px 0 0;}
|
||||
.subNav{border-bottom:solid 1px #e5e3da;cursor:pointer;font-weight:bold;font-size:14px;color:#3ca5c6; height:26px;padding-left:10px;background-color:#fff; padding-top:2px;}
|
||||
.subNav_jiantou{background:url(../images/jiantou1.jpg) no-repeat;background-position:95% 50%; background-color:#fff;}
|
||||
.subNav_jiantou:hover{color:#0781b4; }
|
||||
.currentDd{color:#0781b4;}
|
||||
.currentDt{background-color:#fff;}
|
||||
.navContent{display: none;border-bottom:solid 1px #e5e3da; }
|
||||
.navContent li a{display:block;width:240px;heigh:28px;text-align:center;font-size:12px;line-height:28px;color:#333}
|
||||
.navContent li a:hover{color:#fff;background-color:#b3e0ee}
|
||||
a.subnav_num{ font-weight:normal; color:#ff7143; font-size:12px;}
|
||||
a.subnav_green{ background:#28be6c; color:#fff; font-size:12px; font-weight:normal;height:18px; padding:0px 5px; padding-top:2px; display:block; margin-top:2px; margin-bottom:5px; float:right; margin-right:5px;}
|
||||
a:hover.subnav_green{ background:#14ad5a;}
|
||||
|
||||
|
||||
/*简介*/
|
||||
.project_intro{ width:220px; padding:10px; background:#fff; margin-top:10px; padding-top:5px; color:#6d6d6d; line-height:1.9;}
|
||||
.course_description{max-height: 112px;overflow:hidden; word-break: break-all;word-wrap: break-word;}
|
||||
.course_description_none{max-height: none;}
|
||||
.lg-foot{ border:1px solid #e8eef2; color: #929598; text-align:center; width:220px; height:23px; cursor:pointer;}
|
||||
.lg-foot:hover{ color:#787b7e; border:1px solid #d4d4d4;}
|
||||
/****标签(和资源库的tag样式一致)***/
|
||||
.project_Label{ width:220px; padding:10px; background:#fff; margin-top:10px; padding-top:5px; margin-bottom:10px;}
|
||||
.project_Label_New {width:218px; padding-left:10px; background:#fff; margin-top:15px; margin-bottom:10px;}
|
||||
a.yellowBtn{ display:inline-block;color:#0d90c3; height:22px;}
|
||||
.submit{height:21px;border:0; cursor:pointer; background:url(images/btn.png) no-repeat 0 0;width:42px; margin-top:2px; margin-left:3px; }
|
||||
.isTxt{background:#fbfbfb url(images/inputBg.png) repeat-x left top;height:22px;line-height:22px;border:1px solid #c1c1c1;padding:0 5px;color:#666666;}
|
||||
.re_tag{ width: auto; padding:0 5px; padding-top:2px; height:20px; border:1px solid #f8df8c; background:#fffce6; margin-right:5px; }
|
||||
.re_tag a{ color:#0d90c3;}
|
||||
.tag_h{ }
|
||||
.tag_h span,.tag_h a{ margin-bottom:5px;}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue