diff --git a/app/assets/javascripts/exercise_collections.js.erb b/app/assets/javascripts/exercise_collections.js.erb
index 3530b636..0784f9ac 100644
--- a/app/assets/javascripts/exercise_collections.js.erb
+++ b/app/assets/javascripts/exercise_collections.js.erb
@@ -1,102 +1,135 @@
$(function() {
if ($.isController('exercise_collections')) {
- var data = $('#data').data('working-times');
- var averageWorkingTimeValue = parseFloat($('#data').data('average-working-time'));
+ var data = $('#data');
+ var exerciseList = $('#exercise-list');
- var margin = { top: 30, right: 40, bottom: 30, left: 50 },
- width = 720 - margin.left - margin.right,
- height = 500 - margin.top - margin.bottom;
+ if (data.isPresent()) {
+ data.data('working-times');
+ var averageWorkingTimeValue = parseFloat(data.data('average-working-time'));
- var x = d3.scaleBand().range([0, width]);
- var y = d3.scaleLinear().range([height, 0]);
+ var margin = {top: 30, right: 40, bottom: 30, left: 50},
+ width = 720 - margin.left - margin.right,
+ height = 500 - margin.top - margin.bottom;
- var xAxis = d3.axisBottom(x);
- var yAxisLeft = d3.axisLeft(y);
+ var x = d3.scaleBand().range([0, width]);
+ var y = d3.scaleLinear().range([height, 0]);
- var tooltip = d3.select("#graph").append("div").attr("class", "exercise-id-tooltip");
+ var xAxis = d3.axisBottom(x);
+ var yAxisLeft = d3.axisLeft(y);
- var averageWorkingTime = d3.line()
- .x(function (d) { return x(d.index) + x.bandwidth()/2; })
- .y(function () { return y(averageWorkingTimeValue); });
+ var tooltip = d3.select("#graph").append("div").attr("class", "exercise-id-tooltip");
- var minWorkingTime = d3.line()
- .x(function (d) { return x(d.index) + x.bandwidth()/2; })
- .y(function () { return y(0.1*averageWorkingTimeValue); });
+ var averageWorkingTime = d3.line()
+ .x(function (d) {
+ return x(d.index) + x.bandwidth() / 2;
+ })
+ .y(function () {
+ return y(averageWorkingTimeValue);
+ });
- var maxWorkingTime = d3.line()
- .x(function (d) { return x(d.index) + x.bandwidth()/2; })
- .y(function () { return y(2*averageWorkingTimeValue); });
+ var minWorkingTime = d3.line()
+ .x(function (d) {
+ return x(d.index) + x.bandwidth() / 2;
+ })
+ .y(function () {
+ return y(0.1 * averageWorkingTimeValue);
+ });
- var svg = d3.select('#graph')
- .append("svg")
- .attr("width", width + margin.left + margin.right)
- .attr("height", height + margin.top + margin.bottom)
- .append("g")
- .attr("transform",
- "translate(" + margin.left + "," + margin.top + ")");
+ var maxWorkingTime = d3.line()
+ .x(function (d) {
+ return x(d.index) + x.bandwidth() / 2;
+ })
+ .y(function () {
+ return y(2 * averageWorkingTimeValue);
+ });
- // Get the data
- data = Object.keys(data).map(function (key, index) {
- return {
- index: index,
- exercise_id: parseInt(key),
- working_time: parseFloat(data[key])
- };
- });
+ var svg = d3.select('#graph')
+ .append("svg")
+ .attr("width", width + margin.left + margin.right)
+ .attr("height", height + margin.top + margin.bottom)
+ .append("g")
+ .attr("transform",
+ "translate(" + margin.left + "," + margin.top + ")");
- // Scale the range of the data
- x.domain(data.map(function (d) { return d.index; }));
- y.domain([0, d3.max(data, function (d) { return d.working_time; })]);
+ // Get the data
+ data = Object.keys(data).map(function (key, index) {
+ return {
+ index: index,
+ exercise_id: parseInt(key),
+ working_time: parseFloat(data[key])
+ };
+ });
- // Add the X Axis
- svg.append("g")
- .attr("class", "x axis")
- .attr("transform", "translate(0," + height + ")")
- .call(xAxis);
+ // Scale the range of the data
+ x.domain(data.map(function (d) {
+ return d.index;
+ }));
+ y.domain([0, d3.max(data, function (d) {
+ return d.working_time;
+ })]);
- // Add the Y Axis
- svg.append("g")
- .attr("class", "y axis")
- .style("fill", "steelblue")
- .call(yAxisLeft);
+ // Add the X Axis
+ svg.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0," + height + ")")
+ .call(xAxis);
- // Draw the bars
- svg.selectAll("bar")
- .data(data)
- .enter()
- .append("rect")
- .attr("class", "value-bar")
- .on("mousemove", function (d){
- tooltip
- .style("left", d3.event.pageX - 50 + "px")
- .style("top", d3.event.pageY + 50 + "px")
- .style("display", "inline-block")
- .html("<%= I18n.t('activerecord.models.exercise.one') %> ID: " + d.exercise_id + "
" +
- "<%= I18n.t('exercises.statistics.average_worktime') %>: " + d.working_time + "s");
- })
- .on("mouseout", function (){ tooltip.style("display", "none");})
- .on("click", function (d) {
- window.location.href = "/exercises/" + d.exercise_id + "/statistics";
- })
- .attr("x", function (d) { return x(d.index); })
- .attr("width", x.bandwidth())
- .attr("y", function (d) { return y(d.working_time); })
- .attr("height", function (d) { return height - y(d.working_time); });
+ // Add the Y Axis
+ svg.append("g")
+ .attr("class", "y axis")
+ .style("fill", "steelblue")
+ .call(yAxisLeft);
- // Add the average working time path
- svg.append("path")
- .datum(data)
- .attr("class", "line average-working-time")
- .attr("d", averageWorkingTime);
+ // Draw the bars
+ svg.selectAll("bar")
+ .data(data)
+ .enter()
+ .append("rect")
+ .attr("class", "value-bar")
+ .on("mousemove", function (d) {
+ tooltip
+ .style("left", d3.event.pageX - 50 + "px")
+ .style("top", d3.event.pageY + 50 + "px")
+ .style("display", "inline-block")
+ .html("<%= I18n.t('activerecord.models.exercise.one') %> ID: " + d.exercise_id + "
" +
+ "<%= I18n.t('exercises.statistics.average_worktime') %>: " + d.working_time + "s");
+ })
+ .on("mouseout", function () {
+ tooltip.style("display", "none");
+ })
+ .on("click", function (d) {
+ window.location.href = "/exercises/" + d.exercise_id + "/statistics";
+ })
+ .attr("x", function (d) {
+ return x(d.index);
+ })
+ .attr("width", x.bandwidth())
+ .attr("y", function (d) {
+ return y(d.working_time);
+ })
+ .attr("height", function (d) {
+ return height - y(d.working_time);
+ });
- // Add the anomaly paths (min/max average exercise working time)
- svg.append("path")
- .datum(data)
- .attr("class", "line minimum-working-time")
- .attr("d", minWorkingTime);
- svg.append("path")
- .datum(data)
- .attr("class", "line maximum-working-time")
- .attr("d", maxWorkingTime);
+ // Add the average working time path
+ svg.append("path")
+ .datum(data)
+ .attr("class", "line average-working-time")
+ .attr("d", averageWorkingTime);
+
+ // Add the anomaly paths (min/max average exercise working time)
+ svg.append("path")
+ .datum(data)
+ .attr("class", "line minimum-working-time")
+ .attr("d", minWorkingTime);
+ svg.append("path")
+ .datum(data)
+ .attr("class", "line maximum-working-time")
+ .attr("d", maxWorkingTime);
+ } else if (exerciseList.isPresent()) {
+ var list = $("#sortable");
+ list.sortable();
+ list.disableSelection();
+ }
}
});
diff --git a/app/views/exercise_collections/_form.html.slim b/app/views/exercise_collections/_form.html.slim
index c204db47..b7249267 100644
--- a/app/views/exercise_collections/_form.html.slim
+++ b/app/views/exercise_collections/_form.html.slim
@@ -15,4 +15,24 @@
.form-group
= f.label(t('activerecord.attributes.exercise_collections.exercises'))
= f.collection_select(:exercise_ids, exercises, :id, :title, {}, {class: 'form-control', multiple: true})
+
+ .table-responsive#exercise-list
+ table.table
+ thead
+ tr
+ th
+ th = t('activerecord.attributes.exercise_collection_item.exercise')
+ th = t('activerecord.attributes.exercise.user')
+ th colspan=2 = t('shared.actions')
+ tbody#sortable
+ - @exercise_collection.items.order(:position).each do |item|
+ tr
+ td
+ span.fa.fa-bars
+ td = item.exercise.title
+ td = item.exercise.author
+ td = link_to(t('shared.show'), item.exercise)
+ td
+ a.remove-exercise href="#" = t('shared.destroy')
+
.actions = render('shared/submit_button', f: f, object: @exercise_collection)
diff --git a/config/locales/de.yml b/config/locales/de.yml
index c3f7dc15..e62dbd47 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -131,6 +131,8 @@ de:
user: "Autor"
exercise: "Aufgabe"
feedback_text: "Feedback Text"
+ exercise_collection_item:
+ exercise: "Aufgabe"
models:
code_harbor_link:
one: CodeHarbor-Link
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 494dd163..842dd346 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -131,6 +131,8 @@ en:
user: "Author"
exercise: "Exercise"
feedback_text: "Feedback Text"
+ exercise_collection_item:
+ exercise: "Exercise"
models:
code_harbor_link:
one: CodeHarbor Link