Merge branch 'develop' of 10.0.47.245:/home/trustie2 into develop
1
Gemfile
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
|
@ -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);
|
|
@ -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)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,4 @@
|
||||||
|
/*
|
||||||
|
Place all the styles related to the matching controller here.
|
||||||
|
They will automatically be included in application.css.
|
||||||
|
*/
|
|
@ -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?
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
@ -79,4 +77,9 @@ class TagsController < ApplicationController
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show_all
|
||||||
|
@tags = ActsAsTaggableOn::Tag.find(:all)
|
||||||
|
@tags = @tags.to_a
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,10 +17,14 @@
|
||||||
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
|
||||||
helper :custom_fields
|
helper :custom_fields
|
||||||
|
@ -382,6 +386,15 @@ class UsersController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
###add by huang
|
||||||
|
def user_watchlist
|
||||||
|
|
||||||
|
end
|
||||||
|
###add by huang
|
||||||
|
def user_fanslist
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def find_user
|
def find_user
|
||||||
|
|
|
@ -26,11 +26,8 @@ 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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
class PraiseTread < ActiveRecord::Base
|
||||||
|
attr_accessible :user_id,:praise_tread_object_id,:praise_tread_object_type,:praise_or_tread
|
||||||
|
|
||||||
|
end
|
|
@ -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
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ 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
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 -->
|
||||||
|
|
|
@ -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,6 +45,11 @@
|
||||||
</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>)
|
<%= l(:label_user_watcher) %> (<strong class="font_small_watch"><%= User.watched_by(@user.id).count %></strong>)
|
||||||
<%= 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>)
|
||||||
|
@ -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>
|
||||||
|
|
|
@ -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 %>
|
|
@ -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}
|
||||||
|
)%>');
|
|
@ -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}
|
||||||
|
)%>');
|
|
@ -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 %>
|
|
@ -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>
|
|
@ -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" >
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
#SeemsRateable engine Initializer
|
||||||
|
|
||||||
|
#Configure owner class of the given ratings
|
||||||
|
SeemsRateable::Engine.config.owner_class = "User"
|
|
@ -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 added!Added 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
|
|
@ -18,11 +18,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
|
||||||
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddProjectIdToShares < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :shares, :project_id, :integer
|
||||||
|
end
|
||||||
|
end
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
22
db/schema.rb
|
@ -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|
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 572 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 1018 B |
|
@ -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 .
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
module SeemsRateable
|
||||||
|
class ApplicationController < ActionController::Base
|
||||||
|
end
|
||||||
|
end
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
||||||
|
module SeemsRateable
|
||||||
|
module ApplicationHelper
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,4 @@
|
||||||
|
module SeemsRateable
|
||||||
|
module RatingsHelper
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
module SeemsRateable
|
||||||
|
class CachedRating < ActiveRecord::Base
|
||||||
|
belongs_to :cacheable, :polymorphic => true
|
||||||
|
end
|
||||||
|
end
|
|
@ -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
|
|
@ -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>
|
|
@ -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'
|
|
@ -0,0 +1,3 @@
|
||||||
|
SeemsRateable::Engine.routes.draw do
|
||||||
|
resources :ratings, :only => :create
|
||||||
|
end
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
||||||
|
#SeemsRateable engine Initializer
|
||||||
|
|
||||||
|
#Configure owner class of the given ratings
|
||||||
|
SeemsRateable::Engine.config.owner_class = "User"
|
|
@ -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);
|
|
@ -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)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
||||||
|
module SeemsRateable
|
||||||
|
module Routes
|
||||||
|
def seems_rateable
|
||||||
|
mount SeemsRateable::Engine => '/rateable', :as => :rateable
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,3 @@
|
||||||
|
module SeemsRateable
|
||||||
|
VERSION = "1.0.9"
|
||||||
|
end
|
|
@ -0,0 +1,4 @@
|
||||||
|
# desc "Explaining what the task does"
|
||||||
|
# task :seems_rateable do
|
||||||
|
# # Task goes here
|
||||||
|
# end
|
|
@ -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
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 194 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 2.9 KiB |
|
@ -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;
|
||||||
|
|