Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Evaluations - Comments tab work

 * It is finally complete and working pretty well.  Closes #11
 * Allows for drag-and-drop functionality with Quick Messages
 * Auto-replaces keywords in the quick messages.  Currently only "%fn = Student First Name" is implemented.
  • Loading branch information...
commit bfad948b2be1ba5758d8775cec955a97f39ae4d9 1 parent e09ea0f
Richard Hurt authored
13 app/controllers/evaluations_controller.rb
View
@@ -64,8 +64,16 @@ def update
else
evaluation.points_earned = params[:score]
end
+
elsif params[:comment]
-
+ evaluation = Comment.find_or_create_by_user_id_and_commentable_id(params[:student], params[:id])
+
+ # If the comment is empty then delete the evaluation
+ if params[:comment].empty?
+ Comment.destroy(evaluation)
+ else
+ evaluation.content = params[:comment]
+ end
end
# Save the record
@@ -77,6 +85,9 @@ def update
elsif params[:assignment]
grade = CourseTerm.find(params[:id]).calculate_grade(params[:student])
render :text => "#{grade[:letter]} (#{grade[:score].round}%)", :status => status
+ elsif params[:comment]
+ student = Student.find(params[:student])
+ render :text => "YOU SUCK"
end
}
end
49 app/helpers/evaluation_helper.rb
View
@@ -162,21 +162,42 @@ def comments_body
body << "<tr><td>No Students Found</td></tr>"
else
students.each_with_index do |student, index|
- body << "<tr class='calc #{cycle('odd','even')}' id='s#{student.id}'>"
+ comment = Comment.find_by_user_id_and_commentable_id(student.id, @course_term.id.to_s)
+
+ body << "<tr class='calc #{cycle('odd','even')}' id='comment#{student.id}'>"
body << "<td width='120'>#{student.full_name}</td>"
- body << "<td><input id='c#{student.id}' type='text' value='Comments go here' size='45' /></td>"
- body << '</tr>'
- body += drop_receiving_element("s#{student.id}",
- :method => :put,
- :url => {:student => student.id,
- :controller => "evaluations",
- :action => "update"},
- :with => "'comment=' + element.innerHTML",
- :onDrop => "function(draggable_element, droppable_element, event)
- { new_comment = draggable_element.innerHTML.gsub('%fn', droppable_element.childNodes[0].childNodes[0].textContent.split(' ',1));
- droppable_element.childNodes[1].childNodes[0].setValue(new_comment);
- }",
+ body << "<td><input id='c#{student.id}' type='text' value='"
+ body += comment.content if comment
+ body << "' tabindex=#{index} size='50' "
+
+ # Build the remote_function by hand
+ body += <<END
+onchange="new Ajax.Request('/evaluations/#{@course_term.id}',
+ {asynchronous:true, evalScripts:true, method:'put', onComplete:function(request){update_comment_status('complete', #{student.id})},
+ onFailure:function(request){update_comment_status('failure', #{student.id})},
+ onLoading:function(request){update_comment_status('loading', #{student.id})},
+ onSuccess:function(request){update_comment_status('success', #{student.id})},
+ parameters:'student=#{student.id}&amp;comment=' + encodeURIComponent(value) + '&amp;authenticity_token=' + encodeURIComponent('#{form_authenticity_token}')})"
+END
+ body << ' /> </td>'
+
+
+ body += drop_receiving_element("comment#{student.id}",
+ :onDrop => "function(draggable_element, droppable_element, event) {
+ new_comment = draggable_element.innerHTML.gsub('%fn', droppable_element.childNodes[0].childNodes[0].textContent.split(' ',1));
+ droppable_element.childNodes[1].childNodes[0].setValue(new_comment);
+ droppable_element.childNodes[1].childNodes[0].simulate('change');}",
:hoverclass => 'current')
+
+ # Build the drop_receiving_element javascript by hand
+ # OPTIMIZE: This code doesn't quite work for some reason...
+ # body << "<script type='text/javascript'>//<![CDATA[ "
+ # body << "Droppables.add('comment#{student.id}', {hoverclass:'current', onDrop:function(draggable_element, droppable_element, event) {"
+ # body << " new_comment = draggable_element.innerHTML.gsub('%fn', droppable_element.childNodes[0].childNodes[0].textContent.split(' ',1));"
+ # body << " droppable_element.childNodes[1].childNodes[0].setValue(new_comment);"
+ # body << " droppable_element.childNodes[1].childNodes[0].simulate('change');}}) "
+ # body << '//]]></script>'
+ body << '</tr>'
end
end
@@ -191,7 +212,7 @@ def quick_comments_body
body << "<td><div id='qc#{comment.id}'>#{comment.content}</div></td>"
body += draggable_element("qc#{comment.id}",
- :revert => true, :ghosting => true,
+ :revert => true, :ghosting => true, :scroll => :window,
:reverteffect => "function(element, top_offset, left_offset) { new Effect.MoveBy(element, -top_offset, -left_offset, {duration:0});}")
body << '</tr>'
end
11 app/views/evaluations/_comments.html.erb
View
@@ -1,17 +1,12 @@
<div class="span-14">
<form id="comments_grid">
- <table class='master fixed-grid fixed-grid-header'>
- <thead>
+ <div>
+ <table class="fixed-grid master">
+ <thead>
<tr>
<th width='100'>Student Name</th>
<th>Comments</th>
</tr>
- </thead>
- </table>
-
- <div class='fixed-table'>
- <table class="fixed-grid master">
- <thead>
</thead>
<tbody>
<%= comments_body %>
87 app/views/evaluations/_display.js
View
@@ -34,6 +34,39 @@ window.update_grade_status = function(mode, student_id, assignment_id) {
}
}
+// Change the look of a cell depending on the value entered by the user
+window.cell_status = function(e){
+ var avail_points = parseFloat(e.readAttribute('points')); // How many points is this assignment worth?
+ var grade_value = e.getValue(); // What grade did the user enter?
+
+ // Did the user enter a number or a letter?
+ score = parseFloat(grade_value);
+ if (isNaN(score)) {
+ // Its not a number so look for any 'special' grades
+ switch(grade_value.toUpperCase()) {
+ case 'M': // This is a missing grade and it is counted as a 0
+ e.addClassName('grade-warning');
+
+ break;
+ case 'E': // This is an excused grade and it is ignored
+ e.addClassName('grade-warning');
+
+ break;
+ case '': // This is a blank grade
+ e.addClassName('grade-empty');
+
+ break;
+ default: // This is an invalid grade
+ e.addClassName('grade-error');
+ }
+ } else {
+ // Warn the user about any out of the ordinary grades (too large/small)
+ if (score > avail_points || (score / avail_points) < .40) {
+ e.addClassName('grade-warning');
+ }
+ }
+}
+
window.update_skill_status = function(mode, student_id, skill_id) {
// Define the objects we need
var skill = $('s' + student_id + 'k' + skill_id) // Get the "skill" object
@@ -65,39 +98,39 @@ window.update_skill_status = function(mode, student_id, skill_id) {
break;
}
-
}
-// Change the look of a cell depending on the value entered by the user
-window.cell_status = function(e){
- var avail_points = parseFloat(e.readAttribute('points')); // How many points is this assignment worth?
- var grade_value = e.getValue(); // What grade did the user enter?
- // Did the user enter a number or a letter?
- score = parseFloat(grade_value);
- if (isNaN(score)) {
- // Its not a number so look for any 'special' grades
- switch(grade_value.toUpperCase()) {
- case 'M': // This is a missing grade and it is counted as a 0
- e.addClassName('grade-warning');
+window.update_comment_status = function(mode, student_id) {
+ // Define the objects we need
+ var comment = $('c' + student_id) // Get the "comment" object
- break;
- case 'E': // This is an excused grade and it is ignored
- e.addClassName('grade-warning');
+ // Reset any CSS names
+ comment.removeClassName('grade-warning');
+ comment.removeClassName('grade-error');
+ comment.removeClassName('grade-empty');
- break;
- case '': // This is a blank grade
- e.addClassName('grade-empty');
+ switch (mode) {
+ case('loading'):
+ // Begin the update process...
+ comment.addClassName('grade-updating');
- break;
- default: // This is an invalid grade
- e.addClassName('grade-error');
- }
- } else {
- // Warn the user about any out of the ordinary grades (too large/small)
- if (score > avail_points || (score / avail_points) < .40) {
- e.addClassName('grade-warning');
- }
+ break;
+ case('success'):
+ // Data was saved successfully
+ comment.removeClassName('grade-error');
+ break;
+ case('failure'):
+ // Data did not save successfully
+ comment.addClassName('grade-error');
+
+ break;
+ case('complete'):
+ // Update is complete
+ comment.removeClassName('grade-updating');
+
+ break;
}
}
+
8 app/views/evaluations/_form_control.js
View
@@ -4,15 +4,13 @@ window.processPage = function(mode) {
controlKeyboard('grade_grid');
restrictSubmit('grade_grid');
$('grade_grid').getInputs().each(cell_status);
-
} else if (mode == 'skills') {
controlKeyboard('skills_grid');
restrictSubmit('skills_grid');
-
} else if (mode == 'comments'){
- } else {
- alert("WARNING - mode not defined: " + mode);
- }
+ controlKeyboard('comments_grid');
+ restrictSubmit('comments_grid');
+ } else { alert("WARNING - mode not defined: " + mode); }
$('loading').hide();
}
2  app/views/layouts/application.html.erb
View
@@ -9,7 +9,7 @@
<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype" -%>
<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.2/scriptaculous" -%>
- <%= javascript_include_tag 'livepipe', 'tabs', 'scal', 'tablekit', 'application', :cache => false -%>
+ <%= javascript_include_tag 'livepipe', 'tabs', 'scal', 'tablekit', 'event.simulate', 'application', :cache => false -%>
<% javascript_tag do %>
TableKit.options.rowEvenClass = 'even';
TableKit.options.rowOddClass = 'odd';
20 public/javascripts/event.simulate.js
View
@@ -0,0 +1,20 @@
+/**
+ * Event.simulate(@element, eventName[, options]) -> Element
+ *
+ * - @element: element to fire event on
+ * - eventName: name of event to fire (only MouseEvents and HTMLEvents interfaces are supported)
+ * - options: optional object to fine-tune event properties - pointerX, pointerY, ctrlKey, etc.
+ *
+ * $('foo').simulate('click'); // => fires "click" event on an element with id=foo
+ *
+ **/
+(function(){var eventMatchers={'HTMLEvents':/^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,'MouseEvents':/^(?:click|mouse(?:down|up|over|move|out))$/}
+var defaultOptions={pointerX:0,pointerY:0,button:0,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false,bubbles:true,cancelable:true}
+Event.simulate=function(element,eventName){var options=Object.extend(defaultOptions,arguments[2]||{});var oEvent,eventType=null;element=$(element);for(var name in eventMatchers){if(eventMatchers[name].test(eventName)){eventType=name;break;}}
+if(!eventType)
+throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported');if(document.createEvent){oEvent=document.createEvent(eventType);if(eventType=='HTMLEvents'){oEvent.initEvent(eventName,options.bubbles,options.cancelable);}
+else{oEvent.initMouseEvent(eventName,options.bubbles,options.cancelable,document.defaultView,options.button,options.pointerX,options.pointerY,options.pointerX,options.pointerY,options.ctrlKey,options.altKey,options.shiftKey,options.metaKey,options.button,element);}
+element.dispatchEvent(oEvent);}
+else{options.clientX=options.pointerX;options.clientY=options.pointerY;oEvent=Object.extend(document.createEventObject(),options);element.fireEvent('on'+eventName,oEvent);}
+return element;}
+Element.addMethods({simulate:Event.simulate});})()
Please sign in to comment.
Something went wrong with that request. Please try again.