설명 없음

rubrics-editable-and-custom-do-not-delete.blade.php 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. @extends('layouts.master')
  2. @section('navigation')
  3. @include('local.professors._navigation')
  4. @stop
  5. @section('main')
  6. <div class="row">
  7. <div class="col-md-12">
  8. {{ HTML::linkAction('ActivitiesController@show', 'Back to Activity', array($activity->id), array('class'=>'btn btn-default btn-sm pull-right')) }}
  9. </div>
  10. </div>
  11. <div class="row">
  12. <div class="col-md-12">
  13. <div class="well">
  14. <label>Expected Criteria Outcome</label>
  15. <form class="form-inline">
  16. <input id="activity_id" type="hidden" value="{{{ $activity->id}}}">
  17. <div class="form-group">
  18. <!-- Select percentage. If there is a rubric, select the saved value -->
  19. <select id="expected_percentage" class="form-control">
  20. @for($i = 1; $i <= 20; $i++)
  21. @if($rubric!=NULL && $rubric->expected_percentage == $i*5)
  22. <option selected="selected" value="{{ $i*5 }}">{{ $i*5 }}</option>
  23. @elseif($rubric==NULL && $i*5==70)
  24. <option selected="selected" value="{{ $i*5 }}">{{ $i*5 }}</option>
  25. @else
  26. <option value="{{ $i*5 }}">{{ $i*5 }}</option>
  27. @endif
  28. @endfor
  29. </select>
  30. % of all students must score at least
  31. <!-- Select points. If there is a rubric, select the saved value -->
  32. <select id="expected_points" class="form-control">
  33. @for($i = 1; $i <= 8; $i++)
  34. @if($rubric!=NULL && $rubric->expected_points == $i)
  35. <option selected="selected" value="{{ $i }}">{{ $i }}</option>
  36. @elseif($rubric==NULL && $i==6)
  37. <option selected="selected" value="{{ $i }}">{{ $i }}</option>
  38. @else
  39. <option value="{{ $i }}">{{ $i }}</option>
  40. @endif
  41. @endfor
  42. </select>
  43. point(s) in a criterion for it to pass.
  44. </div>
  45. </form>
  46. <div class="form-group">
  47. <label>Select a Template, or create your own Rubric</label>
  48. <select id="select-template" class="form-control">
  49. <option data-template-id="0">Custom</option>
  50. <optgroup label="Templates">
  51. @foreach ($templates as $template)
  52. <option data-template-id="{{ $template->id }}" class="template">{{ $template->name }}</option>
  53. @endforeach
  54. </optgroup>
  55. <optgroup label="Your Rubrics">
  56. @foreach ($rubrics as $rubric)
  57. <!-- If a rubric already exists for this activity, select it for loading -->
  58. @if ($activity->rubric_id == $rubric->id)
  59. <option selected="selected" data-rubric-id="{{ $rubric->id }}" class="rubric">{{ $rubric->name }}</option>
  60. @else
  61. <option data-rubric-id="{{ $rubric->id }}" class="rubric">{{ $rubric->name }}</option>
  62. @endif
  63. @endforeach
  64. </optgroup>
  65. </select>
  66. </div>
  67. <div class="form-group">
  68. <label>Select a Learning Outcome</label>
  69. <select id="select-outcome" class="form-control">
  70. @foreach ($outcomes as $outcome)
  71. <option data-outcome-id="{{ $outcome->id }}">{{ $outcome->name }}</option>
  72. @endforeach
  73. </select>
  74. </div>
  75. <div class="form-group">
  76. <label>Select a Criterion</label>
  77. <select id="select-criterion" class="form-control">
  78. </select>
  79. </div>
  80. <button id="button-add-criterion" class="btn btn-md btn-primary center-block">Add Criterion to Rubric</button>
  81. </form>
  82. </div>
  83. </div>
  84. </div>
  85. <div id="rubric-container" class="row">
  86. <div class="col-md-12">
  87. @if($activity->rubric_id!=NULL)
  88. <span id="assigned_rubric" class="hidden" data-assigned-rubric="{{{ $activity->rubric_id }}}"></span>
  89. @endif
  90. <table class="table editable-table">
  91. <thead><tr><th colspan="6 "><input id="rubric-name" type="text" class="form-control input-lg" placeholder="Rubric Name"></th></tr></thead>
  92. <thead><tr><th>Criterion</th><th>Beginning (1-2)</th><th>In Progress (3-4)</th><th>Good (5-6)</th><th>Excellent (7-8)</th><th></th></tr></thead>
  93. <tbody>
  94. </tbody>
  95. </table>
  96. <div class="text-center">
  97. <button id="button-save-rubric" class="btn btn-lg btn-primary save">Save</button>
  98. </div>
  99. </div>
  100. </div>
  101. @stop
  102. @section('javascript')
  103. // --------------------------------------------------------------------------
  104. // Page load
  105. // --------------------------------------------------------------------------
  106. // Fetch criteria of first outcome
  107. fetchCriteria($('#select-outcome'));
  108. //
  109. if($('#select-template').find(':selected').data('template-id') == '0')
  110. {
  111. // Hide table
  112. $('#rubric-container').hide();
  113. }
  114. else
  115. {
  116. alert('else');
  117. loadRubric();
  118. }
  119. // Find way to get the original name for use farther below. This doesn't work.
  120. var originalName = $('#rubric-name').val();
  121. alert(originalName);
  122. // --------------------------------------------------------------------------
  123. // Functions
  124. // --------------------------------------------------------------------------
  125. // Fetch criteria associated to a specific learning outcome
  126. function fetchCriteria(outcome)
  127. {
  128. $.post
  129. (
  130. "{{ URL::route('fetchCriteria') }}",
  131. { id: outcome.find(':selected').data('outcome-id')},
  132. function(data)
  133. {
  134. $('#select-criterion').empty();
  135. data.forEach( function (arrayItem)
  136. {
  137. // If criterion does not belong to a user, display it
  138. if(arrayItem.user_id==null)
  139. {
  140. $('#select-criterion')
  141. .append('<option data-criterion-id="'+arrayItem.id+'" >'+arrayItem.name+'</option>');
  142. }
  143. // If it does, but the user is the one logged on, display.
  144. // Otherwise, ignore
  145. else if(arrayItem.user_id!="" && {{{Auth::id()}}}==arrayItem.user_id )
  146. {
  147. $('#select-criterion')
  148. .append('<option data-criterion-id="'+arrayItem.id+'" >'+arrayItem.name+'</option>');
  149. }
  150. });
  151. // Add custom option
  152. $('#select-criterion')
  153. .append('<option data-criterion-id="0">Custom</option>');
  154. $('#select-criterion').prop('disabled', false);
  155. $('#button-add-criterion').prop('disabled', false);
  156. }
  157. );
  158. }
  159. // Add a new criterion to the rubric
  160. function addCriterion()
  161. {
  162. if(!$('tbody').children().length)
  163. {
  164. $('#rubric-container').show();
  165. }
  166. var id= parseInt($('#select-criterion').find(':selected').data('criterion-id'));
  167. // If criterion already exists in the db
  168. if(id!=0)
  169. {
  170. // Check for duplicates
  171. var duplicates=false;
  172. $('tbody tr').each(function()
  173. {
  174. if ($(this).data('criterion-id') == id)
  175. {
  176. duplicates=true;
  177. }
  178. });
  179. if(duplicates)
  180. {
  181. $('#js-error-row').show();
  182. $('#js-error-row').find('#error-message').text('Error: The selected criterion was already added.');
  183. return;
  184. }
  185. else
  186. {
  187. $('#js-error-row').hide();
  188. }
  189. $.post
  190. (
  191. "{{ URL::route('fetchCriterion') }}",
  192. { id: id},
  193. function(data)
  194. {
  195. // If saved criterion is not custom, it can be removed but not edited
  196. if(data.user_id==null)
  197. {
  198. $('table tbody')
  199. .append('<tr data-assoc-outcome-id="'+data.outcome_id+'"'
  200. +'data-criterion-id="'+data.id+'">'
  201. +'<td>'+data.name+'</td>'
  202. +'<td>'+data.description12+'</td>'
  203. +'<td>'+data.description34+'</td>'
  204. +'<td>'+data.description56+'</td>'
  205. +'<td>'+data.description78+'</td>'
  206. +'<th><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></th></tr>');
  207. }
  208. // If saved criterion is custom, it can be removed and edited
  209. else
  210. {
  211. $('table tbody')
  212. .append('<tr data-assoc-outcome-id="'+data.outcome_id+'"'
  213. +'data-criterion-id="0">'
  214. +'<td class="editable" data-type="textarea">Custom</td>'
  215. +'<td class="editable" data-type="textarea"></td>'
  216. +'<td class="editable" data-type="textarea"></td>'
  217. +'<td class="editable" data-type="textarea"></td>'
  218. +'<td class="editable" data-type="textarea"></td>'
  219. +'<th><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></th></tr>');
  220. }
  221. // Enable X-Edtable on this new row
  222. $('.editable').editable({
  223. unsavedclass: null,
  224. rows: "4"
  225. });
  226. }
  227. );
  228. }
  229. // If criterion is completely new and custom
  230. else
  231. {
  232. $('table tbody')
  233. .append('<tr data-assoc-outcome-id="'+$('#select-outcome').find(':selected').data('outcome-id')+'"'
  234. +'data-criterion-id="0">'
  235. +'<td class="editable" data-type="textarea">Custom</td>'
  236. +'<td class="editable" data-type="textarea"></td>'
  237. +'<td class="editable" data-type="textarea"></td>'
  238. +'<td class="editable" data-type="textarea"></td>'
  239. +'<td class="editable" data-type="textarea"></td>'
  240. +'<th><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></th></tr>');
  241. // Enable X-Edtable on this new row
  242. $('.editable').editable({
  243. unsavedclass: null,
  244. rows: "4"
  245. });
  246. }
  247. }
  248. // Fetch single criterion
  249. function fetchCriterion(criterion)
  250. {
  251. $.post
  252. (
  253. "{{ URL::route('fetchCriterion') }}",
  254. { id: outcome.find(':selected').data('outcome-id')},
  255. function(data)
  256. {
  257. $('#select-criterion').empty();
  258. data.forEach( function (arrayItem)
  259. {
  260. $('#select-criterion')
  261. .append('<option data-criterion-id="'+arrayItem.id+'" >'+arrayItem.name+'</option>');
  262. });
  263. $('#select-criterion').append('<option data-criterion-id="0">Custom</option>');
  264. }
  265. );
  266. }
  267. // Load a template
  268. function loadTemplate()
  269. {
  270. // Set expected values to the default 70 / 5
  271. $('#expected_percentage option[value="70"]').prop('selected', true);
  272. $('#expected_points option[value="5"]').prop('selected', true);
  273. $.post
  274. (
  275. "{{ URL::to('loadTemplate') }}",
  276. { id: $('#select-template').find(':selected').data('template-id')},
  277. function(data)
  278. {
  279. // Show the container and empty all rows
  280. $('#rubric-container').show();
  281. $('tbody').empty();
  282. //Set the name of the rubric
  283. $('#rubric-name').val(data.name);
  284. // Set the contents of the rubric
  285. var contents = JSON.parse(data.contents);
  286. contents.forEach(function (criterion)
  287. {
  288. $('table tbody')
  289. .append('<tr data-assoc-outcome-id="'+criterion.outcome_id+'"'
  290. +'data-criterion-id="'+criterion.id+'">'
  291. +'<td>'+criterion.name+'</td>'
  292. +'<td>'+criterion.description12+'</td>'
  293. +'<td>'+criterion.description34+'</td>'
  294. +'<td>'+criterion.description56+'</td>'
  295. +'<td>'+criterion.description78+'</td>'
  296. +'<th></th></tr>');
  297. // Enable X-Edtable on this new row
  298. $('.editable').editable({
  299. unsavedclass: null,
  300. rows: "4"
  301. });
  302. });
  303. }
  304. );
  305. }
  306. // Load a rubric
  307. function loadRubric()
  308. {
  309. $.post
  310. (
  311. "{{ URL::to('professor/loadRubric') }}",
  312. { id: $('#select-template').find(':selected').data('rubric-id')},
  313. function(data)
  314. {
  315. // Show the container and empty all rows
  316. $('#rubric-container').show();
  317. $('tbody').empty();
  318. //Set the name of the rubric
  319. $('#rubric-name').val(data.name);
  320. // Set the contents of the rubric
  321. var contents = JSON.parse(data.contents);
  322. contents.forEach(function (criterion)
  323. {
  324. // If saved criterion is not custom, it can be removed but not edited
  325. if(criterion.user_id==null)
  326. {
  327. $('table tbody')
  328. .append('<tr data-assoc-outcome-id="'+criterion.outcome_id+'"'
  329. +'data-criterion-id="'+criterion.id+'">'
  330. +'<td>'+criterion.name+'</td>'
  331. +'<td>'+criterion.description12+'</td>'
  332. +'<td>'+criterion.description34+'</td>'
  333. +'<td>'+criterion.description56+'</td>'
  334. +'<td>'+criterion.description78+'</td>'
  335. +'<th><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></th></tr>');
  336. }
  337. // If saved criterion is custom, it can be removed and edited
  338. else
  339. {
  340. $('table tbody')
  341. .append('<tr data-assoc-outcome-id="'+criterion.outcome_id+'"'
  342. +'data-criterion-id="0">'
  343. +'<td class="editable" data-type="textarea">Custom</td>'
  344. +'<td class="editable" data-type="textarea"></td>'
  345. +'<td class="editable" data-type="textarea"></td>'
  346. +'<td class="editable" data-type="textarea"></td>'
  347. +'<td class="editable" data-type="textarea"></td>'
  348. +'<th><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></th></tr>');
  349. }
  350. // Enable X-Edtable on this new row
  351. $('.editable').editable({
  352. unsavedclass: null,
  353. rows: "4"
  354. });
  355. });
  356. }
  357. );
  358. }
  359. // Checks whether the user wants to save a rubric with a name that already exists
  360. function nameExists()
  361. {
  362. var duplicates = false;
  363. $('#select-template option').each(function()
  364. {
  365. if($('#rubric-name').val().trim()===$(this).text().trim())
  366. {
  367. duplicates = true;
  368. return;
  369. }
  370. });
  371. return duplicates;
  372. }
  373. // --------------------------------------------------------------------------
  374. // Events
  375. // --------------------------------------------------------------------------
  376. // When trying to change the template, ask the user to confirm and reset the
  377. // rubric if s/he does
  378. $('#select-template').on('change', function()
  379. {
  380. // If changing to custom template, reset
  381. if($('#select-template').find(':selected').data('template-id')=='0')
  382. {
  383. $('#rubric-container').hide();
  384. $('#rubric-name').val('');
  385. $('tbody').empty();
  386. }
  387. // Otherwise, load the selected template/rubric
  388. else
  389. {
  390. if($('#select-template').find(':selected').hasClass('template'))
  391. {
  392. loadTemplate();
  393. }
  394. else
  395. {
  396. loadRubric();
  397. }
  398. }
  399. });
  400. // When a learning outcome changes, update its criteria
  401. $('#select-outcome').on('change', function()
  402. {
  403. fetchCriteria($(this));
  404. });
  405. // When the add button is clicked
  406. $('#button-add-criterion').on('click', function(e)
  407. {
  408. //Prevent page refresh
  409. e.preventDefault();
  410. //Add new criterion
  411. addCriterion();
  412. });
  413. // When save button is clicked
  414. $('#button-save-rubric').on('click', function(e)
  415. {
  416. //Prevent page refresh
  417. e.preventDefault();
  418. // Empty field validation
  419. var emptyFields=false;
  420. $('td').each(function()
  421. {
  422. if ($(this).text() == "" || $(this).text() == "Empty")
  423. {
  424. emptyFields=true;
  425. }
  426. });
  427. // If any fields are empty, display error and return
  428. if(emptyFields || $.trim($('#rubric-name').val())=='')
  429. {
  430. $('#js-error-row').show();
  431. $('#js-error-row').find('#error-message').text('Error: Please fill all the fields.');
  432. return;
  433. }
  434. else
  435. {
  436. $('#js-error-row').hide();
  437. }
  438. //---------------------------------------------------vvv-------------------------------------------------------------------
  439. //TODO update assessments
  440. var criterionObject = new Object();
  441. var criteriaArray = new Array();
  442. // For each criterion in the rubric, get its value and put it into an array
  443. $('tbody tr').each(function( index )
  444. {
  445. criterionObject.id = $(this).data('criterion-id');
  446. criterionObject.outcome_id = $(this).data('assoc-outcome-id');
  447. criterionObject.name = $(this).children('td:nth-child(1)').text();
  448. criterionObject.description12 = $(this).children('td:nth-child(2)').text();
  449. criterionObject.description34 = $(this).children('td:nth-child(3)').text();
  450. criterionObject.description56 = $(this).children('td:nth-child(4)').text();
  451. criterionObject.description78 = $(this).children('td:nth-child(5)').text();
  452. // Clone the object and push it into the array
  453. var clone = jQuery.extend({}, criterionObject);
  454. criteriaArray.push(clone);
  455. });
  456. // If activity does not have a rubric, create it
  457. if($('#assigned_rubric').length === 0)
  458. {
  459. // Check whether a rubric with the written name already exists
  460. // If it does, display an error.
  461. if(nameExists())
  462. {
  463. $('#js-error-row').show();
  464. $('#js-error-row').find('#error-message').text('Error: A rubric or template with that name already exists.');
  465. return;
  466. }
  467. $('#js-error-row').hide();
  468. // Create
  469. $.post
  470. (
  471. "{{ URL::to('professor/saveRubric') }}",
  472. {
  473. name: $('#rubric-name').val(),
  474. activity_id: parseInt($('#activity_id').val()),
  475. contents: JSON.stringify(criteriaArray),
  476. expected_percentage: $('#expected_percentage').find(':selected').val(),
  477. expected_points: $('#expected_points').find(':selected').val()
  478. },
  479. function(data)
  480. {
  481. location.reload(true);
  482. }
  483. );
  484. }
  485. // Else, update it
  486. else
  487. {
  488. // Check whether a rubric with the written name already exists and if the
  489. // selected template's id equals assigned id. If the name exists, but the
  490. // ids don't match, show error
  491. alert(originalName);
  492. if(originalName != $('#rubric-name').val() && nameExists())
  493. {
  494. $('#js-error-row').show();
  495. $('#js-error-row').find('#error-message').text('Error: You must change the name of the rubric.');
  496. return;
  497. }
  498. $('#js-error-row').hide();
  499. // Update database
  500. $.post
  501. (
  502. "{{ URL::to('professor/updateRubric') }}",
  503. {
  504. id: $('#assigned_rubric').data('assigned-rubric'),
  505. name: $('#rubric-name').val(),
  506. contents: JSON.stringify(criteriaArray),
  507. expected_percentage: $('#expected_percentage').find(':selected').val(),
  508. expected_points: $('#expected_points').find(':selected').val()
  509. },
  510. function(data)
  511. {
  512. location.reload();
  513. }
  514. );
  515. }
  516. });
  517. //-----------------------------------------------------^^^------------------------------------------------------------------
  518. // TODO Move this somewhere else
  519. // When the delete button is clicked
  520. $('#button-delete-rubric').on('click', function(e)
  521. {
  522. // Delete from database
  523. $.post
  524. (
  525. "{{ URL::to('professor/deleteRubric') }}",
  526. {
  527. id: $('#select-template').find(':selected').data('rubric-id')
  528. },
  529. function(data)
  530. {
  531. location.reload();
  532. }
  533. );
  534. });
  535. // Remove a criterion and hide the table if it was the only one
  536. $('table').on('click', '.glyphicon-remove', function(e)
  537. {
  538. $(this).closest('tr').remove();
  539. if(!$('tbody').children().length)
  540. {
  541. $('#rubric-container').hide();
  542. }
  543. });
  544. @stop