Merge branch 'develop' of 10.0.47.245:/home/trustie2 into develop

This commit is contained in:
fanqiang 2013-08-08 22:27:05 +08:00
commit a31f817e55
86 changed files with 1642 additions and 35 deletions

View File

@ -7,6 +7,7 @@ gem "coderay", "~> 1.0.6"
gem "fastercsv", "~> 1.5.0", :platforms => [:mri_18, :mingw_18, :jruby] gem "fastercsv", "~> 1.5.0", :platforms => [:mri_18, :mingw_18, :jruby]
gem "builder", "3.0.0" gem "builder", "3.0.0"
gem 'acts-as-taggable-on' gem 'acts-as-taggable-on'
# Optional gem for LDAP authentication # Optional gem for LDAP authentication
group :ldap do group :ldap do
gem "net-ldap", "~> 0.3.1" gem "net-ldap", "~> 0.3.1"

View File

@ -98,6 +98,8 @@ GEM
rmagick (2.13.2) rmagick (2.13.2)
ruby-openid (2.1.8) ruby-openid (2.1.8)
rubyzip (0.9.9) rubyzip (0.9.9)
jquery-rails
rails
selenium-webdriver (2.33.0) selenium-webdriver (2.33.0)
childprocess (>= 0.2.5) childprocess (>= 0.2.5)
multi_json (~> 1.0) multi_json (~> 1.0)

View File

@ -0,0 +1,2 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -0,0 +1,225 @@
/************************************************************************
*************************************************************************
@Name : jRating - jQuery Plugin
@Revison : 3.0
@Date : 28/01/2013
@Author: ALPIXEL - (www.myjqueryplugins.com - www.alpixel.fr)
@License : Open Source - MIT License : http://www.opensource.org/licenses/mit-license.php
**************************************************************************
*************************************************************************/
(function($) {
$.fn.jRating = function(op) {
var defaults = {
/** String vars **/
bigStarsPath : '<%= image_path "seems_rateable/stars.png" %>', // path of the icon stars.png
smallStarsPath : '<%= image_path "seems_rateable/small.png" %>', // path of the icon small.png
path : '<%= SeemsRateable::Engine.routes.url_helpers.ratings_path %>',
type : 'big', // can be set to 'small' or 'big'
/** Boolean vars **/
step:false, // if true, mouseover binded star by star,
isDisabled:false,
showRateInfo: false,
canRateAgain : false,
/** Integer vars **/
length:5, // number of star to display
decimalLength : 0, // number of decimals.. Max 3, but you can complete the function 'getNote'
rateMax : 20, // maximal rate - integer from 0 to 9999 (or more)
rateInfosX : -45, // relative position in X axis of the info box when mouseover
rateInfosY : 5, // relative position in Y axis of the info box when mouseover
nbRates : 1,
/** Functions **/
onSuccess : null,
onError : null
};
if(this.length>0)
return this.each(function() {
/*vars*/
var opts = $.extend(defaults, op),
newWidth = 0,
starWidth = 0,
starHeight = 0,
bgPath = '',
hasRated = false,
globalWidth = 0,
nbOfRates = opts.nbRates;
if($(this).hasClass('jDisabled') || opts.isDisabled)
var jDisabled = true;
else
var jDisabled = false;
getStarWidth();
$(this).height(starHeight);
var average = parseFloat($(this).attr('data-average')), // get the average of all rates
idBox = parseInt($(this).attr('data-id')), // get the id of the box
kls = $(this).attr('data-kls'),
dimension = $(this).attr('data-dimension'),
widthRatingContainer = starWidth*opts.length, // Width of the Container
widthColor = average/opts.rateMax*widthRatingContainer, // Width of the color Container
quotient =
$('<div>',
{
'class' : 'jRatingColor',
css:{
width:widthColor
}
}).appendTo($(this)),
average =
$('<div>',
{
'class' : 'jRatingAverage',
css:{
width:0,
top:- starHeight
}
}).appendTo($(this)),
jstar =
$('<div>',
{
'class' : 'jStar',
css:{
width:widthRatingContainer,
height:starHeight,
top:- (starHeight*2),
background: 'url('+bgPath+') repeat-x'
}
}).appendTo($(this));
$(this).css({width: widthRatingContainer,overflow:'hidden',zIndex:1,position:'relative'});
if(!jDisabled)
$(this).unbind().bind({
mouseenter : function(e){
var realOffsetLeft = findRealLeft(this);
var relativeX = e.pageX - realOffsetLeft;
if (opts.showRateInfo)
var tooltip =
$('<p>',{
'class' : 'jRatingInfos',
html : getNote(relativeX)+' <span class="maxRate">/ '+opts.rateMax+'</span>',
css : {
top: (e.pageY + opts.rateInfosY),
left: (e.pageX + opts.rateInfosX)
}
}).appendTo('body').show();
},
mouseover : function(e){
$(this).css('cursor','pointer');
},
mouseout : function(){
$(this).css('cursor','default');
if(hasRated) average.width(globalWidth);
else average.width(0);
},
mousemove : function(e){
var realOffsetLeft = findRealLeft(this);
var relativeX = e.pageX - realOffsetLeft;
if(opts.step) newWidth = Math.floor(relativeX/starWidth)*starWidth + starWidth;
else newWidth = relativeX;
average.width(newWidth);
if (opts.showRateInfo)
$("p.jRatingInfos")
.css({
left: (e.pageX + opts.rateInfosX)
})
.html(getNote(newWidth) +' <span class="maxRate">/ '+opts.rateMax+'</span>');
},
mouseleave : function(){
$("p.jRatingInfos").remove();
},
click : function(e){
var element = this;
/*set vars*/
hasRated = true;
globalWidth = newWidth;
nbOfRates--;
if(!opts.canRateAgain || parseInt(nbOfRates) <= 0) $(this).unbind().css('cursor','default').addClass('jDisabled');
if (opts.showRateInfo) $("p.jRatingInfos").fadeOut('fast',function(){$(this).remove();});
e.preventDefault();
var rate = getNote(newWidth);
average.width(newWidth);
$.post(defaults.path,
{
idBox : idBox,
rate : rate,
kls : kls,
dimension : dimension
/** action : 'rating' **/
},
function(data) {
if(!data.error)
{
/** Here you can display an alert box,
or use the jNotify Plugin :) http://www.myqjqueryplugins.com/jNotify
exemple : */
if(opts.onSuccess) opts.onSuccess( element, rate );
}
else
{
/** Here you can display an alert box,
or use the jNotify Plugin :) http://www.myqjqueryplugins.com/jNotify
exemple : */
if(opts.onError) opts.onError( element, rate );
}
},
'json'
);
}
});
function getNote(relativeX) {
var noteBrut = parseFloat((relativeX*100/widthRatingContainer)*opts.rateMax/100);
switch(opts.decimalLength) {
case 1 :
var note = Math.round(noteBrut*10)/10;
break;
case 2 :
var note = Math.round(noteBrut*100)/100;
break;
case 3 :
var note = Math.round(noteBrut*1000)/1000;
break;
default :
var note = Math.round(noteBrut*1)/1;
}
return note;
};
function getStarWidth(){
switch(opts.type) {
case 'small' :
starWidth = 12; // width of the picture small.png
starHeight = 10; // height of the picture small.png
bgPath = opts.smallStarsPath;
break;
default :
starWidth = 23; // width of the picture stars.png
starHeight = 20; // height of the picture stars.png
bgPath = opts.bigStarsPath;
}
};
function findRealLeft(obj) {
if( !obj ) return 0;
return obj.offsetLeft + findRealLeft( obj.offsetParent );
};
});
}
})(jQuery);

View File

@ -0,0 +1,25 @@
$(document).ready(function(){
$(".rateable").jRating({
//default options displayed below ->
rateMax: 5, //Maximal rate
length : 5, //Number of stars
//decimalLength : 0, //Number of decimals in the rate
//type : 'big', //Big or small
//step : true, //If set to true, filling of the stars is done star by star (step by step).
//isDisabled: false, //Set true to display static rating
//showRateInfo:false, //Rate info panel, set true to display
//rateInfosX : 45, //In pixel - Absolute left position of the information box during mousemove.
//rateInfosY : 5, //In pixel - Absolute top position of the information box during mousemove.
path : '<%= SeemsRateable::Engine.routes.url_helpers.ratings_path %>',
onSuccess : function(element, rate){
//something like ->
//alert('success');
$('<span class="text-success"><small style="display:inline-block;">Thanks for rating!</small></span>').insertAfter(element)
},
onError : function(element, rate) {
$('<span class="text-error"><small style="display:inline-block;">You have already rated!</small></span>').insertAfter(element)
}
});
});

View File

@ -0,0 +1,4 @@
/*
Place all the styles related to the matching controller here.
They will automatically be included in application.css.
*/

View File

@ -95,6 +95,9 @@ class ApplicationController < ActionController::Base
# Returns the current user or nil if no user is logged in # Returns the current user or nil if no user is logged in
# and starts a session if needed # and starts a session if needed
def current_user
find_current_user
end
def find_current_user def find_current_user
user = nil user = nil
unless api_request? unless api_request?

View File

@ -0,0 +1,68 @@
class PraiseTreadController < ApplicationController
def praise_plus
@obj = nil
if request.get?
@obj = params[:obj] # 传的是对象最后变成id了
#首先创建或更新praise_tread 表
@pt = PraiseTread.find_by_user_id_and_praise_tread_object_id(User.current.id,@obj)
@pt = @pt.nil? ? PraiseTread.new : @pt
@pt.user_id = User.current.id
@pt.praise_tread_object_id = @obj.to_i
@pt.praise_tread_object_type = User.find_by_id(@obj).class.name.underscore
@pt.praise_or_tread = 1
@pt.save
#再创建或更新praise_tread_cache表
@ptc = PraiseTreadCache.find_by_object_id(@obj)
@ptc = @ptc.nil? ? PraiseTreadCache.new : @ptc
@ptc.object_id = @obj.to_i
@ptc.object_type = User.find_by_id(@obj).class.name.underscore
@ptc.plus(1)
@ptc.save
end
@obj = User.find_by_id(@obj)
respond_to do |format|
format.html
format.js
end
end
def praise_minus
@obj = nil
if request.get?
@obj = params[:obj] # 传的是对象最后变成id了
#首先更新praise_tread 表 删除关注记录
@pt = PraiseTread.find_by_user_id_and_praise_tread_object_id_and_praise_tread_object_type(User.current.id,@obj,"user")
@pt.delete
#再更新praise_tread_cache表 使相应的记录减1 当为0时删除
@ptc = PraiseTreadCache.find_by_object_id(@obj)
@ptc.minus(1)
if @ptc.praise_num == 0
@ptc.delete
end
end
@obj = User.find_by_id(@obj)
respond_to do |format|
format.html
format.js
end
end
def tread_plus
end
def tread_minus
respond_to do |format|
format.html
format.js
end
end
end

View File

@ -2,9 +2,7 @@
class TagsController < ApplicationController class TagsController < ApplicationController
before_filter :require_admin,:only => :show before_filter :require_admin,:only => :show
#Added by nie
#before_filter :require_login,:only => :add_tag
#end
include ProjectsHelper include ProjectsHelper
include IssuesHelper include IssuesHelper
include UsersHelper include UsersHelper
@ -78,5 +76,10 @@ class TagsController < ApplicationController
def show def show
end end
def show_all
@tags = ActsAsTaggableOn::Tag.find(:all)
@tags = @tags.to_a
end
end end

View File

@ -17,9 +17,13 @@
class UsersController < ApplicationController class UsersController < ApplicationController
layout 'base_users' layout 'base_users'
before_filter :require_admin, :except => [:show, :index,:tag_save, :user_projects, :user_newfeedback, :user_comments, :watch_bids, :info] before_filter :require_admin, :except => [:show, :index,:tag_save, :user_projects, :user_newfeedback, :user_comments, :watch_bids, :info, :user_watchlist, :user_fanslist]
before_filter :find_user, :only => [:show, :edit, :update, :destroy, :edit_membership, :destroy_membership, :user_activities, :user_projects, :user_newfeedback, :user_comments, :watch_bids, :info] before_filter :find_user, :only => [:user_fanslist, :user_watchlist, :show, :edit, :update, :destroy, :edit_membership, :destroy_membership, :user_activities, :user_projects, :user_newfeedback, :user_comments, :watch_bids, :info]
accept_api_auth :index, :show, :create, :update, :destroy accept_api_auth :index, :show, :create, :update, :destroy
#william
before_filter :require_login,:only=>[:tag_save]
helper :sort helper :sort
include SortHelper include SortHelper
@ -27,7 +31,7 @@ class UsersController < ApplicationController
include CustomFieldsHelper include CustomFieldsHelper
include AvatarHelper include AvatarHelper
# added by liuping 关注 # added by liuping 关注
helper :watchers helper :watchers
helper :activities helper :activities
@ -379,7 +383,16 @@ class UsersController < ApplicationController
respond_to do |format| respond_to do |format|
format.html format.html
format.js format.js
end end
end
###add by huang
def user_watchlist
end
###add by huang
def user_fanslist
end end
private private

View File

@ -26,12 +26,9 @@ module ApplicationHelper
include GravatarHelper::PublicMethods include GravatarHelper::PublicMethods
include Redmine::Pagination::Helper include Redmine::Pagination::Helper
include AvatarHelper include AvatarHelper
## added by william
### added by william include PraiseTreadHelper
include ActsAsTaggableOn::TagsHelper
# include WatchersHelper
extend Forwardable extend Forwardable
def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
@ -1309,4 +1306,14 @@ module ApplicationHelper
html.html_safe html.html_safe
end end
#end #end
# add by huang
def show_watcher_list(user)
html = ''
for user in User.watched_by(user.id)
html << (link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :class => "avatar", :title => "#{user.name}")
end
html.html_safe
end
# end
end end

View File

@ -377,7 +377,7 @@ module IssuesHelper
# this method is used to get all projects that tagged one tag # this method is used to get all projects that tagged one tag
# added by william # added by william
def get_issues_by_tag(tag_name) def get_issues_by_tag(tag_name)
Issue.tagged_with(tag_name) Issue.tagged_with(tag_name).by_join_date
end end
end end

View File

@ -0,0 +1,23 @@
module PraiseTreadHelper
#added by william
def is_praise_or_tread(object,user_id)
@obj_type = object.class.name.underscore
@obj_id = object.id
@is_praise = PraiseTread.find_by_sql("select * from praise_treads where user_id=#{user_id} and " +
"praise_tread_object_type='#{@obj_type}' and praise_tread_object_id=#{@obj_id} ")
return @is_praise
end
#end
def get_praise_num(object)
@obj_type = object.class.name.underscore
@obj_id = object.id
@record = PraiseTreadCache.find_by_object_id_and_object_type(@obj_id,@obj_type)
if @record
return @record.praise_num
else
return 0
end
end
end

View File

@ -85,7 +85,7 @@ module ProjectsHelper
# this method is used to get all projects that tagged one tag # this method is used to get all projects that tagged one tag
# added by william # added by william
def get_projects_by_tag(tag_name) def get_projects_by_tag(tag_name)
Project.tagged_with(tag_name) Project.tagged_with(tag_name).by_join_date
end end
end end

View File

@ -58,7 +58,7 @@ module UsersHelper
# this method is used to get all projects that tagged one tag # this method is used to get all projects that tagged one tag
# added by william # added by william
def get_users_by_tag(tag_name) def get_users_by_tag(tag_name)
User.tagged_with(tag_name) User.tagged_with(tag_name).by_join_date
end end
end end

View File

@ -60,7 +60,8 @@ class Issue < ActiveRecord::Base
###########################added by william ###########################added by william
acts_as_taggable acts_as_taggable
scope :by_join_date, order("created_at DESC")
##end
DONE_RATIO_OPTIONS = %w(issue_field issue_status) DONE_RATIO_OPTIONS = %w(issue_field issue_status)
attr_reader :current_journal attr_reader :current_journal

View File

@ -0,0 +1,4 @@
class PraiseTread < ActiveRecord::Base
attr_accessible :user_id,:praise_tread_object_id,:praise_tread_object_type,:praise_or_tread
end

View File

@ -0,0 +1,11 @@
class PraiseTreadCache < ActiveRecord::Base
attr_accessible :object_id,:object_type,:praise_num,:tread_num
def plus(num)
self.update_attribute(:praise_num, self.praise_num.to_i + num)
end
def minus(num)
self.update_attribute(:praise_num, self.praise_num.to_i - num)
end
end

View File

@ -78,7 +78,7 @@ class Project < ActiveRecord::Base
:author => nil :author => nil
############################added by william ############################added by william
acts_as_taggable acts_as_taggable
scope :by_join_date, order("created_at DESC")
###################added by liuping 关注 ###################added by liuping 关注
acts_as_watchable acts_as_watchable

View File

@ -102,8 +102,8 @@ class User < Principal
acts_as_customizable acts_as_customizable
############################added by william ############################added by william
acts_as_taggable acts_as_taggable
scope :by_join_date, order("created_at DESC")
############################# added by liuping 关注 ############################# added by liuping 关注
acts_as_watchable acts_as_watchable

View File

@ -4,7 +4,7 @@
<!-- 1代表是user类型 2代表是project类型 3代表是issue类型 --> <!-- 1代表是user类型 2代表是project类型 3代表是issue类型 -->
<!-- 3 代表的是issue 当是issue是 处理方式与前2个对象不同 --> <!-- 3 代表的是issue 当是issue是 处理方式与前2个对象不同 -->
<% if object_flag == '3' %> <% if object_flag == '3' %>
<%= toggle_link (image_tag "/images/sidebar/add.png"), 'put-tag-form-issue', {:focus => 'name'} %> <%= toggle_link (image_tag "/images/sidebar/add.png"), 'put-tag-form-issue', {:focus => 'name-issue'} %>
<div id="tags_show_issue"> <div id="tags_show_issue">
<%= render :partial => "layouts/tag_name",:locals => {:obj => obj,:non_list_all => false ,:object_flag => object_flag} %> <%= render :partial => "layouts/tag_name",:locals => {:obj => obj,:non_list_all => false ,:object_flag => object_flag} %>
</div> </div>

View File

@ -30,7 +30,7 @@
<div class="inf_user_image"> <div class="inf_user_image">
<table> <table>
<tr> <tr>
<td><%= link_to image_tag(avatar_image(@project), :class => 'avatar') %></td> <td><%= link_to image_tag(url_to_avatar(@project), :class => 'avatar') %></td>
<td align="center"> <td align="center">
<div class="info_font"> <div class="info_font">
<%= textilizable @project.name %> <%= textilizable @project.name %>
@ -42,6 +42,7 @@
</div></td> </div></td>
</tr> </tr>
</table> </table>
<!--tags--> <!--tags-->
<div class="tags"> <div class="tags">
<!-- added by william -for tag --> <!-- added by william -for tag -->

View File

@ -10,6 +10,7 @@
<%= stylesheet_link_tag 'jquery/jquery-ui-1.9.2', 'application', :media => 'all' %> <%= stylesheet_link_tag 'jquery/jquery-ui-1.9.2', 'application', :media => 'all' %>
<%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %> <%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %>
<%= javascript_heads %> <%= javascript_heads %>
<%= heads_for_theme %> <%= heads_for_theme %>
<%= call_hook :view_layouts_base_html_head %> <%= call_hook :view_layouts_base_html_head %>
<!-- page specific tags --> <!-- page specific tags -->
@ -44,10 +45,15 @@
</table></td> </table></td>
</tr> </tr>
</table> </table>
<div id="praise_tread">
<%= render :partial => "/praise_tread/praise_tread",:locals => {:obj => @user,:show_flag => false,:user_id => User.current.id}%>
</div>
<div> <div>
<%= l(:label_user_watcher) %> (<strong class="font_small_watch"><%= User.watched_by(@user.id).count %></strong>) &nbsp; <%= l(:label_user_watcher) %> (<strong class="font_small_watch"><%= User.watched_by(@user.id).count %></strong>) &nbsp;
<%= l(:label_user_fans) %> (<strong class="font_small_watch"><%= @user.watcher_users.count %></strong>) <%= l(:label_user_fans) %> (<strong class="font_small_watch"><%= @user.watcher_users.count %></strong>)
</div> </div>
</div> </div>
<div class="user_underline"></div> <div class="user_underline"></div>
<!--info--> <!--info-->
@ -70,7 +76,7 @@
<div class="user_fans"> <div class="user_fans">
<div class="font_title_left"> <div class="font_title_left">
<strong><%= l(:label_user_watcher) %>(<%= link_to User.watched_by(@user.id).count %>)</strong> <strong><%= l(:label_user_watcher) %>(<%= link_to User.watched_by(@user.id).count, :controller=>"users",:action=>"user_watchlist" %>)</strong>
</div> </div>
<div class="left_wf"> <div class="left_wf">
@ -87,7 +93,7 @@
<!--fans--> <!--fans-->
<div class="user_fans"> <div class="user_fans">
<div class="font_title_left"> <div class="font_title_left">
<strong><%= l(:label_user_fans) %>(<%= link_to @user.watcher_users.count %>)</strong> <strong><%= l(:label_user_fans) %>(<%= link_to @user.watcher_users.count,:controller=>"users",:action=>"user_fanslist" %>)</strong>
</div> </div>
<div class="left_wf"> <div class="left_wf">
<table> <table>

View File

View File

@ -0,0 +1,17 @@
<div id="praise">
<% if is_praise_or_tread(obj,user_id).size > 0 %>
<%= image_tag("/images/praise.png") %>
<%= link_to "取消贊",:controller=>"praise_tread",:action=>"praise_minus",:remote=>true,:obj => obj %>
(<%= get_praise_num(obj)%>)
<% else %>
<%= image_tag("/images/tread.png") %>
<%= link_to "贊",:controller=>"praise_tread",:action=>"praise_plus",:remote=>true,:obj => obj %>
(<%= get_praise_num(obj)%>)
<% end %>
</div>
<% if show_flag %>
<div id="tread">
<%= link_to image_tag("/images/tread.png"),:controller=>"praise_tread",
:action=>"tread_minus",:remote=>true,:obj => obj %>踩
</div>
<% end %>

View File

View File

@ -0,0 +1,3 @@
$('#praise_tread').html('<%= j(
render :partial => "/praise_tread/praise_tread",:locals => {:obj => @obj,:show_flag => false,:user_id => User.current.id}
)%>');

View File

@ -0,0 +1,3 @@
$('#praise_tread').html('<%= j(
render :partial => "/praise_tread/praise_tread",:locals => {:obj => @obj,:show_flag => false,:user_id => User.current.id}
)%>');

View File

@ -0,0 +1,18 @@
<style type="text/css">
#tag {
background-color: #dbe4ee;
border-radius: 5px 5px 5px 5px;
color: #3a587d !important;
padding: 0px 4px;
margin: 3px;
display: inline-block;
font-size: 11px;
text-decoration: none;
cursor: pointer;
}
</style>
<% for tag in @tags %>
<span id="tag">
<%= tag.name %>
</span>
<% end %>

View File

@ -0,0 +1,32 @@
<!--add by huang-->
<h3><%= l(:label_user_fans)%></h3>
<div class="inf_user_image">
<% for user in @user.watcher_users %>
<ul class="list_watch"><li>
<table width="660px" border="0" align="center">
<tr>
<td colspan="2" valign="top" width="50" ><%= link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :title => "#{user.name}" %></td>
<td><table width="580px" border="0">
<tr>
<td colspan="2" valign="top"><strong><%= content_tag "div", link_to_user(user), :class => "nomargin avatar_name" %>
</td>
</tr>
<tr>
<td colspan="2" width="580px" ><p class="font_description">
<% unless user.memberships.empty? %>
<%= l(:label_contribute_to, :project_count => "#{user.memberships.count}") %>
<% for member in user.memberships %>
<%= link_to_project(member.project) %><%= (user.memberships.last == member) ? '' : '' %>
<% end %>
<% end %>
</p></td>
</tr>
<tr>
<td width="200" align="right" class="font_lighter"><%= l(:label_user_joinin) %><%= format_date(@user.created_on) %>
</td>
</tr>
</table></td>
</tr>
</table></li></ul>
<% end %>
</div>

View File

@ -10,7 +10,8 @@
<td> <td>
<table width="580" border="0"> <table width="580" border="0">
<tr> <tr>
<td colspan="2" valign="top"><strong> <%= link_to_user(membership.user) if membership.respond_to?(:user) %></strong><a class="font_lighter"> 创建了</a> <%= link_to_project(membership.project) %></td> <td colspan="2" valign="top"><strong> <%= link_to_user(membership.user) if membership.respond_to?(:user) %></strong>
<a class="font_lighter"> 创建了</a> <%= link_to_project(membership.project) %></td>
</tr> </tr>
<tr> <tr>
<td colspan="2" width="580" > <td colspan="2" width="580" >

View File

@ -0,0 +1,32 @@
<!--add by huang-->
<h3><%= l(:label_user_watcher)%></h3>
<div class="inf_user_image">
<% for user in User.watched_by(@user.id) %>
<ul class="list_watch"><li>
<table width="660px" border="0" align="center">
<tr>
<td colspan="2" valign="top" width="50" ><%= link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :title => "#{user.name}" %></td>
<td><table width="580px" border="0">
<tr>
<td colspan="2" valign="top"><strong><%= content_tag "div", link_to_user(user), :class => "nomargin avatar_name" %>
</td>
</tr>
<tr>
<td colspan="2" width="580px" ><p class="font_description">
<% unless user.memberships.empty? %>
<%= l(:label_contribute_to, :project_count => "#{user.memberships.count}") %>
<% for member in user.memberships %>
<%= link_to_project(member.project) %><%= (user.memberships.last == member) ? '' : '' %>
<% end %>
<% end %>
</p></td>
</tr>
<tr>
<td width="200" align="right" class="font_lighter"><%= l(:label_user_joinin) %><%= format_date(@user.created_on) %>
</td>
</tr>
</table></td>
</tr>
</table></li></ul>
<% end %>
</div>

View File

@ -137,7 +137,7 @@
<p class="font_welcome2">项目需求</p> <p class="font_welcome2">项目需求</p>
<p class="font_lighter">添加描述添加描述添加描述添加描述...</p> <p class="font_lighter">添加描述添加描述添加描述添加描述...</p>
</td><td align="center"> </td><td align="center">
<p class="font_welcome2">发现开源</p> <p class="font_welcome2">项目需求</p>
<p class="font_lighter">添加描述添加描述添加描述添加描述...</p> <p class="font_lighter">添加描述添加描述添加描述添加描述...</p>
</td></tr> </td></tr>
</table> </table>

View File

@ -0,0 +1,4 @@
#SeemsRateable engine Initializer
#Configure owner class of the given ratings
SeemsRateable::Engine.config.owner_class = "User"

View File

@ -547,7 +547,7 @@ en:
label_assigned_to_me_issues: Issues assigned to me label_assigned_to_me_issues: Issues assigned to me
label_last_login: Last connection label_last_login: Last connection
label_registered_on: Registered on label_registered_on: Registered on
label_activity: Activity label_activity: Activities
label_overall_activity: Overall activity label_overall_activity: Overall activity
label_user_activity: "%{value}'s activity" label_user_activity: "%{value}'s activity"
label_new: New label_new: New
@ -588,7 +588,7 @@ en:
label_news_added: News added label_news_added: News added
label_news_comment_added: Comment added to a news label_news_comment_added: Comment added to a news
label_settings: Settings label_settings: Settings
label_overview: Overview label_overview: Activities
label_version: Version label_version: Version
label_version_new: New version label_version_new: New version
label_version_plural: Versions label_version_plural: Versions
@ -1082,3 +1082,90 @@ en:
description_date_from: Enter start date description_date_from: Enter start date
description_date_to: Enter end date description_date_to: Enter end date
text_repository_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed.' text_repository_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed.'
#modify by mkz
#by young
label_requirement: Requirement
label_requirement_focus: Requirement focus
label_developer: Developer
label_investor: Investor
label_theme: Theme
label_logged_as_new: Current user
button_register: Register
issue_list: Issue list
lastest_respond: Lastest respond
label_news_lastest: Lastest news
label_versions_settings: Display settings
label_versions_progress: Complete schedule
label_versions_description: Versions description
label_my_photo: My photo
label_documents_sort: Order setting
label_activities_settings: Display settings
#end
#huang
label_file_new: Download
label_user_edit: "Edit information"
label_user_info: "User information" #huang 添加
label_user_watcher: "Follower" # huang添加的
label_user_fans: "Fans"
label_user_commits: "Code commits"
label_user_watchered: "Followed" # huang添加的
label_user_newfeedback: "Leave a message" ## huang添加的
label_user_login: "Lastest login:"
label_user_mail: "Mail address:"
label_user_joinin: "Join date:"
label_user_activities: "You have no activities,come and join us!"
label_project_overview: "Overview"
label_project_tool: "Tool"
label_project_defect: "Defect"
label_project_newother: "See other comments"
label_project_newshare: "share"
label_project_newadd: "added"
label_project_unadd: "No project,go to creat it!"
label_project_un: "You haven't joined any project!"
#end by huang
#added by liuping
button_unfollow: Unfollow
button_follow: Follow
label_delete_confirm: Confirm delete
label_more_tags: More
#fq
button_leave_meassge: Leave message
label_leave_message_to: leave %{name} a message
label_leave_message: Message content
label_message: message board
field_add: Add before %{time}
button_more: More
label_user_response: User response
label_bidding_project: Bidding project
button_bidding: I want to be the bid
button_new_bid: New bid
label_user_information: "My information"
#Customer addedAdded by nie
label_create_time: Creat time
label_current_contributors: current contributors
label_lines_of_code: lines of code
label_since_last_commits: since last commit
label_users_on_trustie: User
label_front: first page
label_commit_on: commit times
label_follow_people: followers
label_member_since: join trustie2
label_contribute_to: Participate in %{project_count} numbers of projects
label_total_commit: Together %{total_commit} numbers of committing
label_upload_profile: Upload avatar
label_type_as: Type as
label_status_as: Status as
label_priority_as: Priority as
label_member_list: Member list
label_author_name: Posted by %{author_name}
label_comments_count: (%{count} numbers of comments)
label_post_on: Post on
label_find_all_comments: view all comments
label_updated_time_on: " Updated on %{value} "
label_bid_plural: Requirement

View File

@ -17,11 +17,14 @@
RedmineApp::Application.routes.draw do RedmineApp::Application.routes.draw do
resources :shares resources :shares
get "tags/index" get "tags/index"
get "tags/show" get "tags/show"
get "praise_tread/praise_plus"
get "praise_tread/praise_minus"
get "praise_tread/tread_minus"
root :to => 'welcome#index', :as => 'home' root :to => 'welcome#index', :as => 'home'
@ -76,6 +79,8 @@ RedmineApp::Application.routes.draw do
match 'user_newfeedback', :to => 'users#user_newfeedback', :via => :get, :as => "user_newfeedback" match 'user_newfeedback', :to => 'users#user_newfeedback', :via => :get, :as => "user_newfeedback"
match 'watch_bids', :controller => 'users', :action => 'watch_bids', :via => [:get , :post] match 'watch_bids', :controller => 'users', :action => 'watch_bids', :via => [:get , :post]
match 'info', :to => 'users#info', :via => [:get , :post], :as => 'user_info' match 'info', :to => 'users#info', :via => [:get , :post], :as => 'user_info'
match 'user_watchlist', :to => 'users#user_watchlist', :via => :get, :as => "user_watchlist" #add by huang
match 'user_fanslist', :to => 'users#user_fanslist', :via => :get, :as => "user_fanslist" #add by huang
end end
end end
#end #end
@ -95,7 +100,7 @@ RedmineApp::Application.routes.draw do
match 'users/:id/memberships/:membership_id', :to => 'users#edit_membership', :via => :put, :as => 'user_membership' match 'users/:id/memberships/:membership_id', :to => 'users#edit_membership', :via => :put, :as => 'user_membership'
match 'users/:id/memberships/:membership_id', :to => 'users#destroy_membership', :via => :delete match 'users/:id/memberships/:membership_id', :to => 'users#destroy_membership', :via => :delete
match 'users/:id/memberships', :to => 'users#edit_membership', :via => :post, :as => 'user_memberships' match 'users/:id/memberships', :to => 'users#edit_membership', :via => :post, :as => 'user_memberships'
################# added by william ################# added by william
match 'users/tag_save', :to => 'users#tag_save', :via => :post, :as => 'tag' match 'users/tag_save', :to => 'users#tag_save', :via => :post, :as => 'tag'
post 'watchers/watch', :to => 'watchers#watch', :as => 'watch' post 'watchers/watch', :to => 'watchers#watch', :as => 'watch'
@ -422,8 +427,14 @@ RedmineApp::Application.routes.draw do
match 'bids/:id', :controller => 'bids', :action => 'show', :as => 'respond' match 'bids/:id', :controller => 'bids', :action => 'show', :as => 'respond'
########### added by liuping ########### added by liuping
match 'tags/add_tag',:to => 'tags#add_tag',:as=>"add_tag" match 'tags/add_tag',:to => 'tags#add_tag',:as=>"add_tag"
match 'tags/delete_tag',:to => 'tags#delete_tag',:as=>"add_tag" match 'tags/delete_tag',:to => 'tags#delete_tag',:as=>"add_tag"
match 'tags/show_all',:to => 'tags#show_all'
match 'parise_tread/praise_plus',:to => 'parise_tread#praise_plus',:as=>"praise"
match 'parise_tread/tread_minus',:to => 'parise_tread#tread_minus',:as=>"tread"
end end

View File

@ -0,0 +1,5 @@
class AddProjectIdToShares < ActiveRecord::Migration
def change
add_column :shares, :project_id, :integer
end
end

View File

@ -0,0 +1,18 @@
class CreateSeemsRateableRates < ActiveRecord::Migration
def self.up
create_table :seems_rateable_rates do |t|
t.belongs_to :rater
t.belongs_to :rateable, :polymorphic => true
t.float :stars, :null => false
t.integer :rater_id, :limit => 8
t.integer :rateable_id
t.string :rateable_type
t.string :dimension
t.timestamps
end
end
def self.down
drop_table :rates
end
end

View File

@ -0,0 +1,17 @@
class CreateSeemsRateableCachedRatings < ActiveRecord::Migration
def self.up
create_table :seems_rateable_cached_ratings do |t|
t.belongs_to :cacheable, :polymorphic => true
t.float :avg, :null => false
t.integer :cnt, :null => false
t.string :dimension
t.integer :cacheable_id, :limit => 8
t.string :cacheable_type
t.timestamps
end
end
def self.down
drop_table :cached_ratings
end
end

View File

@ -0,0 +1,15 @@
class CreatePraiseTreads < ActiveRecord::Migration
def self.up
create_table :praise_treads do |t|
t.column :user_id,:integer,:null => false
t.column :praise_tread_object_id,:integer
t.column :praise_tread_object_type,:string
t.column :praise_or_tread,:integer
t.timestamps
end
end
def self.down
drop_table :praise_treads
end
end

View File

@ -0,0 +1,16 @@
class CreatePraiseTreadCaches < ActiveRecord::Migration
def self.up
create_table :praise_tread_caches do |t|
t.column :object_id,:integer,:null => false
t.column :object_type,:string
t.column :praise_num,:integer
t.column :tread_num,:integer
t.timestamps
end
end
def self.down
drop_table :praise_tread_caches
end
end

View File

@ -11,7 +11,7 @@
# #
# It's strongly recommended to check this file into your version control system. # It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20130805131602) do ActiveRecord::Schema.define(:version => 20130807021309) do
create_table "a_user_watchers", :force => true do |t| create_table "a_user_watchers", :force => true do |t|
t.string "name" t.string "name"
@ -432,6 +432,24 @@ ActiveRecord::Schema.define(:version => 20130805131602) do
t.string "salt", :null => false t.string "salt", :null => false
end end
create_table "praise_tread_caches", :force => true do |t|
t.integer "object_id", :null => false
t.string "object_type"
t.integer "praise_num"
t.integer "tread_num"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "praise_treads", :force => true do |t|
t.integer "user_id", :null => false
t.integer "praise_tread_object_id"
t.string "praise_tread_object_type"
t.integer "praise_or_tread"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "project_tags", :force => true do |t| create_table "project_tags", :force => true do |t|
t.integer "project_id" t.integer "project_id"
t.integer "tag_id" t.integer "tag_id"
@ -506,7 +524,6 @@ ActiveRecord::Schema.define(:version => 20130805131602) do
t.text "permissions" t.text "permissions"
t.string "issues_visibility", :limit => 30, :default => "default", :null => false t.string "issues_visibility", :limit => 30, :default => "default", :null => false
end end
create_table "settings", :force => true do |t| create_table "settings", :force => true do |t|
t.string "name", :default => "", :null => false t.string "name", :default => "", :null => false
t.text "value" t.text "value"
@ -522,6 +539,7 @@ ActiveRecord::Schema.define(:version => 20130805131602) do
t.string "url" t.string "url"
t.datetime "created_at", :null => false t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false t.datetime "updated_at", :null => false
t.integer "project_id"
end end
create_table "students", :force => true do |t| create_table "students", :force => true do |t|

View File

@ -0,0 +1,21 @@
*.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
.project
.rvmrc
spec
test

View File

@ -0,0 +1,23 @@
source "https://rubygems.org"
# Declare your gem's dependencies in seems_rateable.gemspec.
# Bundler will treat runtime dependencies like base dependencies, and
# development dependencies will be added by default to the :development group.
gemspec
# Declare any dependencies that are still in development here instead of in
# your gemspec. These might include edge Rails or gems from your path or
# Git. Remember to move these dependencies to your gemspec before releasing
# your gem to rubygems.org.
# To use debugger
# gem 'debugger'
group :development do
gem 'sqlite3'
gem 'jquery-rails'
gem 'twitter-bootstrap-rails'
gem 'sorcery'
end

View File

@ -0,0 +1,20 @@
Copyright 2013 YOURNAME
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,111 @@
# SeemsRateable
Star rating gem for Rails application using jQuery plugin <a href="http://www.myjqueryplugins.com/jquery-plugin/jrating">jRating</a>
## Demo
<a href="http://rateable.herokuapp.com/">Demo</a> application, requires to sign up before rating
## Instructions
### Installation
Add this line to your application's Gemfile:
gem 'seems_rateable'
And then execute:
$ bundle
Or install it yourself as:
$ gem install seems_rateable
### Generation
$ rails generate seems_rateable:install
Generator creates migration files, javascript files and initializer
### Prepare
Require javascript files by adding this line to application.js
#application.js
//= require_directory ./rateable
Add <code>seems_rateable</code> to routes.rb file
Include stylesheet adding <code><%= seems_rateable_stylesheet %></code> to your layout header
Also make sure you have an existing <code>current_user</code> helper method
Don't forget to run
$ rake db:migrate
To prepare model add <code> seems_rateable </code> to your rateable model file. You can also pass a hash of options to
customize the functionality
<ul>
<li><code>:dimensions</code>Array of dimensions e.g <code>:dimensions => [:quality, :quantity]</code> </li>
<li><code>:allow_update</code>Allowing user to re-rate his own ratings, default set to false e.g <code>:allow_update=> true</code></li>
</ul>
class Post < ActiveRecord::Base
seems_rateable :allow_update => true, :dimensions => [:quality, :length]
end
To access object's rates use <code>rates</code> method, to get dimension rates pass an argument eg :
@object.rates
@object.rates(:quality)
@object.rates(:quantity)
This also applies to cached average rating e.g
@object.average
@object.average(:quality)
@object.average(:quantity)
And to object's raters e.g
@object.raters
@object.raters(:quality)
@object.raters(:quantity)
To track user's given ratings add <code>seems_rateable_rater</code> to your rater model.
If your rater class is not "User"(e.g "Client" or "Customer") change configuration in initializer generated by this engine.
Now you can access user's ratings by <code>@user.ratings_given</code>
### Usage
To display star rating use helper method <code>rating_for</code> in your view
#index.html.erb
rating_for @post
rating_for @post, :dimension => :quality, :class => 'post', :id => 'list'
rating_for @post, :static => true
You can specify these options :
<ul>
<li><code>:dimension</code>The dimension of the object</li>
<li><code>:static</code>Set to true to display static star rating, default false</li>
<li><code>:class</code>Class of the div, default set to 'rateable'</li>
<li><code>:id</code>ID of the div e.g <code>:id => "info"</code>, default nil</li>
</ul>
To edit the javascript options locate rateable.js file in /app/assets/javascripts/rateable/.
The javascript options are explained directly in the file
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request

View File

@ -0,0 +1,32 @@
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end
require 'rdoc/task'
RDoc::Task.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'SeemsRateable'
rdoc.options << '--line-numbers'
rdoc.rdoc_files.include('README.rdoc')
rdoc.rdoc_files.include('lib/**/*.rb')
end
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
load 'rails/tasks/engine.rake'
Bundler::GemHelper.install_tasks
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
load 'rails/tasks/engine.rake'
Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
require 'rspec/core'
require 'rspec/core/rake_task'
task :default => :spec

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

View File

@ -0,0 +1,15 @@
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//= require_tree .

View File

@ -0,0 +1,62 @@
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the top of the
* compiled file, but it's generally better to create a new file per style scope.
*
*= require_self
*= require_tree .
*/
/*********************/
/** jRating CSS **/
/*********************/
/**Div containing the color of the stars */
.jRatingAverage {
background-color:#f62929;
position:relative;
top:0;
left:0;
z-index:2;
height:100%;
}
.jRatingColor {
background-color:#FFD400; /* bgcolor of the stars*/
position:relative;
top:0;
left:0;
z-index:2;
height:100%;
}
/** Div containing the stars **/
.jStar {
position:relative;
left:0;
z-index:3;
}
/** P containing the rate informations **/
p.jRatingInfos {
position: absolute;
z-index:9999;
background: transparent url('bg_jRatingInfos.png') no-repeat;
color: #CACACA;
display: none;
width: 91px;
height: 29px;
font-size:16px;
text-align:center;
padding-top:5px;
}
p.jRatingInfos span.maxRate {
color:#c9c9c9;
font-size:14px;
}

View File

@ -0,0 +1,4 @@
module SeemsRateable
class ApplicationController < ActionController::Base
end
end

View File

@ -0,0 +1,17 @@
require_dependency "seems_rateable/application_controller"
module SeemsRateable
class RatingsController < ::ApplicationController
def create
raise NoCurrentUserInstanceError unless current_user
obj = params[:kls].classify.constantize.find(params[:idBox])
begin
obj.rate(params[:rate].to_i, current_user.id, params[:dimension])
render :json => true
rescue Errors::AlreadyRatedError
render :json => {:error => true}
end
end
end
end

View File

@ -0,0 +1,4 @@
module SeemsRateable
module ApplicationHelper
end
end

View File

@ -0,0 +1,4 @@
module SeemsRateable
module RatingsHelper
end
end

View File

@ -0,0 +1,5 @@
module SeemsRateable
class CachedRating < ActiveRecord::Base
belongs_to :cacheable, :polymorphic => true
end
end

View File

@ -0,0 +1,6 @@
module SeemsRateable
class Rate < ActiveRecord::Base
belongs_to :rater, :class_name => SeemsRateable::Engine.config.owner_class
belongs_to :rateable, :polymorphic => true
end
end

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title>SeemsRateable</title>
<%= stylesheet_link_tag "seems_rateable/application", media: "all" %>
<%= javascript_include_tag "seems_rateable/application" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>

View File

@ -0,0 +1,8 @@
#!/usr/bin/env ruby1.9.1
# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
ENGINE_ROOT = File.expand_path('../..', __FILE__)
ENGINE_PATH = File.expand_path('../../lib/seems_rateable/engine', __FILE__)
require 'rails/all'
require 'rails/engine/commands'

View File

@ -0,0 +1,3 @@
SeemsRateable::Engine.routes.draw do
resources :ratings, :only => :create
end

View File

@ -0,0 +1,39 @@
require 'rails/generators/migration'
require 'fileutils'
module SeemsRateable
module Generators
class InstallGenerator < ::Rails::Generators::Base
include Rails::Generators::Migration
source_root File.expand_path('../templates', __FILE__)
def self.next_migration_number(path)
unless @prev_migration_nr
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
else
@prev_migration_nr += 1
end
@prev_migration_nr.to_s
end
desc "generating migration files"
def copy_migrations
migration_template "rates_migration.rb", "db/migrate/create_seems_rateable_rates.rb"
migration_template "cached_ratings_migration.rb", "db/migrate/create_seems_rateable_cached_ratings.rb"
end
desc "generating initializer"
def copy_initializer
template "initializer.rb", "config/initializers/seems_rateable.rb"
end
desc "generating javascript files"
def copy_javascript_asset
Dir.mkdir "app/assets/javascripts/rateable" unless File.directory?("app/assets/javascripts/rateable")
copy_file "rateable.js.erb", "app/assets/javascripts/rateable/rateable.js.erb" unless File.exists?("app/assets/javascripts/rateable/rateable.js.erb")
copy_file "jRating.js.erb", "app/assets/javascripts/rateable/jRating.js.erb" unless File.exists?("app/assets/javascripts/rateable/jRating.js.erb")
end
end
end
end

View File

@ -0,0 +1,17 @@
class CreateSeemsRateableCachedRatings < ActiveRecord::Migration
def self.up
create_table :seems_rateable_cached_ratings do |t|
t.belongs_to :cacheable, :polymorphic => true
t.float :avg, :null => false
t.integer :cnt, :null => false
t.string :dimension
t.integer :cacheable_id, :limit => 8
t.string :cacheable_type
t.timestamps
end
end
def self.down
drop_table :cached_ratings
end
end

View File

@ -0,0 +1,4 @@
#SeemsRateable engine Initializer
#Configure owner class of the given ratings
SeemsRateable::Engine.config.owner_class = "User"

View File

@ -0,0 +1,225 @@
/************************************************************************
*************************************************************************
@Name : jRating - jQuery Plugin
@Revison : 3.0
@Date : 28/01/2013
@Author: ALPIXEL - (www.myjqueryplugins.com - www.alpixel.fr)
@License : Open Source - MIT License : http://www.opensource.org/licenses/mit-license.php
**************************************************************************
*************************************************************************/
(function($) {
$.fn.jRating = function(op) {
var defaults = {
/** String vars **/
bigStarsPath : '<%= image_path "seems_rateable/stars.png" %>', // path of the icon stars.png
smallStarsPath : '<%= image_path "seems_rateable/small.png" %>', // path of the icon small.png
path : '<%= SeemsRateable::Engine.routes.url_helpers.ratings_path %>',
type : 'big', // can be set to 'small' or 'big'
/** Boolean vars **/
step:false, // if true, mouseover binded star by star,
isDisabled:false,
showRateInfo: false,
canRateAgain : false,
/** Integer vars **/
length:5, // number of star to display
decimalLength : 0, // number of decimals.. Max 3, but you can complete the function 'getNote'
rateMax : 20, // maximal rate - integer from 0 to 9999 (or more)
rateInfosX : -45, // relative position in X axis of the info box when mouseover
rateInfosY : 5, // relative position in Y axis of the info box when mouseover
nbRates : 1,
/** Functions **/
onSuccess : null,
onError : null
};
if(this.length>0)
return this.each(function() {
/*vars*/
var opts = $.extend(defaults, op),
newWidth = 0,
starWidth = 0,
starHeight = 0,
bgPath = '',
hasRated = false,
globalWidth = 0,
nbOfRates = opts.nbRates;
if($(this).hasClass('jDisabled') || opts.isDisabled)
var jDisabled = true;
else
var jDisabled = false;
getStarWidth();
$(this).height(starHeight);
var average = parseFloat($(this).attr('data-average')), // get the average of all rates
idBox = parseInt($(this).attr('data-id')), // get the id of the box
kls = $(this).attr('data-kls'),
dimension = $(this).attr('data-dimension'),
widthRatingContainer = starWidth*opts.length, // Width of the Container
widthColor = average/opts.rateMax*widthRatingContainer, // Width of the color Container
quotient =
$('<div>',
{
'class' : 'jRatingColor',
css:{
width:widthColor
}
}).appendTo($(this)),
average =
$('<div>',
{
'class' : 'jRatingAverage',
css:{
width:0,
top:- starHeight
}
}).appendTo($(this)),
jstar =
$('<div>',
{
'class' : 'jStar',
css:{
width:widthRatingContainer,
height:starHeight,
top:- (starHeight*2),
background: 'url('+bgPath+') repeat-x'
}
}).appendTo($(this));
$(this).css({width: widthRatingContainer,overflow:'hidden',zIndex:1,position:'relative'});
if(!jDisabled)
$(this).unbind().bind({
mouseenter : function(e){
var realOffsetLeft = findRealLeft(this);
var relativeX = e.pageX - realOffsetLeft;
if (opts.showRateInfo)
var tooltip =
$('<p>',{
'class' : 'jRatingInfos',
html : getNote(relativeX)+' <span class="maxRate">/ '+opts.rateMax+'</span>',
css : {
top: (e.pageY + opts.rateInfosY),
left: (e.pageX + opts.rateInfosX)
}
}).appendTo('body').show();
},
mouseover : function(e){
$(this).css('cursor','pointer');
},
mouseout : function(){
$(this).css('cursor','default');
if(hasRated) average.width(globalWidth);
else average.width(0);
},
mousemove : function(e){
var realOffsetLeft = findRealLeft(this);
var relativeX = e.pageX - realOffsetLeft;
if(opts.step) newWidth = Math.floor(relativeX/starWidth)*starWidth + starWidth;
else newWidth = relativeX;
average.width(newWidth);
if (opts.showRateInfo)
$("p.jRatingInfos")
.css({
left: (e.pageX + opts.rateInfosX)
})
.html(getNote(newWidth) +' <span class="maxRate">/ '+opts.rateMax+'</span>');
},
mouseleave : function(){
$("p.jRatingInfos").remove();
},
click : function(e){
var element = this;
/*set vars*/
hasRated = true;
globalWidth = newWidth;
nbOfRates--;
if(!opts.canRateAgain || parseInt(nbOfRates) <= 0) $(this).unbind().css('cursor','default').addClass('jDisabled');
if (opts.showRateInfo) $("p.jRatingInfos").fadeOut('fast',function(){$(this).remove();});
e.preventDefault();
var rate = getNote(newWidth);
average.width(newWidth);
$.post(defaults.path,
{
idBox : idBox,
rate : rate,
kls : kls,
dimension : dimension
/** action : 'rating' **/
},
function(data) {
if(!data.error)
{
/** Here you can display an alert box,
or use the jNotify Plugin :) http://www.myqjqueryplugins.com/jNotify
exemple : */
if(opts.onSuccess) opts.onSuccess( element, rate );
}
else
{
/** Here you can display an alert box,
or use the jNotify Plugin :) http://www.myqjqueryplugins.com/jNotify
exemple : */
if(opts.onError) opts.onError( element, rate );
}
},
'json'
);
}
});
function getNote(relativeX) {
var noteBrut = parseFloat((relativeX*100/widthRatingContainer)*opts.rateMax/100);
switch(opts.decimalLength) {
case 1 :
var note = Math.round(noteBrut*10)/10;
break;
case 2 :
var note = Math.round(noteBrut*100)/100;
break;
case 3 :
var note = Math.round(noteBrut*1000)/1000;
break;
default :
var note = Math.round(noteBrut*1)/1;
}
return note;
};
function getStarWidth(){
switch(opts.type) {
case 'small' :
starWidth = 12; // width of the picture small.png
starHeight = 10; // height of the picture small.png
bgPath = opts.smallStarsPath;
break;
default :
starWidth = 23; // width of the picture stars.png
starHeight = 20; // height of the picture stars.png
bgPath = opts.bigStarsPath;
}
};
function findRealLeft(obj) {
if( !obj ) return 0;
return obj.offsetLeft + findRealLeft( obj.offsetParent );
};
});
}
})(jQuery);

View File

@ -0,0 +1,25 @@
$(document).ready(function(){
$(".rateable").jRating({
//default options displayed below ->
rateMax: 5, //Maximal rate
length : 5, //Number of stars
//decimalLength : 0, //Number of decimals in the rate
//type : 'big', //Big or small
//step : true, //If set to true, filling of the stars is done star by star (step by step).
//isDisabled: false, //Set true to display static rating
//showRateInfo:false, //Rate info panel, set true to display
//rateInfosX : 45, //In pixel - Absolute left position of the information box during mousemove.
//rateInfosY : 5, //In pixel - Absolute top position of the information box during mousemove.
path : '<%= SeemsRateable::Engine.routes.url_helpers.ratings_path %>',
onSuccess : function(element, rate){
//something like ->
//alert('success');
$('<span class="text-success"><small style="display:inline-block;">Thanks for rating!</small></span>').insertAfter(element)
},
onError : function(element, rate) {
$('<span class="text-error"><small style="display:inline-block;">You have already rated!</small></span>').insertAfter(element)
}
});
});

View File

@ -0,0 +1,18 @@
class CreateSeemsRateableRates < ActiveRecord::Migration
def self.up
create_table :seems_rateable_rates do |t|
t.belongs_to :rater
t.belongs_to :rateable, :polymorphic => true
t.float :stars, :null => false
t.integer :rater_id, :limit => 8
t.integer :rateable_id
t.string :rateable_type
t.string :dimension
t.timestamps
end
end
def self.down
drop_table :rates
end
end

View File

@ -0,0 +1,14 @@
begin
require 'rails'
rescue LoadError
end
require "seems_rateable/engine"
require "seems_rateable/errors"
require "seems_rateable/helpers"
require "seems_rateable/model"
require "seems_rateable/routes"
require "seems_rateable/version"
module SeemsRateable
end

View File

@ -0,0 +1,17 @@
module SeemsRateable
class Engine < ::Rails::Engine
isolate_namespace SeemsRateable
config.generators do |g|
g.test_framework :rspec, :fixture => false
g.fixture_replacement :factory_girl, :dir => 'spec/factories'
end
initializer :seems_rateable do
ActiveRecord::Base.send :include, SeemsRateable::Model
ActionView::Base.send :include, SeemsRateable::Helpers
ActionDispatch::Routing::Mapper.send :include, SeemsRateable::Routes
end
end
end

View File

@ -0,0 +1,21 @@
module SeemsRateable
module Errors
class InvalidRateableObjectError < StandardError
def to_s
"Stated object is not rateable. Add 'seems_rateable' to your object's class model."
end
end
class NoCurrentUserInstanceError < StandardError
def to_s
"User instance current_user is not available."
end
end
class AlreadyRatedError < StandardError
def to_s
"User has already rated an object."
end
end
end
end

View File

@ -0,0 +1,27 @@
module SeemsRateable
module Helpers
def rating_for(obj, opts={})
raise Errors::InvalidRateableObjectError unless obj.class.respond_to?(:rateable?)
options = {
:dimension => nil,
:static => false,
:class => 'rateable',
:id => nil
}.update(opts)
content_tag :div, "", "data-average" => obj.average(options[:dimension]) ? obj.average(options[:dimension]).avg : 0, :id => options[:id],
:class => "#{options[:class]}#{jdisabled?(options[:static])}",
"data-id" => obj.id, "data-kls" => obj.class.name, "data-dimension" => options[:dimension]
end
def seems_rateable_stylesheet
stylesheet_link_tag "seems_rateable/application", media: "all", "data-turbolinks-track" => true
end
private
def jdisabled?(option)
" jDisabled" if option || !current_user
end
end
end

View File

@ -0,0 +1,111 @@
require 'active_support/concern'
module SeemsRateable
module Model
extend ActiveSupport::Concern
def rate(stars, user_id, dimension=nil)
if !has_rated?(user_id, dimension)
self.rates.create do |r|
r.stars = stars
r.rater_id = user_id
end
update_overall_average_rating(stars, dimension)
elsif has_rated?(user_id, dimension) && can_update?
update_users_rating(stars, user_id, dimension)
else
raise Errors::AlreadyRatedError
end
end
def update_overall_average_rating(stars, dimension=nil)
if average(dimension).nil?
CachedRating.create do |r|
r.avg = stars
r.dimension = dimension
r.cacheable_id = self.id
r.cacheable_type = self.class.name
r.cnt = 1
end
else
r = average(dimension)
r.avg = (r.avg * r.cnt + stars) / (r.cnt+1)
r.cnt += 1
r.save!
end
end
def update_users_rating(stars, user_id, dimension=nil)
obj = rates(dimension).where(:rater_id => user_id).first
current_record = average(dimension)
current_record.avg = (current_record.avg*current_record.cnt - obj.stars + stars) / (current_record.cnt)
current_record.save!
obj.stars = stars
obj.save!
end
def average(dimension=nil)
if dimension.nil?
self.send "rate_average_without_dimension"
else
self.send "#{dimension}_average"
end
end
def rates(dimension=nil)
if dimension.nil?
self.send "rates_without_dimension"
else
self.send "#{dimension}_rates"
end
end
def raters(dimension=nil)
if dimension.nil?
self.send "raters_without_dimension"
else
self.send "#{dimension}_raters"
end
end
def has_rated?(user_id, dimension=nil)
record = self.rates(dimension).where(:rater_id => user_id)
record.empty? ? false : true
end
def can_update?
self.class.can_update?
end
module ClassMethods
def seems_rateable(opts={})
#has_many :rates_without_dimension, -> { where(dimension: nil) }, :as => :rateable, :class_name => SeemsRateable::Rate, :dependent => :destroy
has_many :rates_without_dimension, :conditions => { dimension: nil }, :as => :rateable, :class_name => SeemsRateable::Rate, :dependent => :destroy
has_many :raters_without_dimension, :through => :rates_without_dimension, :source => :rater
has_one :rate_average_without_dimension, :conditions => { dimension: nil }, :as => :cacheable, :class_name => SeemsRateable::CachedRating, :dependent => :destroy
@permission = opts[:allow_update] ? true : false
def self.can_update?
@permission
end
def self.rateable?
true
end
if opts[:dimensions].is_a?(Array)
opts[:dimensions].each do |dimension|
has_many :"#{dimension}_rates", :conditions => { dimension: dimension.to_s }, :dependent => :destroy, :class_name => SeemsRateable::Rate, :as => :rateable
has_many :"#{dimension}_raters", :through => :"#{dimension}_rates", :source => :rater
has_one :"#{dimension}_average", :conditions => { dimension: dimension.to_s }, :as => :cacheable, :class_name => SeemsRateable::CachedRating, :dependent => :destroy
end
end
end
def seems_rateable_rater
has_many :ratings_given, :class_name => SeemsRateable::Rate, :foreign_key => :rater_id
end
end
end
end

View File

@ -0,0 +1,7 @@
module SeemsRateable
module Routes
def seems_rateable
mount SeemsRateable::Engine => '/rateable', :as => :rateable
end
end
end

View File

@ -0,0 +1,3 @@
module SeemsRateable
VERSION = "1.0.9"
end

View File

@ -0,0 +1,4 @@
# desc "Explaining what the task does"
# task :seems_rateable do
# # Task goes here
# end

View File

@ -0,0 +1,25 @@
$:.push File.expand_path("../lib", __FILE__)
# Maintain your gem's version:
require "seems_rateable/version"
# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
s.name = "seems_rateable"
s.version = SeemsRateable::VERSION
s.authors = ["Peter Toth"]
s.email = ["proximin@gmail.com"]
s.homepage = "http://rateable.herokuapp.com"
s.summary = "Star Rating Engine"
s.description = "Star rating engine using jQuery plugin jRating for Rails applications"
s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"]
s.add_dependency "rails"
s.add_dependency "jquery-rails"
s.add_development_dependency "sqlite3"
s.add_development_dependency 'rspec-rails'
s.add_development_dependency 'capybara'
s.add_development_dependency 'factory_girl_rails'
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
public/images/praise.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
public/images/tread.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -11,6 +11,11 @@ h4 {border-bottom: 1px dotted #bbb;}
/*new by huang*/ /*new by huang*/
/**/ /**/
ul.list_watch{list-style-type:none;
height:auto;
border-bottom: 1px dashed rgb(204, 204, 204);
}
.new_creat{ .new_creat{
padding-top: 0px; padding-top: 0px;
float: right; float: right;