logs
This commit is contained in:
parent
72fffcfbca
commit
e6a9e00f82
10
app/assets/javascripts/logs.js
Normal file
10
app/assets/javascripts/logs.js
Normal file
@ -0,0 +1,10 @@
|
||||
(function($) {
|
||||
|
||||
$(document).on("turbolinks:load", function() {
|
||||
$(".log-form input.datepicker").datepicker({autoclose: true, todayBtn: "linked", format: "yyyy-mm-dd"});
|
||||
$(".log-form input.rating").starRating();
|
||||
|
||||
$(".log-table input.rating").starRating({readOnly: true});
|
||||
});
|
||||
|
||||
})(jQuery);
|
@ -3,6 +3,8 @@
|
||||
$(document).on("turbolinks:load", function() {
|
||||
$(".recipe-view ul.ingredients").checkable();
|
||||
$(".recipe-view ol.steps").checkable();
|
||||
|
||||
$(".recipe-table input.rating").starRating({readOnly: true, interval: 0.25, size: '20px'});
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
|
@ -3,37 +3,68 @@
|
||||
|
||||
var pluginName = "starRating";
|
||||
var defaultOptions = {
|
||||
starCount: 5
|
||||
starCount: 5,
|
||||
readOnly: false,
|
||||
interval: 1,
|
||||
size: '30px'
|
||||
};
|
||||
|
||||
var methods = {
|
||||
initialize: function(opts) {
|
||||
return this.each(function() {
|
||||
var $input = $(this);
|
||||
|
||||
if ($input.data(pluginName.toLowerCase()) === true) {
|
||||
if (console && console.log) {
|
||||
console.log("star rating has already been initialized; skipping...");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$input.attr("data-" + pluginName.toLowerCase(), "true");
|
||||
|
||||
var options = _.extend({}, defaultOptions, opts);
|
||||
|
||||
var $input = $(this);
|
||||
options.$input = $input;
|
||||
var $widget = $("<span />").addClass("star-rating").css({'font-size': options.size});
|
||||
var $emptySet = $("<span />").addClass("empty-set").appendTo($widget);
|
||||
var $filledSet = $("<span />").addClass("filled-set").appendTo($widget);
|
||||
|
||||
var $widget = $("<span />").addClass("star-rating");
|
||||
options.$input = $input;
|
||||
options.$emptySet = $emptySet;
|
||||
|
||||
for (var x = 1; x <= options.starCount; x++) {
|
||||
$widget.append(
|
||||
$("<span />").addClass("star").data("rating", x)
|
||||
$emptySet.append(
|
||||
$("<span />").addClass("star empty")
|
||||
);
|
||||
|
||||
$filledSet.append(
|
||||
$("<span />").addClass("star full")
|
||||
);
|
||||
}
|
||||
|
||||
$widget.data(pluginName + ".options", options);
|
||||
|
||||
$input.hide().after($widget);
|
||||
$input.data(pluginName, true).hide().after($widget);
|
||||
|
||||
privateMethods.updateStars($widget);
|
||||
|
||||
$widget.on("click." + pluginName, "span.star", function(e) {
|
||||
var value = $(this).data("rating");
|
||||
if (!options.readOnly) {
|
||||
$widget
|
||||
.on("click." + pluginName, function(e) {
|
||||
var value = privateMethods.calculateRating($widget, e.pageX);
|
||||
privateMethods.setValue($widget, value);
|
||||
})
|
||||
.on("mousemove." + pluginName, function(e) {
|
||||
var value = privateMethods.calculateRating($widget, e.pageX);
|
||||
privateMethods.updateStars($widget, value);
|
||||
})
|
||||
.on("mouseleave." + pluginName, function (e) {
|
||||
privateMethods.updateStars($widget);
|
||||
});
|
||||
}
|
||||
|
||||
$input.on("change." + pluginName, function() {
|
||||
$input
|
||||
.on("change." + pluginName, function() {
|
||||
privateMethods.updateStars($widget);
|
||||
});
|
||||
});
|
||||
@ -41,25 +72,33 @@
|
||||
};
|
||||
|
||||
var privateMethods = {
|
||||
updateStars: function($widget) {
|
||||
updateStars: function($widget, value) {
|
||||
var options = $widget.data(pluginName + ".options");
|
||||
var value = parseInt(options.$input.val());
|
||||
|
||||
$widget.find(".star").each(function(idx, elem) {
|
||||
var $star = $(elem);
|
||||
$star.removeClass("empty full");
|
||||
if ($star.data("rating") <= value) {
|
||||
$star.addClass("full");
|
||||
} else {
|
||||
$star.addClass("empty");
|
||||
}
|
||||
});
|
||||
value = (value == null ? (parseFloat(options.$input.val() || 0)) : value);
|
||||
$widget.find(".filled-set").css({width: privateMethods.calculateWidth($widget, value)});
|
||||
},
|
||||
|
||||
setValue: function($widget, value) {
|
||||
var options = $widget.data(pluginName + ".options");
|
||||
options.$input.val(value);
|
||||
privateMethods.updateStars($widget);
|
||||
},
|
||||
|
||||
calculateWidth: function($widget, value) {
|
||||
var options = $widget.data(pluginName + ".options");
|
||||
var width = options.$emptySet.width();
|
||||
return ((value / options.starCount) * 100).toString() + "%";
|
||||
},
|
||||
|
||||
// Given a screen X coordinate, calculates the nearest valid value for this rating widget
|
||||
calculateRating: function($widget, screenX) {
|
||||
var options = $widget.data(pluginName + ".options");
|
||||
var offset = options.$emptySet.offset();
|
||||
var width = options.$emptySet.width();
|
||||
var ratio = (screenX - offset.left) / width;
|
||||
ratio = Math.max(0, Math.min(1, ratio));
|
||||
|
||||
return Math.ceil(options.starCount * (1 / options.interval) * ratio) / (1 / options.interval);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2,10 +2,23 @@
|
||||
|
||||
span.star-rating {
|
||||
|
||||
display: block;
|
||||
font-size: 30px;
|
||||
display: inline-block;
|
||||
color: gold;
|
||||
cursor: default;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
|
||||
.empty-set {
|
||||
color: gray;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.filled-set {
|
||||
overflow-x: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
span.star {
|
||||
|
||||
|
@ -3,14 +3,11 @@ class LogsController < ApplicationController
|
||||
before_action :ensure_valid_user
|
||||
|
||||
before_action :set_log, only: [:show, :edit, :update, :destroy]
|
||||
before_action :set_recipe, only: [:index, :new, :create]
|
||||
before_action :set_recipe, only: [:new, :create]
|
||||
before_action :require_recipe, only: [:new, :create]
|
||||
|
||||
def index
|
||||
@logs = Log.for_user(current_user)
|
||||
if @recipe
|
||||
@logs = @logs.for_recipe(@recipe)
|
||||
end
|
||||
@logs = Log.for_user(current_user).order(:date)
|
||||
end
|
||||
|
||||
def show
|
||||
@ -41,8 +38,9 @@ class LogsController < ApplicationController
|
||||
|
||||
def create
|
||||
@log = Log.new
|
||||
@log.recipe = @recipe.log_copy(current_user)
|
||||
@log.assign_attributes(log_params)
|
||||
@log.recipe.is_log = true
|
||||
@log.recipe.user = current_user
|
||||
@log.user = current_user
|
||||
@log.source_recipe = @recipe
|
||||
|
||||
@ -79,7 +77,7 @@ class LogsController < ApplicationController
|
||||
end
|
||||
|
||||
def log_params
|
||||
params.require(:log).permit(:date, :rating, recipe_attributes: [:name, :description, :source, :yields, :total_time, :active_time, recipe_ingredients_attributes: [:name, :ingredient_id, :quantity, :units, :preparation, :sort_order, :id, :_destroy], recipe_steps_attributes: [:step, :sort_order, :id, :_destroy]])
|
||||
params.require(:log).permit(:date, :rating, :notes, recipe_attributes: [:name, :description, :source, :yields, :total_time, :active_time, recipe_ingredients_attributes: [:name, :ingredient_id, :quantity, :units, :preparation, :sort_order, :id, :_destroy], recipe_steps_attributes: [:step, :sort_order, :id, :_destroy]])
|
||||
end
|
||||
|
||||
end
|
@ -1,9 +1,11 @@
|
||||
class LogDecorator < BaseDecorator
|
||||
|
||||
def recipe
|
||||
RecipeDecorator.decorate(wrapped.recipe, h)
|
||||
end
|
||||
|
||||
def date
|
||||
v = super
|
||||
puts v
|
||||
puts '================'
|
||||
if v && v.respond_to?(:strftime)
|
||||
v.strftime("%Y-%m-%d")
|
||||
else
|
||||
|
@ -24,4 +24,8 @@ class RecipeDecorator < BaseDecorator
|
||||
end
|
||||
end
|
||||
|
||||
def average_rating
|
||||
@average_rating ||= (Log.for_recipe(wrapped).for_user(self.user).where('rating IS NOT NULL').average(:rating) || 0)
|
||||
end
|
||||
|
||||
end
|
@ -21,6 +21,7 @@ module ApplicationHelper
|
||||
nav = [
|
||||
nav_item('Recipes', recipes_path, 'recipes'),
|
||||
nav_item('Ingredients', ingredients_path, 'ingredients'),
|
||||
nav_item('Logs', logs_path, 'logs'),
|
||||
nav_item('Calculator', calculator_path, 'calculator'),
|
||||
nav_item('About', about_path, 'home')
|
||||
]
|
||||
|
@ -1,6 +1,6 @@
|
||||
<% @log = decorate(@log, LogDecorator) %>
|
||||
|
||||
<%= form_for([@recipe, @log]) do |f| %>
|
||||
<%= form_for([@recipe, @log], html: {class: 'log-form'}) do |f| %>
|
||||
|
||||
<%= render partial: 'shared/error_list', locals: {model: @log} %>
|
||||
|
||||
@ -44,10 +44,3 @@
|
||||
|
||||
<% end %>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$(document).on("turbolinks:load", function() {
|
||||
$("input.datepicker").datepicker({autoclose: true, todayBtn: "linked", format: "yyyy-mm-dd"});
|
||||
$("input.rating").starRating();
|
||||
});
|
||||
</script>
|
@ -0,0 +1,40 @@
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
|
||||
<div class="page-header">
|
||||
<h1>Log Entries</h1>
|
||||
</div>
|
||||
|
||||
<% if @logs.empty? %>
|
||||
<p>No Entries</p>
|
||||
<% else %>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="log-table table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Recipe</th>
|
||||
<th>Date</th>
|
||||
<th>Rating</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<% decorate(@logs, LogDecorator).each do |log| %>
|
||||
<tr>
|
||||
<td><%= link_to log.recipe.short_name, log %></td>
|
||||
<td><%= log.date %></td>
|
||||
<td><input type="hidden" class="rating" value="<%= log.rating %>" /></td>
|
||||
<td><%= %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,10 +10,11 @@
|
||||
<% else %>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<table class="recipe-table table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Rating</th>
|
||||
<th>Yields</th>
|
||||
<th>Time</th>
|
||||
<th>Created</th>
|
||||
@ -27,6 +28,13 @@
|
||||
<% decorate(@recipes, RecipeDecorator).each do |recipe| %>
|
||||
<tr>
|
||||
<td><%= link_to recipe.short_name, recipe %></td>
|
||||
<td>
|
||||
<% if recipe.average_rating > 0 %>
|
||||
<input type="hidden" class="rating" value="<%= recipe.average_rating %>" />
|
||||
<% else %>
|
||||
--
|
||||
<% end %>
|
||||
</td>
|
||||
<td><%= recipe.yields %></td>
|
||||
<td><%= recipe_time(recipe) %></td>
|
||||
<td><%= timestamp(recipe.created_at) %></td>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<% if model.errors.any? %>
|
||||
<div id="error_explanation" class="alert alert-danger">
|
||||
<h4><%= pluralize(model.errors.count, 'error') %> prohibited this <%= model.class.model_name.human %> from being saved:</h4>
|
||||
<h4><%= pluralize(model.errors.count, 'error') %> prohibited this <%= model.model_name.human %> from being saved:</h4>
|
||||
|
||||
<ul>
|
||||
<% model.errors.full_messages.each do |msg| %>
|
||||
|
@ -1,7 +1,7 @@
|
||||
Rails.application.routes.draw do
|
||||
|
||||
resources :recipes do
|
||||
resources :logs, only: [:index, :new, :create]
|
||||
resources :logs, only: [:new, :create]
|
||||
end
|
||||
|
||||
resources :logs, except: [:new, :create]
|
||||
|
Loading…
Reference in New Issue
Block a user