diff --git a/grade/report/grader/index.php b/grade/report/grader/index.php
index 66b944772c7..85e6776b9de 100644
--- a/grade/report/grader/index.php
+++ b/grade/report/grader/index.php
@@ -52,7 +52,8 @@ if (isset($graderreportsilast)) {
}
$PAGE->set_url(new moodle_url('/grade/report/grader/index.php', array('id'=>$courseid)));
-$PAGE->requires->yui_module('moodle-gradereport_grader-scrollview', 'M.gradereport_grader.scrollview.init');
+//$PAGE->requires->yui_module('moodle-gradereport_grader-scrollview', 'M.gradereport_grader.scrollview.init');
+$PAGE->requires->yui_module('moodle-gradereport_grader-gradereporttable', 'M.gradereport_grader.gradereporttable.init', array());
// basic access checks
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
@@ -193,6 +194,15 @@ if ($USER->gradeediting[$course->id] && ($report->get_pref('showquickfeedback')
echo $reporthtml;
}
+// Render a loading screen.
+$loading = html_writer::div(
+ html_writer::div(
+ '', 'gradebook-loading'
+ ), 'gradebook-loading-screen', array('aria-hidden' => 'true')
+ );
+
+echo $loading;
+
// prints paging bar at bottom for large pages
if (!empty($studentsperpage) && $studentsperpage >= 20) {
echo $OUTPUT->paging_bar($numusers, $report->page, $studentsperpage, $report->pbarurl);
diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index cf02a6ee5db..2ad04b3a118 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -1137,7 +1137,7 @@ class grade_report_grader extends grade_report {
$html .= $OUTPUT->container(html_writer::table($righttable), 'right_scroller');
} else {
$fulltable = new html_table();
- $fulltable->attributes['class'] = 'gradestable flexible boxaligncenter generaltable';
+ $fulltable->attributes['class'] = 'table table-bordered table-striped table-condensed';
$fulltable->id = 'user-grades';
// Extract rows from each side (left and right) and collate them into one row each
diff --git a/grade/report/grader/module.js b/grade/report/grader/module.js
index 6263883d05d..e760ce9fc56 100644
--- a/grade/report/grader/module.js
+++ b/grade/report/grader/module.js
@@ -56,7 +56,8 @@ M.gradereport_grader = {
return;
}
- var content = '
';
+ var overriden = /.*overridden.*/g.test(properties.cell.getAttribute('class')) ? 'overriden' : '';
+ var content = '
';
content += '
'+properties.username+'
'+properties.itemname+'
';
if (properties.feedback) {
content += '
'+properties.feedback+'
';
diff --git a/grade/report/grader/pix/corner-fold.png b/grade/report/grader/pix/corner-fold.png
new file mode 100644
index 00000000000..14f7089f4cf
Binary files /dev/null and b/grade/report/grader/pix/corner-fold.png differ
diff --git a/grade/report/grader/styles.css b/grade/report/grader/styles.css
index 671817b79c7..d11d789a716 100644
--- a/grade/report/grader/styles.css
+++ b/grade/report/grader/styles.css
@@ -1,75 +1,142 @@
-.path-grade-report-grader .flexible th {
- white-space: normal;
+.path-grade-report-grader .yui3-overlay {
+ border: 0;
+ background: none;
+ background-color: 'initial';
+ min-width: 200px;
}
-.gradestable {
- margin-bottom: 0;
+.path-grade-report-grader .graderreportoverlay {
+ background-color: white;
+ width: auto;
+ padding: 10px;
+ border-color: #ddd;
+ font-size: 12px;
+ -webkit-box-shadow: #999999 2px 2px 3px;
+ -moz-box-shadow: #999999 2px 2px 3px;
+ box-shadow: #999999 2px 2px 3px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -ms-border-radius: 4px;
+ -o-border-radius: 4px;
+ border-radius: 4px;
}
-.gradestable th.user img {
- width: 20px;
- height: 20px;
+.path-grade-report-grader .graderreportoverlay.overriden {
+ border-top: 22px solid #f1c32a;
}
-.gradestable th img {
- vertical-align: text-bottom;
- padding-bottom: 0;
+.path-grade-report-grader .graderreportoverlay.overriden:before {
+ font-size: 12px;
+ content: "Overridden grade";
+ color: black;
+ height: 0px;
+ width: 100%;
+ display: inline-block;
+ text-align: center;
+ top: -32px;
+ float: left;
+ position: relative;
}
-.gradestable th .grade_icons {
- margin-top: .3em;
+.path-grade-report-grader .graderreportoverlay .overriden {
+ background-color: #f1c32a;
+ width: 100%;
+ text-align: center;
}
-.gradestable th img.sorticon {
- margin-left: .3em;
+.path-grade-report-grader .graderreportoverlay .fullname {
+ color: #444;
}
-.dir-rtl .gradestable th img.sorticon {
- margin-left: 0;
- margin-right: .3em;
+.path-grade-report-grader .graderreportoverlay .itemname {
+ padding-top: 4px;
+ color: #666;
}
-table#user-grades .catlevel2 {
- background-color: #f9f9f9;
+.path-grade-report-grader .gradeparent {
+ overflow: inherit;
}
-table#user-grades tr.range td.cell {
- font-weight: 700;
+
+table#user-grades {
+ font-size: 14px;
}
-table#user-grades tr.avg td.cell {
- background-color: #efefff;
- font-weight: 700;
- color: #00008B;
+table#user-grades .avg th,
+table#user-grades .avg td,
+table#user-grades .heading th {
+ font-weight: bold;
+ background-color: #333;
+ color: #ddd;
+ border-color: #444;
}
-table#user-grades tr.odd td.cell {
- background-color: #efefef;
- white-space: nowrap;
+table#user-grades .avg th a,
+table#user-grades .avg td a,
+table#user-grades .heading th a {
+ color: white;
+ font-weight: normal;
}
-table#user-grades tr td.overridden {
- background-color: #F3E4C0;
+table#user-grades .avg .cell {
+ font-weight: bold;
+ text-align: center;
}
-table#user-grades tr.odd td.overridden {
- background-color: #EFD9A4;
+table#user-grades .avg .cell.header {
+ text-align: right;
}
-table#user-grades tr td.ajaxoverridden {
- background-color: #FFE3A0;
+table#user-grades th {
+ font-weight: normal;
}
-table#user-grades tr.odd td.ajaxoverridden {
- background-color: #FFDA83;
+table#user-grades th.cell {
+ height: 20px;
+ white-space: nowrap;
}
-table#user-grades tr.even td.excluded {
- background-color: #EABFFF;
+.path-grade-report-history table#user-grades th.cell {
+ white-space: normal;
}
-table#user-grades tr.odd td.excluded {
- background-color: #E5AFFF;
+table#user-grades .controls {
+ text-align: right;
+ background-color: #eee;
+ height: 20px;
}
-table#user-grades tr.odd th.header {
- background-color: #efefef;
- background-image: none;
+table#user-grades tr {
+ height: 40px;
}
-table#user-grades tr.even th.header {
- background-image: none;
+table#user-grades tr .gradevalue {
+ width: 100%;
+ text-align: center;
+ display: inline-block;
}
-table#user-grades tr.groupavg td.cell {
- background-color: #efffef;
- font-weight: 700;
- color: #006400;
+table#user-grades tr .user {
+ min-width: 200px;
+ max-width: 200px;
+ width: 200px;
+ background-color: #777777;
+ border-color: #666666;
}
-table#user-grades td.cat,
-table#user-grades td.course {
- font-weight: 700;
+table#user-grades tr .user a {
+ color: white;
+}
+table#user-grades tr .user .userpicture {
+ display: none;
+}
+table#user-grades tr.odd td.grade.vmarked {
+ background-color: #f39a00;
+ border-bottom-color: #f39a00;
+}
+table#user-grades tr.odd td.grade.vmarked.overridden {
+ background-color: #f39a00;
+}
+table#user-grades tr.odd td.grade.hmarked {
+ background-color: #f5cd00;
+ border-bottom-color: #f5cd00;
+}
+table#user-grades tr.odd td.grade.hmarked.overridden {
+ background-color: #f5cd00;
+}
+table#user-grades tr.odd td.grade.vmarked.hmarked {
+ background-color: #f1b900;
+ border-bottom-color: #f1b900;
+}
+table#user-grades tr.odd td.grade.vmarked.hmarked.overridden {
+ background-color: #f1b900;
+}
+table#user-grades tr.odd td.grade.overridden {
+ background-color: #fff;
+ background: url([[pix:gradereport_grader|corner-fold]]) no-repeat;
+ width: 16px;
+ height: 16px;
+ background-color: #efefef;
}
table#user-grades {
font-size: 10px;
@@ -411,110 +478,36 @@ tr.groupavg th.header {
.path-grade-report-grader .heading_name_row th {
white-space: nowrap;
width: 2000px;
+table#user-grades tr.even td.grade.vmarked {
+ background-color: #f4a400;
+ border-bottom-color: #f4a400;
}
-
-/*MDL-21088 - IE 7 ignores nowraps on tds or ths so we put a span within it with a nowrap on it*/
-.path-grade-report-grader heading_name_row th span {
- white-space: nowrap;
+table#user-grades tr.even td.grade.vmarked.overridden {
+ background-color: #f4a400;
}
-.path-grade-report-grader .grade_icons img.ajax {
- float: right;
+table#user-grades tr.even td.grade.hmarked {
+ background-color: #f5cf2c;
+ border-bottom-color: #f5cf2c;
}
-.path-grade-report-grader .gradestable th.user,
-.path-grade-report-grader .gradestable th.range,
-.path-grade-report-grader .flexible th,
-.path-grade-report-grader .flexible td,
-.path-grade-report-grader .flexible th a,
-.path-grade-report-grader .flexible td a,
-.path-grade-report-grader .gradestable th.range,
-.path-grade-report-grader td {
- white-space: nowrap;
+table#user-grades tr.even td.grade.hmarked.overridden {
+ background-color: #f5cf2c;
}
-table#user-grades .catlevel1,
-table#user-grades .r1,
-.path-grade-report-grader table tr.even td.cell,
-.path-grade-report-grader table tr.even th {
- background-color: #fff;
+table#user-grades tr.even td.grade.vmarked.hmarked {
+ background-color: #f1be00;
+ border-bottom-color: #f1be00;
}
-table#user-grades .catlevel3,
-.path-grade-report-grader table tr.odd td.cell {
- background-color: #efefef;
+table#user-grades tr.even td.grade.vmarked.hmarked.overridden {
+ background-color: #f1be00;
}
-table#fixed_column tr.odd th ,
-table#user-grades tr.odd th {
- background-color: #efefef;
+table#user-grades tr.even td.grade.overridden {
+ background-color: #efefef;
+ background: url([[pix:gradereport_grader|corner-fold]]) no-repeat;
+ width: 16px;
+ height: 16px;
+ background-color: #efefef;
}
-table#user-grades td.vmarked,
-table#user-grades tr.odd td.vmarked,
-table#user-grades tr.avg td.vmarked,
-table#user-grades tr.controls td.vmarked,
-table#user-grades .catlevel1.vmarked,
-table#user-grades .catlevel2.vmarked,
-table#user-grades .catlevel3.vmarked,
-table#user-grades tr.range td.vmarked,
-table#user-grades tr.groupavg td.vmarked {
- background-color: #fc3;
-}
-table#user-grades td.hmarked,
-table#user-grades tr.odd td.hmarked,
-table#user-grades tr.even td.hmarked,
-table#user-grades tr.odd th.hmarked,
-table#user-grades tr.even th.hmarked {
- background-color: #ff9;
-}
-table#user-grades td.hmarked.vmarked,
-table#user-grades tr.odd td.hmarked.vmarked,
-table#user-grades tr.even td.hmarked.vmarked {
- background-color: #fc9;
-}
-table#user-grades tr.heading,
-table#user-grades .heading td {
- border-style: solid;
- border-width: 0;
-}
-table#user-grades td.userfield,
-table#user-grades th,
-.path-grade-report-grader div.gradeparent,
-.path-grade-report-grader .ie6 form,
-table#user-grades td.ajax {
- text-align: left;
-}
-.dir-rtl table#user-grades td.userfield,
-.dir-rtl table#user-grades th,
-.path-grade-report-grader.dir-rtl div.gradeparent,
-.path-grade-report-grader.dir-rtl .ie6 form,
-.dir-rtl table#user-grades td.ajax {
- text-align: right;
-}
-.path-grade-report-grader .gradeparent {
- overflow: auto;
-}
-table#user-grades td.controls,
-.path-grade-report-grader table tr.avg .cell,
-.path-grade-report-grader table tr.range .cell {
- background-color: #f3ead8;
-}
-.path-grade-report-grader div.left_scroller tr,
-.path-grade-report-grader div.right_scroller tr,
-.path-grade-report-grader div.left_scroller td,
-.path-grade-report-grader div.right_scroller td,
-.path-grade-report-grader div.left_scroller th,
-.path-grade-report-grader div.right_scroller th {
- height: 4.5em;
- font-size: 10px;
-}
-.path-grade-report-grader table th.user,
-.path-grade-report-grader table td.userfield {
- text-align: left;
- vertical-align: middle;
-}
-.path-grade-report-grader .usersuspended a:link,
-.path-grade-report-grader .usersuspended a:visited {
- color: #666;
-}
-.path-grade-report-grader table th.usersuspended img.usersuspendedicon {
- vertical-align: text-bottom;
- margin-left: .45em;
+table#user-grades .overridden .grade_icons {
+ padding-left: 10px;
}
.path-grade-report-grader .yui3-overlay {
background-color: #FFEE69;
@@ -524,69 +517,234 @@ table#user-grades td.controls,
left: 0;
padding: 2px 5px;
font-size: 0.7em;
+table#user-grades .catlevel1 .action-icon img {
+ opacity: 0.5;
}
-.path-grade-report-grader .yui3-overlay .fullname {
- color: #5F3E00;
- font-weight: bold;
-}
-.path-grade-report-grader .yui3-overlay .itemname {
- color: #194F3E;
- font-weight: bold;
-}
-.path-grade-report-grader .yui3-overlay .feedback {
- color: #5F595E;
-}
-/* table#user-grades td */
-/* .grader-report-grader table#user-grades td .yui-panel div.hd { */
-.path-grade-report-grader #tooltipPanel {
- text-align: left;
-}
-.path-grade-report-grader .yui3-overlay a.container-close {
- margin-top: -3px;
-}
-.path-grade-report-grader #hiddentooltiproot,
-.tooltipDiv {
- display: none;
-}
-.path-grade-report-grader.ie .right_scroller {
- overflow-y: hidden;
-}
-.path-grade-report-grader.ie table#fixed_column th {
- height: 4.5em;
-}
-.path-grade-report-grader.ie table#fixed_column tr.avg th {
- height: 2.1em;
-}
-.path-grade-report-grader.ie div.left_scroller td {
- height: 4.5em;
-}
-.path-grade-report-grader.ie6 div.right_scroller {
- margin-top: 4em;
- width: auto;
- position: absolute;
-}
-.path-grade-report-grader.ie6 .excludedfloater {
- font-size: 7px;
+table#user-grades .catlevel1 .action-icon.selected img {
+ opacity: 1;
}
-/** MDL-40071 **/
-.path-grade-report-grader.dir-rtl table th.user,
-.path-grade-report-grader.dir-rtl table td.userfield {
- text-align: right;
+#gradebook-header-container {
+ font-size: 14px;
+ background-color: #444;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+#gradebook-header-container .gradebook-header-cell {
+ background-color: #444;
+ color: white;
+ padding: 4px;
+ white-space: nowrap;
+ border: 1px solid #444;
+ border-top: 0;
+ border-right: 0;
+ overflow: hidden;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+#gradebook-header-container .gradebook-header-cell.catlevel1 {
+ background-color: #333;
+}
+#gradebook-header-container .gradebook-header-cell.catlevel2 {
+ background-color: #222;
+}
+#gradebook-header-container .gradebook-header-cell a {
+ color: white;
+}
+#gradebook-header-container .gradebook-header-cell:hover {
+ background-color: #111;
+}
+#gradebook-header-container .gradebook-header-cell .icon {
+ width: 24px;
+ height: 24px;
+ vertical-align: middle;
+ border: 0;
+ padding-right: 6px;
}
-/** MDL-40180 **/
-.dir-rtl table#user-grades th.category,
-.dir-rtl table#user-grades th#studentheader,
-.dir-rtl table#user-grades th.user {
- text-align: right;
+#gradebook-user-container {
+ background-color: #777;
}
-.path-grade-report-grader.dir-rtl th.user img.userpicture {
- margin-left: 0.5em;
+#gradebook-user-container .gradebook-user-cell {
+ background-color: #666;
+ font-size: 14px;
+ border: 1px solid #666;
+ border-top: 0;
+ padding: 4px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+#gradebook-user-container .gradebook-user-cell .userpicture {
+ display: none;
+}
+#gradebook-user-container .gradebook-user-cell a {
+ font-weight: normal;
+ color: #fff;
+}
+#gradebook-user-container .gradebook-user-cell:nth-child(2n+1) {
+ background-color: #777;
+ border-bottom: 1px solid #777;
+}
+#gradebook-user-container .gradebook-user-cell:nth-child(2n):hover {
+ background-color: #5c5c5c;
+}
+#gradebook-user-container .gradebook-user-cell:hover {
+ background-color: #6d6d6d;
+}
+#gradebook-user-container .gradebook-user-cell:first-child {
+ /*border-top: 1px solid #666;*/
}
-.path-grade-report-grader .yui3-scrollview-scrollbar {
- opacity: 1 !important;
+#gradebook-footer-container {
+ display: none;
+ font-size: 14px;
+ background-color: #444;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+#gradebook-footer-container.gradebook-footer-row-sticky {
+ display: block;
+}
+#gradebook-footer-container.gradebook-footer-row-sticky .cell {
+ border-top: 2px solid gray;
+}
+#gradebook-footer-container .gradebook-footer-cell {
+ padding: 8px;
+ font-size: 14px;
+ background-color: #333;
+ color: white;
+ font-weight: bold;
+ text-align: center;
+ border: 1px solid #444;
+ border-right: 0;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+#gradebook-footer-container .gradebook-footer-cell:nth-of-type(1) {
+ text-align: right;
+}
+#gradebook-footer-container .gradebook-footer-cell .btn {
+ float: left;
+}
+
+#gradebook-user-header-container {
+ background-color: #333;
+ font-size: 14px;
+ text-align: left;
+ padding: 8px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+#gradebook-user-header-container a {
+ color: white;
+}
+
+.gradebook-loading-screen {
+ width: 100%;
+ height: 40px;
+ position: fixed;
+ left: 0;
+ bottom: 0;
+ background-color: black;
+ z-index: 99999;
+ opacity: 0.8;
+ padding: 10px;
+ text-align: center;
+}
+.gradebook-loading-screen .gradebook-loading {
+ padding-right: 40px;
+ text-align: center;
+ width: 100%;
+}
+
+.gradebook-loading i {
+ width: 20px;
+ height: 20px;
+ display: inline-block;
+ border-radius: 50%;
+ background: #00b3d5;
+}
+
+.gradebook-loading i:first-child {
+ -webkit-animation: gradebook-loading-ani2 0.5s linear infinite;
+ animation: gradebook-loading-ani2 0.5s linear infinite;
+ opacity: 0;
+ -webkit-transform: translate(-20px);
+ -moz-transform: translate(-20px);
+ -ms-transform: translate(-20px);
+ -o-transform: translate(-20px);
+ transform: translate(-20px);
+}
+
+.gradebook-loading i:nth-child(2),
+.gradebook-loading i:nth-child(3) {
+ -webkit-animation: gradebook-loading-ani3 0.5s linear infinite;
+ animation: gradebook-loading-ani3 0.5s linear infinite;
+}
+
+.gradebook-loading i:last-child {
+ -webkit-animation: gradebook-loading-ani1 0.5s linear infinite;
+ animation: gradebook-loading-ani1 0.5s linear infinite;
+}
+
+@-webkit-keyframes gradebook-loading-ani1 {
+ 100% {
+ -webkit-transform: translate(40px);
+ -moz-transform: translate(40px);
+ -ms-transform: translate(40px);
+ -o-transform: translate(40px);
+ transform: translate(40px);
+ opacity: 0;
+ }
+}
+
+@keyframes gradebook-loading-ani1 {
+ 100% {
+ -webkit-transform: translate(40px);
+ -moz-transform: translate(40px);
+ -ms-transform: translate(40px);
+ -o-transform: translate(40px);
+ transform: translate(40px);
+ opacity: 0;
+ }
+}
+
+@-webkit-keyframes gradebook-loading-ani2 {
+ 100% {
+ -webkit-transform: translate(20px);
+ -moz-transform: translate(20px);
+ -ms-transform: translate(20px);
+ -o-transform: translate(20px);
+ transform: translate(20px);
+ opacity: 1;
+ }
+}
+
+@keyframes gradebook-loading-ani2 {
+ 100% {
+ -webkit-transform: translate(20px);
+ -moz-transform: translate(20px);
+ -ms-transform: translate(20px);
+ -o-transform: translate(20px);
+ transform: translate(20px);
+ opacity: 1;
+ }
+}
+
+@-webkit-keyframes gradebook-loading-ani3 {
+ 100% {
+ -webkit-transform: translate(20px);
+ -moz-transform: translate(20px);
+ -ms-transform: translate(20px);
+ -o-transform: translate(20px);
+ transform: translate(20px);
+ }
}
.path-grade-report-grader .yui3-scrollview-scrollbar-horiz {
@@ -627,6 +785,14 @@ table#user-grades th.category {
}
.path-grade-report-grader td.grade.overridden {
line-height: 20px;
+@keyframes gradebook-loading-ani3 {
+ 100% {
+ -webkit-transform: translate(20px);
+ -moz-transform: translate(20px);
+ -ms-transform: translate(20px);
+ -o-transform: translate(20px);
+ transform: translate(20px);
+ }
}
/** MDL-46812 **/
diff --git a/grade/report/grader/yui/build/moodle-gradereport_grader-gradereporttable/moodle-gradereport_grader-gradereporttable-debug.js b/grade/report/grader/yui/build/moodle-gradereport_grader-gradereporttable/moodle-gradereport_grader-gradereporttable-debug.js
new file mode 100644
index 00000000000..4d2378b0e49
--- /dev/null
+++ b/grade/report/grader/yui/build/moodle-gradereport_grader-gradereporttable/moodle-gradereport_grader-gradereporttable-debug.js
@@ -0,0 +1,397 @@
+YUI.add('moodle-gradereport_grader-gradereporttable', function (Y, NAME) {
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see
.
+
+
+/**
+ * Static header and student column for grader table.
+ *
+ * @package gradereport_grader
+ * @copyright 2014 UC Regents
+ * @author Alfonso Roman
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+var LOGNS = 'moodle-gradereport_grader-gradereporttable';
+
+M.gradereport_grader = M.gradereport_grader || {};
+
+// Create a gradebook module
+M.gradereport_grader.gradereporttable = {
+ // Resuable nodes
+ node_student_header_cell: {},
+ node_student_cell: {},
+ node_footer_row: {},
+ scrollevent: function() {
+ console.log('scrolll event');
+ },
+ // Init module
+ init: function() {
+ Y.log('Loading grader report floating headers and columns.', 'debug', LOGNS);
+
+ // Set up some reusable nodes.
+ this.node_student_header_cell = Y.one('#studentheader');
+ // First student cell.
+ this.node_student_cell = Y.one('#user-grades .user.cell');
+ // Averages row.
+ this.node_footer_row = Y.one('#user-grades .avg');
+
+ // Check if there are any students -- otherwise no need to do anything.
+ if (this.node_student_cell) {
+ // Generate floating elements.
+ this.float_user_column();
+ this.float_assignment_header();
+ this.float_user_header();
+
+ // Onscroll event updates all the floating header/column positions.
+ var onscroll = function() {
+
+ // Get better performance by preventing layout thrashing. This occurs
+ // when the DOM is repeatedly updated and queried for updated values.
+ //
+ // To fix this, group reads and writes
+
+ //
+ // First get all the readable values needed.
+
+ // Header row
+ var headercontainer = document.getElementById('gradebook-header-container');
+ var userheadercell = document.getElementById('studentheader');
+
+ var usercolumnheader = document.getElementById('gradebook-user-header-container');
+
+ var headercelltop = userheadercell.offsetTop + userheadercell.offsetParent.offsetTop;
+
+ // User column
+ var pageleftcutoff = window.pageXOffset;
+ var firstusercell = document.querySelectorAll("#user-grades .user.cell")[0];
+ var firstusercellpos = firstusercell.offsetLeft + firstusercell.offsetParent.offsetLeft;
+
+ var usercolumn = document.getElementById('gradebook-user-container');
+
+ // Footer row
+ var lastrow = document.querySelectorAll('#user-grades .avg')[0];
+ var footer, lastrowpos;
+
+ // Check that Average footer is available.
+ if (lastrow !== undefined) {
+ footer = document.getElementById('gradebook-footer-container');
+ lastrowpos = lastrow.offsetTop + lastrow.offsetParent.offsetTop;
+ }
+
+ // Viewport values
+ var pageYOffset = window.pageYOffset;
+ var windowInnerHeight = window.innerHeight;
+
+ //
+ // Next do all the writing.
+
+ // Header position
+ headercontainer.style.left = userheadercell.offsetLeft + userheadercell.offsetParent.offsetLeft + 'px';
+ if (pageYOffset > headercelltop) {
+ headercontainer.style.top = pageYOffset + 40 + 'px';
+ usercolumnheader.style.top = pageYOffset + 40 + 'px';
+ } else {
+ headercontainer.style.top = headercelltop + 'px';
+ usercolumnheader.style.top = headercelltop + 'px';
+ }
+
+ // User column position
+ if (pageleftcutoff > firstusercellpos) {
+ usercolumn.style.left = pageleftcutoff + 'px';
+ usercolumnheader.style.left = pageleftcutoff + 'px';
+ } else {
+ usercolumn.style.left = firstusercellpos + 'px';
+ usercolumnheader.style.left = firstusercellpos + 'px';
+ }
+
+ // Update footer
+ if (lastrow !== undefined) {
+ footer.style.left = userheadercell.offsetLeft + userheadercell.offsetParent.offsetLeft + 'px';
+
+ if (pageYOffset + windowInnerHeight < lastrowpos) {
+ footer.style.top = (pageYOffset + windowInnerHeight - 50) + 'px';
+ footer.classList.add('gradebook-footer-row-sticky');
+ } else {
+ footer.style.top = lastrowpos + 'px';
+ footer.classList.remove('gradebook-footer-row-sticky');
+ }
+ }
+ };
+
+ // Add the floating 'average' footer if available.
+ if (this.node_footer_row) {
+ this.float_assignment_footer();
+ }
+
+ // Set floating element initial positions by simulating scroll.
+ onscroll();
+
+ // Generate events.
+ //
+ // Use native DOM scroll & resize events instead of YUI synthetic event.
+ window.onscroll = onscroll;
+ window.onresize = function() {
+
+ onscroll();
+
+ // Resize headers & footers.
+ // This is an expensive operation, not expected to happen often.
+ var headers = Y.all('#gradebook-header-container .gradebook-header-cell');
+ var resizedcells = Y.all('#user-grades .heading .cell');
+
+ var headeroffsetleft = Y.one('#studentheader').getX();
+ var newcontainerwidth = 0;
+ resizedcells.each(function(cell, idx) {
+ var headercell = headers.item(idx);
+
+ newcontainerwidth += cell.get('offsetWidth');
+ var styles = {
+ width: cell.get('offsetWidth'),
+ left: cell.getX() - headeroffsetleft + 'px'
+ };
+ headercell.setStyles(styles);
+ });
+
+ var footers = Y.all('#gradebook-footer-container .gradebook-footer-cell');
+
+ if (footers.size() !== 0) {
+ var resizedavgcells = Y.all('#user-grades .avg .cell');
+
+ resizedavgcells.each(function(cell, idx) {
+ var footercell = footers.item(idx);
+ var styles = {
+ width: cell.get('offsetWidth'),
+ left: cell.getX() - headeroffsetleft + 'px'
+ };
+ footercell.setStyles(styles);
+ });
+ Y.one('#gradebook-footer-container').setStyle('width', newcontainerwidth);
+ }
+
+ Y.one('#gradebook-header-container').setStyle('width', newcontainerwidth);
+
+ };
+ }
+
+ // Remove loading screen. Need to do YUI synthetic event to trigger
+ // on all browsers.
+ Y.on('domready', function() {
+ Y.one('.gradebook-loading-screen').remove(true);
+ Y.all('#user-grades .overridden').setAttribute('aria-label', 'Overriden grade');
+ });
+ },
+ float_user_column: function() {
+ Y.log('Floating the user column.', 'debug', LOGNS);
+
+ // Grab the user names column
+ var user_column = Y.all('#user-grades .user.cell');
+
+ // Generate a floating table
+ var floating_user_column = Y.Node.create('');
+ var floating_user_column_height = 0;
+ var user_column_offset = this.node_student_cell.getY();
+
+ user_column.each(function(node) {
+
+ // Create cloned node and container.
+ // We'll absolutely position the container to each cell position,
+ // this will guarantee that student cells are always aligned.
+ var container_node = Y.Node.create('');
+
+ // Grab the username
+ var usernamenode = node.cloneNode(true);
+ container_node.append(usernamenode.getHTML());
+ usernamenode = null;
+
+ container_node.setStyles({
+ 'height': node.get('offsetHeight') + 'px',
+ 'width': node.get('offsetWidth') + 'px',
+ 'position': 'absolute',
+ 'top': (node.getY() - user_column_offset) + 'px'
+ });
+
+ floating_user_column_height += node.get('offsetHeight');
+ // Retrieve the corresponding row
+ var classes = node.ancestor().getAttribute('class').split(' ').join('.');
+ // Attach highlight event
+ container_node.on('click', function() {
+ Y.one('.' + classes).all('.grade').toggleClass('hmarked');
+ });
+ // Add the cloned nodes to our floating table
+ floating_user_column.appendChild(container_node);
+
+ }, this);
+
+ // Style the table
+ floating_user_column.setStyles({
+ 'position': 'absolute',
+ 'left': this.node_student_cell.getX() + 'px',
+ 'top': this.node_student_cell.getY() + 'px',
+ 'width': this.node_student_cell.get('offsetWidth'),
+ 'height': floating_user_column_height + 'px',
+ 'background-color': '#f9f9f9'
+ });
+
+ Y.one('body').append(floating_user_column);
+ },
+ float_user_header: function() {
+ Y.log('Floating the user column header.', 'debug', LOGNS);
+
+ // Float the 'user name' header cell.
+ var floating_user_header_cell = Y.Node.create('');
+
+ // Clone the node
+ var cellnode = this.node_student_header_cell.cloneNode(true);
+ // Append node contents
+ floating_user_header_cell.append(cellnode.getHTML());
+ floating_user_header_cell.setStyles({
+ 'position': 'absolute',
+ 'left': this.node_student_cell.getX() + 'px',
+ 'top': this.node_student_header_cell.getY() + 'px',
+ 'width': '200px',
+ 'height': this.node_student_header_cell.get('offsetHeight') + 'px'
+ });
+
+ // Safe for collection
+ cellnode = null;
+
+ Y.one('body').append(floating_user_header_cell);
+ },
+ float_assignment_header: function() {
+ Y.log('Floating the assignment header.', 'debug', LOGNS);
+
+ var grade_headers = Y.all('#user-grades tr.heading .cell');
+
+ // Generate a floating headers
+ var floating_grade_headers = Y.Node.create('');
+
+ var floating_grade_headers_width = 0;
+ var floating_grade_headers_height = 0;
+ var grade_headers_offset = this.node_student_header_cell.getX();
+
+ grade_headers.each(function(node) {
+
+ // Get the target column to highlight. This is embedded in
+ // the column cell #, but it's off by one, so need to adjust for that.
+ var col = node.getAttribute('class');
+
+ // Extract the column #
+ var search = /c[0-9]+/g;
+ var match = search.exec(col);
+ match = match[0].replace('c', '');
+
+ // Offset
+ var target_col = parseInt(match, 10);
+ ++target_col;
+
+ var nodepos = node.getX();
+
+ // We need to clone the node, otherwise we mutate original obj
+ var nodeclone = node.cloneNode(true);
+
+ var newnode = Y.Node.create('');
+ newnode.append(nodeclone.getHTML());
+ newnode.addClass(nodeclone.getAttribute('class'));
+ nodeclone = null;
+
+ newnode.setStyles({
+ 'width': node.get('offsetWidth') + 'px',
+ 'height': node.get('offsetHeight') + 'px',
+ 'position': 'absolute',
+ 'left': (nodepos - grade_headers_offset) + 'px'
+ });
+
+ // Sum up total width
+ floating_grade_headers_width += parseInt(node.get('offsetWidth'), 10);
+ floating_grade_headers_height = node.get('offsetHeight');
+
+ // Attach 'highlight column' event to new node
+ newnode.on('click', function() {
+ Y.all('.cell.c' + target_col).toggleClass('vmarked');
+ });
+
+ // Append to floating table.
+ floating_grade_headers.appendChild(newnode);
+ }, this);
+
+ // Position header table.
+ floating_grade_headers.setStyles({
+ 'position': 'absolute',
+ 'top': this.node_student_header_cell.getY() + 'px',
+ 'left': this.node_student_header_cell.getX() + 'px',
+ 'width': floating_grade_headers_width + 'px',
+ 'height': floating_grade_headers_height + 'px'
+ });
+
+ Y.one('body').append(floating_grade_headers);
+ },
+ float_assignment_footer: function() {
+ Y.log('Floating the averages footer.', 'debug', LOGNS);
+
+ // Generate the sticky footer row.
+ // Grab the row.
+ var footer_row = Y.all('#user-grades .lastrow .cell');
+ // Create a container.
+ var floating_grade_footers = Y.Node.create('');
+ var floating_grade_footer_width = 0;
+ var footer_row_offset = this.node_footer_row.getX();
+ // Copy nodes
+ footer_row.each(function(node) {
+
+ var nodepos = node.getX();
+ var cellnodeclone = node.cloneNode(true);
+
+ var newnode = Y.Node.create('');
+ newnode.append(cellnodeclone.getHTML());
+ newnode.setStyles({
+ 'width': node.get('offsetWidth') + 'px',
+ 'height': '50px',
+ 'position': 'absolute',
+ 'left': (nodepos - footer_row_offset) + 'px'
+ });
+
+ floating_grade_footers.append(newnode);
+ floating_grade_footer_width += parseInt(node.get('offsetWidth'), 10);
+ }, this);
+
+ // Attach 'Update' button.
+ var update_button = Y.one('#gradersubmit');
+ if (update_button) {
+ var button = Y.Node.create('');
+ button.on('click', function() {
+ YUI().use('node-event-simulate', function(Y) {
+ Y.one('#gradersubmit').simulate('click');
+ });
+ });
+ floating_grade_footers.one('.gradebook-footer-cell').append(button);
+ }
+
+ // Position the row
+ floating_grade_footers.setStyles({
+ 'position': 'absolute',
+ 'left': this.node_footer_row.getX() + 'px',
+ 'bottom': '0',
+ 'height': '50px',
+ 'width': floating_grade_footer_width + 'px'
+ });
+
+ Y.one('body').append(floating_grade_footers);
+ }
+};
+
+
+}, '@VERSION@');
diff --git a/grade/report/grader/yui/build/moodle-gradereport_grader-gradereporttable/moodle-gradereport_grader-gradereporttable-min.js b/grade/report/grader/yui/build/moodle-gradereport_grader-gradereporttable/moodle-gradereport_grader-gradereporttable-min.js
new file mode 100644
index 00000000000..cfa5af8a406
--- /dev/null
+++ b/grade/report/grader/yui/build/moodle-gradereport_grader-gradereporttable/moodle-gradereport_grader-gradereporttable-min.js
@@ -0,0 +1 @@
+YUI.add("moodle-gradereport_grader-gradereporttable",function(e,t){var n="moodle-gradereport_grader-gradereporttable";M.gradereport_grader=M.gradereport_grader||{},M.gradereport_grader.gradereporttable={node_student_header_cell:{},node_student_cell:{},node_footer_row:{},scrollevent:function(){console.log("scrolll event")},init:function(){this.node_student_header_cell=e.one("#studentheader"),this.node_student_cell=e.one("#user-grades .user.cell"),this.node_footer_row=e.one("#user-grades .avg");if(this.node_student_cell){this.float_user_column(),this.float_assignment_header(),this.float_user_header();var t=function(){var e=document.getElementById("gradebook-header-container"),t=document.getElementById("studentheader"),n=document.getElementById("gradebook-user-header-container"),r=t.offsetTop+t.offsetParent.offsetTop,i=window.pageXOffset,s=document.querySelectorAll("#user-grades .user.cell")[0],o=s.offsetLeft+s.offsetParent.offsetLeft,u=document.getElementById("gradebook-user-container"),a=document.querySelectorAll("#user-grades .avg")[0],f,l;a!==undefined&&(f=document.getElementById("gradebook-footer-container"),l=a.offsetTop+a.offsetParent.offsetTop);var c=window.pageYOffset,h=window.innerHeight;e.style.left=t.offsetLeft+t.offsetParent.offsetLeft+"px",c>r?(e.style.top=c+40+"px",n.style.top=c+40+"px"):(e.style.top=r+"px",n.style.top=r+"px"),i>o?(u.style.left=i+"px",n.style.left=i+"px"):(u.style.left=o+"px",n.style.left=o+"px"),a!==undefined&&(f.style.left=t.offsetLeft+t.offsetParent.offsetLeft+"px",c+h'),r=0,i=this.node_student_cell.getY();t.each(function(t){var s=e.Node.create('
'),o=t.cloneNode(!0);s.append(o.getHTML()),o=null,s.setStyles({height:t.get("offsetHeight")+"px",width:t.get("offsetWidth")+"px",position:"absolute",top:t.getY()-i+"px"}),r+=t.get("offsetHeight");var u=t.ancestor().getAttribute("class").split(" ").join(".");s.on("click",function(){e.one("."+u).all(".grade").toggleClass("hmarked")}),n.appendChild(s)},this),n.setStyles({position:"absolute",left:this.node_student_cell.getX()+"px",top:this.node_student_cell.getY()+"px",width:this.node_student_cell.get("offsetWidth"),height:r+"px","background-color":"#f9f9f9"}),e.one("body").append(n)},float_user_header:function(){var t=e.Node.create(''),n=this.node_student_header_cell.cloneNode(!0);t.append(n.getHTML()),t.setStyles({position:"absolute",left:this.node_student_cell.getX()+"px",top:this.node_student_header_cell.getY()+"px",width:"200px",height:this.node_student_header_cell.get("offsetHeight")+"px"}),n=null,e.one("body").append(t)},float_assignment_header:function(){var t=e.all("#user-grades tr.heading .cell"),n=e.Node.create(''),r=0,i=0,s=this.node_student_header_cell.getX();t.each(function(t){var o=t.getAttribute("class"),u=/c[0-9]+/g,a=u.exec(o);a=a[0].replace("c","");var f=parseInt(a,10);++f;var l=t.getX(),c=t.cloneNode(!0),h=e.Node.create('');h.append(c.getHTML()),h.addClass(c.getAttribute("class")),c=null,h.setStyles({width:t.get("offsetWidth")+"px",height:t.get("offsetHeight")+"px",position:"absolute",left:l-s+"px"}),r+=parseInt(t.get("offsetWidth"),10),i=t.get("offsetHeight"),h.on("click",function(){e.all(".cell.c"+f).toggleClass("vmarked")}),n.appendChild(h)},this),n.setStyles({position:"absolute",top:this.node_student_header_cell.getY()+"px",left:this.node_student_header_cell.getX()+"px",width:r+"px",height:i+"px"}),e.one("body").append(n)},float_assignment_footer:function(){var t=e.all("#user-grades .lastrow .cell"),n=e.Node.create(''),r=0,i=this.node_footer_row.getX();t.each(function(t){var s=t.getX(),o=t.cloneNode(!0),u=e.Node.create('');u.append(o.getHTML()),u.setStyles({width:t.get("offsetWidth")+"px",height:"50px",position:"absolute",left:s-i+"px"}),n.append(u),r+=parseInt(t.get("offsetWidth"),10)},this);var s=e.one("#gradersubmit");if(s){var o=e.Node.create('
");o.on("click",function(){YUI().use("node-event-simulate",function(e){e.one("#gradersubmit").simulate("click")})}),n.one(".gradebook-footer-cell").append(o)}n.setStyles({position:"absolute",left:this.node_footer_row.getX()+"px",bottom:"0",height:"50px",width:r+"px"}),e.one("body").append(n)}}},"@VERSION@");
diff --git a/grade/report/grader/yui/build/moodle-gradereport_grader-gradereporttable/moodle-gradereport_grader-gradereporttable.js b/grade/report/grader/yui/build/moodle-gradereport_grader-gradereporttable/moodle-gradereport_grader-gradereporttable.js
new file mode 100644
index 00000000000..df09be6723c
--- /dev/null
+++ b/grade/report/grader/yui/build/moodle-gradereport_grader-gradereporttable/moodle-gradereport_grader-gradereporttable.js
@@ -0,0 +1,392 @@
+YUI.add('moodle-gradereport_grader-gradereporttable', function (Y, NAME) {
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see
.
+
+
+/**
+ * Static header and student column for grader table.
+ *
+ * @package gradereport_grader
+ * @copyright 2014 UC Regents
+ * @author Alfonso Roman
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+var LOGNS = 'moodle-gradereport_grader-gradereporttable';
+
+M.gradereport_grader = M.gradereport_grader || {};
+
+// Create a gradebook module
+M.gradereport_grader.gradereporttable = {
+ // Resuable nodes
+ node_student_header_cell: {},
+ node_student_cell: {},
+ node_footer_row: {},
+ scrollevent: function() {
+ console.log('scrolll event');
+ },
+ // Init module
+ init: function() {
+
+ // Set up some reusable nodes.
+ this.node_student_header_cell = Y.one('#studentheader');
+ // First student cell.
+ this.node_student_cell = Y.one('#user-grades .user.cell');
+ // Averages row.
+ this.node_footer_row = Y.one('#user-grades .avg');
+
+ // Check if there are any students -- otherwise no need to do anything.
+ if (this.node_student_cell) {
+ // Generate floating elements.
+ this.float_user_column();
+ this.float_assignment_header();
+ this.float_user_header();
+
+ // Onscroll event updates all the floating header/column positions.
+ var onscroll = function() {
+
+ // Get better performance by preventing layout thrashing. This occurs
+ // when the DOM is repeatedly updated and queried for updated values.
+ //
+ // To fix this, group reads and writes
+
+ //
+ // First get all the readable values needed.
+
+ // Header row
+ var headercontainer = document.getElementById('gradebook-header-container');
+ var userheadercell = document.getElementById('studentheader');
+
+ var usercolumnheader = document.getElementById('gradebook-user-header-container');
+
+ var headercelltop = userheadercell.offsetTop + userheadercell.offsetParent.offsetTop;
+
+ // User column
+ var pageleftcutoff = window.pageXOffset;
+ var firstusercell = document.querySelectorAll("#user-grades .user.cell")[0];
+ var firstusercellpos = firstusercell.offsetLeft + firstusercell.offsetParent.offsetLeft;
+
+ var usercolumn = document.getElementById('gradebook-user-container');
+
+ // Footer row
+ var lastrow = document.querySelectorAll('#user-grades .avg')[0];
+ var footer, lastrowpos;
+
+ // Check that Average footer is available.
+ if (lastrow !== undefined) {
+ footer = document.getElementById('gradebook-footer-container');
+ lastrowpos = lastrow.offsetTop + lastrow.offsetParent.offsetTop;
+ }
+
+ // Viewport values
+ var pageYOffset = window.pageYOffset;
+ var windowInnerHeight = window.innerHeight;
+
+ //
+ // Next do all the writing.
+
+ // Header position
+ headercontainer.style.left = userheadercell.offsetLeft + userheadercell.offsetParent.offsetLeft + 'px';
+ if (pageYOffset > headercelltop) {
+ headercontainer.style.top = pageYOffset + 40 + 'px';
+ usercolumnheader.style.top = pageYOffset + 40 + 'px';
+ } else {
+ headercontainer.style.top = headercelltop + 'px';
+ usercolumnheader.style.top = headercelltop + 'px';
+ }
+
+ // User column position
+ if (pageleftcutoff > firstusercellpos) {
+ usercolumn.style.left = pageleftcutoff + 'px';
+ usercolumnheader.style.left = pageleftcutoff + 'px';
+ } else {
+ usercolumn.style.left = firstusercellpos + 'px';
+ usercolumnheader.style.left = firstusercellpos + 'px';
+ }
+
+ // Update footer
+ if (lastrow !== undefined) {
+ footer.style.left = userheadercell.offsetLeft + userheadercell.offsetParent.offsetLeft + 'px';
+
+ if (pageYOffset + windowInnerHeight < lastrowpos) {
+ footer.style.top = (pageYOffset + windowInnerHeight - 50) + 'px';
+ footer.classList.add('gradebook-footer-row-sticky');
+ } else {
+ footer.style.top = lastrowpos + 'px';
+ footer.classList.remove('gradebook-footer-row-sticky');
+ }
+ }
+ };
+
+ // Add the floating 'average' footer if available.
+ if (this.node_footer_row) {
+ this.float_assignment_footer();
+ }
+
+ // Set floating element initial positions by simulating scroll.
+ onscroll();
+
+ // Generate events.
+ //
+ // Use native DOM scroll & resize events instead of YUI synthetic event.
+ window.onscroll = onscroll;
+ window.onresize = function() {
+
+ onscroll();
+
+ // Resize headers & footers.
+ // This is an expensive operation, not expected to happen often.
+ var headers = Y.all('#gradebook-header-container .gradebook-header-cell');
+ var resizedcells = Y.all('#user-grades .heading .cell');
+
+ var headeroffsetleft = Y.one('#studentheader').getX();
+ var newcontainerwidth = 0;
+ resizedcells.each(function(cell, idx) {
+ var headercell = headers.item(idx);
+
+ newcontainerwidth += cell.get('offsetWidth');
+ var styles = {
+ width: cell.get('offsetWidth'),
+ left: cell.getX() - headeroffsetleft + 'px'
+ };
+ headercell.setStyles(styles);
+ });
+
+ var footers = Y.all('#gradebook-footer-container .gradebook-footer-cell');
+
+ if (footers.size() !== 0) {
+ var resizedavgcells = Y.all('#user-grades .avg .cell');
+
+ resizedavgcells.each(function(cell, idx) {
+ var footercell = footers.item(idx);
+ var styles = {
+ width: cell.get('offsetWidth'),
+ left: cell.getX() - headeroffsetleft + 'px'
+ };
+ footercell.setStyles(styles);
+ });
+ Y.one('#gradebook-footer-container').setStyle('width', newcontainerwidth);
+ }
+
+ Y.one('#gradebook-header-container').setStyle('width', newcontainerwidth);
+
+ };
+ }
+
+ // Remove loading screen. Need to do YUI synthetic event to trigger
+ // on all browsers.
+ Y.on('domready', function() {
+ Y.one('.gradebook-loading-screen').remove(true);
+ Y.all('#user-grades .overridden').setAttribute('aria-label', 'Overriden grade');
+ });
+ },
+ float_user_column: function() {
+
+ // Grab the user names column
+ var user_column = Y.all('#user-grades .user.cell');
+
+ // Generate a floating table
+ var floating_user_column = Y.Node.create('');
+ var floating_user_column_height = 0;
+ var user_column_offset = this.node_student_cell.getY();
+
+ user_column.each(function(node) {
+
+ // Create cloned node and container.
+ // We'll absolutely position the container to each cell position,
+ // this will guarantee that student cells are always aligned.
+ var container_node = Y.Node.create('');
+
+ // Grab the username
+ var usernamenode = node.cloneNode(true);
+ container_node.append(usernamenode.getHTML());
+ usernamenode = null;
+
+ container_node.setStyles({
+ 'height': node.get('offsetHeight') + 'px',
+ 'width': node.get('offsetWidth') + 'px',
+ 'position': 'absolute',
+ 'top': (node.getY() - user_column_offset) + 'px'
+ });
+
+ floating_user_column_height += node.get('offsetHeight');
+ // Retrieve the corresponding row
+ var classes = node.ancestor().getAttribute('class').split(' ').join('.');
+ // Attach highlight event
+ container_node.on('click', function() {
+ Y.one('.' + classes).all('.grade').toggleClass('hmarked');
+ });
+ // Add the cloned nodes to our floating table
+ floating_user_column.appendChild(container_node);
+
+ }, this);
+
+ // Style the table
+ floating_user_column.setStyles({
+ 'position': 'absolute',
+ 'left': this.node_student_cell.getX() + 'px',
+ 'top': this.node_student_cell.getY() + 'px',
+ 'width': this.node_student_cell.get('offsetWidth'),
+ 'height': floating_user_column_height + 'px',
+ 'background-color': '#f9f9f9'
+ });
+
+ Y.one('body').append(floating_user_column);
+ },
+ float_user_header: function() {
+
+ // Float the 'user name' header cell.
+ var floating_user_header_cell = Y.Node.create('');
+
+ // Clone the node
+ var cellnode = this.node_student_header_cell.cloneNode(true);
+ // Append node contents
+ floating_user_header_cell.append(cellnode.getHTML());
+ floating_user_header_cell.setStyles({
+ 'position': 'absolute',
+ 'left': this.node_student_cell.getX() + 'px',
+ 'top': this.node_student_header_cell.getY() + 'px',
+ 'width': '200px',
+ 'height': this.node_student_header_cell.get('offsetHeight') + 'px'
+ });
+
+ // Safe for collection
+ cellnode = null;
+
+ Y.one('body').append(floating_user_header_cell);
+ },
+ float_assignment_header: function() {
+
+ var grade_headers = Y.all('#user-grades tr.heading .cell');
+
+ // Generate a floating headers
+ var floating_grade_headers = Y.Node.create('');
+
+ var floating_grade_headers_width = 0;
+ var floating_grade_headers_height = 0;
+ var grade_headers_offset = this.node_student_header_cell.getX();
+
+ grade_headers.each(function(node) {
+
+ // Get the target column to highlight. This is embedded in
+ // the column cell #, but it's off by one, so need to adjust for that.
+ var col = node.getAttribute('class');
+
+ // Extract the column #
+ var search = /c[0-9]+/g;
+ var match = search.exec(col);
+ match = match[0].replace('c', '');
+
+ // Offset
+ var target_col = parseInt(match, 10);
+ ++target_col;
+
+ var nodepos = node.getX();
+
+ // We need to clone the node, otherwise we mutate original obj
+ var nodeclone = node.cloneNode(true);
+
+ var newnode = Y.Node.create('');
+ newnode.append(nodeclone.getHTML());
+ newnode.addClass(nodeclone.getAttribute('class'));
+ nodeclone = null;
+
+ newnode.setStyles({
+ 'width': node.get('offsetWidth') + 'px',
+ 'height': node.get('offsetHeight') + 'px',
+ 'position': 'absolute',
+ 'left': (nodepos - grade_headers_offset) + 'px'
+ });
+
+ // Sum up total width
+ floating_grade_headers_width += parseInt(node.get('offsetWidth'), 10);
+ floating_grade_headers_height = node.get('offsetHeight');
+
+ // Attach 'highlight column' event to new node
+ newnode.on('click', function() {
+ Y.all('.cell.c' + target_col).toggleClass('vmarked');
+ });
+
+ // Append to floating table.
+ floating_grade_headers.appendChild(newnode);
+ }, this);
+
+ // Position header table.
+ floating_grade_headers.setStyles({
+ 'position': 'absolute',
+ 'top': this.node_student_header_cell.getY() + 'px',
+ 'left': this.node_student_header_cell.getX() + 'px',
+ 'width': floating_grade_headers_width + 'px',
+ 'height': floating_grade_headers_height + 'px'
+ });
+
+ Y.one('body').append(floating_grade_headers);
+ },
+ float_assignment_footer: function() {
+
+ // Generate the sticky footer row.
+ // Grab the row.
+ var footer_row = Y.all('#user-grades .lastrow .cell');
+ // Create a container.
+ var floating_grade_footers = Y.Node.create('');
+ var floating_grade_footer_width = 0;
+ var footer_row_offset = this.node_footer_row.getX();
+ // Copy nodes
+ footer_row.each(function(node) {
+
+ var nodepos = node.getX();
+ var cellnodeclone = node.cloneNode(true);
+
+ var newnode = Y.Node.create('');
+ newnode.append(cellnodeclone.getHTML());
+ newnode.setStyles({
+ 'width': node.get('offsetWidth') + 'px',
+ 'height': '50px',
+ 'position': 'absolute',
+ 'left': (nodepos - footer_row_offset) + 'px'
+ });
+
+ floating_grade_footers.append(newnode);
+ floating_grade_footer_width += parseInt(node.get('offsetWidth'), 10);
+ }, this);
+
+ // Attach 'Update' button.
+ var update_button = Y.one('#gradersubmit');
+ if (update_button) {
+ var button = Y.Node.create('');
+ button.on('click', function() {
+ YUI().use('node-event-simulate', function(Y) {
+ Y.one('#gradersubmit').simulate('click');
+ });
+ });
+ floating_grade_footers.one('.gradebook-footer-cell').append(button);
+ }
+
+ // Position the row
+ floating_grade_footers.setStyles({
+ 'position': 'absolute',
+ 'left': this.node_footer_row.getX() + 'px',
+ 'bottom': '0',
+ 'height': '50px',
+ 'width': floating_grade_footer_width + 'px'
+ });
+
+ Y.one('body').append(floating_grade_footers);
+ }
+};
+
+
+}, '@VERSION@');
diff --git a/grade/report/grader/yui/src/gradereporttable/build.json b/grade/report/grader/yui/src/gradereporttable/build.json
new file mode 100644
index 00000000000..4fadacf58c5
--- /dev/null
+++ b/grade/report/grader/yui/src/gradereporttable/build.json
@@ -0,0 +1,10 @@
+{
+ "name": "moodle-gradereport_grader-gradereporttable",
+ "builds": {
+ "moodle-gradereport_grader-gradereporttable": {
+ "jsfiles": [
+ "gradereporttable.js"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/grade/report/grader/yui/src/gradereporttable/js/gradereporttable.js b/grade/report/grader/yui/src/gradereporttable/js/gradereporttable.js
new file mode 100644
index 00000000000..37e0d0217e1
--- /dev/null
+++ b/grade/report/grader/yui/src/gradereporttable/js/gradereporttable.js
@@ -0,0 +1,392 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+
+/**
+ * Static header and student column for grader table.
+ *
+ * @package gradereport_grader
+ * @copyright 2014 UC Regents
+ * @author Alfonso Roman
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+var LOGNS = 'moodle-gradereport_grader-gradereporttable';
+
+M.gradereport_grader = M.gradereport_grader || {};
+
+// Create a gradebook module
+M.gradereport_grader.gradereporttable = {
+ // Resuable nodes
+ node_student_header_cell: {},
+ node_student_cell: {},
+ node_footer_row: {},
+ scrollevent: function() {
+ console.log('scrolll event');
+ },
+ // Init module
+ init: function() {
+ Y.log('Loading grader report floating headers and columns.', 'debug', LOGNS);
+
+ // Set up some reusable nodes.
+ this.node_student_header_cell = Y.one('#studentheader');
+ // First student cell.
+ this.node_student_cell = Y.one('#user-grades .user.cell');
+ // Averages row.
+ this.node_footer_row = Y.one('#user-grades .avg');
+
+ // Check if there are any students -- otherwise no need to do anything.
+ if (this.node_student_cell) {
+ // Generate floating elements.
+ this.float_user_column();
+ this.float_assignment_header();
+ this.float_user_header();
+
+ // Onscroll event updates all the floating header/column positions.
+ var onscroll = function() {
+
+ // Get better performance by preventing layout thrashing. This occurs
+ // when the DOM is repeatedly updated and queried for updated values.
+ //
+ // To fix this, group reads and writes
+
+ //
+ // First get all the readable values needed.
+
+ // Header row
+ var headercontainer = document.getElementById('gradebook-header-container');
+ var userheadercell = document.getElementById('studentheader');
+
+ var usercolumnheader = document.getElementById('gradebook-user-header-container');
+
+ var headercelltop = userheadercell.offsetTop + userheadercell.offsetParent.offsetTop;
+
+ // User column
+ var pageleftcutoff = window.pageXOffset;
+ var firstusercell = document.querySelectorAll("#user-grades .user.cell")[0];
+ var firstusercellpos = firstusercell.offsetLeft + firstusercell.offsetParent.offsetLeft;
+
+ var usercolumn = document.getElementById('gradebook-user-container');
+
+ // Footer row
+ var lastrow = document.querySelectorAll('#user-grades .avg')[0];
+ var footer, lastrowpos;
+
+ // Check that Average footer is available.
+ if (lastrow !== undefined) {
+ footer = document.getElementById('gradebook-footer-container');
+ lastrowpos = lastrow.offsetTop + lastrow.offsetParent.offsetTop;
+ }
+
+ // Viewport values
+ var pageYOffset = window.pageYOffset;
+ var windowInnerHeight = window.innerHeight;
+
+ //
+ // Next do all the writing.
+
+ // Header position
+ headercontainer.style.left = userheadercell.offsetLeft + userheadercell.offsetParent.offsetLeft + 'px';
+ if (pageYOffset > headercelltop) {
+ headercontainer.style.top = pageYOffset + 40 + 'px';
+ usercolumnheader.style.top = pageYOffset + 40 + 'px';
+ } else {
+ headercontainer.style.top = headercelltop + 'px';
+ usercolumnheader.style.top = headercelltop + 'px';
+ }
+
+ // User column position
+ if (pageleftcutoff > firstusercellpos) {
+ usercolumn.style.left = pageleftcutoff + 'px';
+ usercolumnheader.style.left = pageleftcutoff + 'px';
+ } else {
+ usercolumn.style.left = firstusercellpos + 'px';
+ usercolumnheader.style.left = firstusercellpos + 'px';
+ }
+
+ // Update footer
+ if (lastrow !== undefined) {
+ footer.style.left = userheadercell.offsetLeft + userheadercell.offsetParent.offsetLeft + 'px';
+
+ if (pageYOffset + windowInnerHeight < lastrowpos) {
+ footer.style.top = (pageYOffset + windowInnerHeight - 50) + 'px';
+ footer.classList.add('gradebook-footer-row-sticky');
+ } else {
+ footer.style.top = lastrowpos + 'px';
+ footer.classList.remove('gradebook-footer-row-sticky');
+ }
+ }
+ };
+
+ // Add the floating 'average' footer if available.
+ if (this.node_footer_row) {
+ this.float_assignment_footer();
+ }
+
+ // Set floating element initial positions by simulating scroll.
+ onscroll();
+
+ // Generate events.
+ //
+ // Use native DOM scroll & resize events instead of YUI synthetic event.
+ window.onscroll = onscroll;
+ window.onresize = function() {
+
+ onscroll();
+
+ // Resize headers & footers.
+ // This is an expensive operation, not expected to happen often.
+ var headers = Y.all('#gradebook-header-container .gradebook-header-cell');
+ var resizedcells = Y.all('#user-grades .heading .cell');
+
+ var headeroffsetleft = Y.one('#studentheader').getX();
+ var newcontainerwidth = 0;
+ resizedcells.each(function(cell, idx) {
+ var headercell = headers.item(idx);
+
+ newcontainerwidth += cell.get('offsetWidth');
+ var styles = {
+ width: cell.get('offsetWidth'),
+ left: cell.getX() - headeroffsetleft + 'px'
+ };
+ headercell.setStyles(styles);
+ });
+
+ var footers = Y.all('#gradebook-footer-container .gradebook-footer-cell');
+
+ if (footers.size() !== 0) {
+ var resizedavgcells = Y.all('#user-grades .avg .cell');
+
+ resizedavgcells.each(function(cell, idx) {
+ var footercell = footers.item(idx);
+ var styles = {
+ width: cell.get('offsetWidth'),
+ left: cell.getX() - headeroffsetleft + 'px'
+ };
+ footercell.setStyles(styles);
+ });
+ Y.one('#gradebook-footer-container').setStyle('width', newcontainerwidth);
+ }
+
+ Y.one('#gradebook-header-container').setStyle('width', newcontainerwidth);
+
+ };
+ }
+
+ // Remove loading screen. Need to do YUI synthetic event to trigger
+ // on all browsers.
+ Y.on('domready', function() {
+ Y.one('.gradebook-loading-screen').remove(true);
+ Y.all('#user-grades .overridden').setAttribute('aria-label', 'Overriden grade');
+ });
+ },
+ float_user_column: function() {
+ Y.log('Floating the user column.', 'debug', LOGNS);
+
+ // Grab the user names column
+ var user_column = Y.all('#user-grades .user.cell');
+
+ // Generate a floating table
+ var floating_user_column = Y.Node.create('');
+ var floating_user_column_height = 0;
+ var user_column_offset = this.node_student_cell.getY();
+
+ user_column.each(function(node) {
+
+ // Create cloned node and container.
+ // We'll absolutely position the container to each cell position,
+ // this will guarantee that student cells are always aligned.
+ var container_node = Y.Node.create('');
+
+ // Grab the username
+ var usernamenode = node.cloneNode(true);
+ container_node.append(usernamenode.getHTML());
+ usernamenode = null;
+
+ container_node.setStyles({
+ 'height': node.get('offsetHeight') + 'px',
+ 'width': node.get('offsetWidth') + 'px',
+ 'position': 'absolute',
+ 'top': (node.getY() - user_column_offset) + 'px'
+ });
+
+ floating_user_column_height += node.get('offsetHeight');
+ // Retrieve the corresponding row
+ var classes = node.ancestor().getAttribute('class').split(' ').join('.');
+ // Attach highlight event
+ container_node.on('click', function() {
+ Y.one('.' + classes).all('.grade').toggleClass('hmarked');
+ });
+ // Add the cloned nodes to our floating table
+ floating_user_column.appendChild(container_node);
+
+ }, this);
+
+ // Style the table
+ floating_user_column.setStyles({
+ 'position': 'absolute',
+ 'left': this.node_student_cell.getX() + 'px',
+ 'top': this.node_student_cell.getY() + 'px',
+ 'width': this.node_student_cell.get('offsetWidth'),
+ 'height': floating_user_column_height + 'px',
+ 'background-color': '#f9f9f9'
+ });
+
+ Y.one('body').append(floating_user_column);
+ },
+ float_user_header: function() {
+ Y.log('Floating the user column header.', 'debug', LOGNS);
+
+ // Float the 'user name' header cell.
+ var floating_user_header_cell = Y.Node.create('');
+
+ // Clone the node
+ var cellnode = this.node_student_header_cell.cloneNode(true);
+ // Append node contents
+ floating_user_header_cell.append(cellnode.getHTML());
+ floating_user_header_cell.setStyles({
+ 'position': 'absolute',
+ 'left': this.node_student_cell.getX() + 'px',
+ 'top': this.node_student_header_cell.getY() + 'px',
+ 'width': '200px',
+ 'height': this.node_student_header_cell.get('offsetHeight') + 'px'
+ });
+
+ // Safe for collection
+ cellnode = null;
+
+ Y.one('body').append(floating_user_header_cell);
+ },
+ float_assignment_header: function() {
+ Y.log('Floating the assignment header.', 'debug', LOGNS);
+
+ var grade_headers = Y.all('#user-grades tr.heading .cell');
+
+ // Generate a floating headers
+ var floating_grade_headers = Y.Node.create('');
+
+ var floating_grade_headers_width = 0;
+ var floating_grade_headers_height = 0;
+ var grade_headers_offset = this.node_student_header_cell.getX();
+
+ grade_headers.each(function(node) {
+
+ // Get the target column to highlight. This is embedded in
+ // the column cell #, but it's off by one, so need to adjust for that.
+ var col = node.getAttribute('class');
+
+ // Extract the column #
+ var search = /c[0-9]+/g;
+ var match = search.exec(col);
+ match = match[0].replace('c', '');
+
+ // Offset
+ var target_col = parseInt(match, 10);
+ ++target_col;
+
+ var nodepos = node.getX();
+
+ // We need to clone the node, otherwise we mutate original obj
+ var nodeclone = node.cloneNode(true);
+
+ var newnode = Y.Node.create('');
+ newnode.append(nodeclone.getHTML());
+ newnode.addClass(nodeclone.getAttribute('class'));
+ nodeclone = null;
+
+ newnode.setStyles({
+ 'width': node.get('offsetWidth') + 'px',
+ 'height': node.get('offsetHeight') + 'px',
+ 'position': 'absolute',
+ 'left': (nodepos - grade_headers_offset) + 'px'
+ });
+
+ // Sum up total width
+ floating_grade_headers_width += parseInt(node.get('offsetWidth'), 10);
+ floating_grade_headers_height = node.get('offsetHeight');
+
+ // Attach 'highlight column' event to new node
+ newnode.on('click', function() {
+ Y.all('.cell.c' + target_col).toggleClass('vmarked');
+ });
+
+ // Append to floating table.
+ floating_grade_headers.appendChild(newnode);
+ }, this);
+
+ // Position header table.
+ floating_grade_headers.setStyles({
+ 'position': 'absolute',
+ 'top': this.node_student_header_cell.getY() + 'px',
+ 'left': this.node_student_header_cell.getX() + 'px',
+ 'width': floating_grade_headers_width + 'px',
+ 'height': floating_grade_headers_height + 'px'
+ });
+
+ Y.one('body').append(floating_grade_headers);
+ },
+ float_assignment_footer: function() {
+ Y.log('Floating the averages footer.', 'debug', LOGNS);
+
+ // Generate the sticky footer row.
+ // Grab the row.
+ var footer_row = Y.all('#user-grades .lastrow .cell');
+ // Create a container.
+ var floating_grade_footers = Y.Node.create('');
+ var floating_grade_footer_width = 0;
+ var footer_row_offset = this.node_footer_row.getX();
+ // Copy nodes
+ footer_row.each(function(node) {
+
+ var nodepos = node.getX();
+ var cellnodeclone = node.cloneNode(true);
+
+ var newnode = Y.Node.create('');
+ newnode.append(cellnodeclone.getHTML());
+ newnode.setStyles({
+ 'width': node.get('offsetWidth') + 'px',
+ 'height': '50px',
+ 'position': 'absolute',
+ 'left': (nodepos - footer_row_offset) + 'px'
+ });
+
+ floating_grade_footers.append(newnode);
+ floating_grade_footer_width += parseInt(node.get('offsetWidth'), 10);
+ }, this);
+
+ // Attach 'Update' button.
+ var update_button = Y.one('#gradersubmit');
+ if (update_button) {
+ var button = Y.Node.create('');
+ button.on('click', function() {
+ YUI().use('node-event-simulate', function(Y) {
+ Y.one('#gradersubmit').simulate('click');
+ });
+ });
+ floating_grade_footers.one('.gradebook-footer-cell').append(button);
+ }
+
+ // Position the row
+ floating_grade_footers.setStyles({
+ 'position': 'absolute',
+ 'left': this.node_footer_row.getX() + 'px',
+ 'bottom': '0',
+ 'height': '50px',
+ 'width': floating_grade_footer_width + 'px'
+ });
+
+ Y.one('body').append(floating_grade_footers);
+ }
+};
diff --git a/grade/report/grader/yui/src/gradereporttable/meta/gradereporttable.json b/grade/report/grader/yui/src/gradereporttable/meta/gradereporttable.json
new file mode 100644
index 00000000000..ce28d26304a
--- /dev/null
+++ b/grade/report/grader/yui/src/gradereporttable/meta/gradereporttable.json
@@ -0,0 +1,9 @@
+{
+ "moodle-local_ucla-gradebooktable": {
+ "requires": [
+ "node",
+ "event",
+ "node-event-simulate"
+ ]
+ }
+}
\ No newline at end of file