diff --git a/grade/report/grader/index.php b/grade/report/grader/index.php index 85e6776b9de..473669ac922 100644 --- a/grade/report/grader/index.php +++ b/grade/report/grader/index.php @@ -52,8 +52,7 @@ 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-gradereporttable', 'M.gradereport_grader.gradereporttable.init', array()); +$PAGE->requires->yui_module('moodle-gradereport_grader-gradereporttable', 'Y.M.gradereport_grader.init'); // basic access checks if (!$course = $DB->get_record('course', array('id' => $courseid))) { @@ -194,15 +193,6 @@ 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/lang/en/gradereport_grader.php b/grade/report/grader/lang/en/gradereport_grader.php index 7f18997187f..5286ba369d0 100644 --- a/grade/report/grader/lang/en/gradereport_grader.php +++ b/grade/report/grader/lang/en/gradereport_grader.php @@ -35,3 +35,4 @@ $string['pluginname'] = 'Grader report'; $string['preferences'] = 'Grader report preferences'; $string['useractivitygrade'] = '{$a} grade'; $string['useractivityfeedback'] = '{$a} feedback'; +$string['overriddengrade'] = 'Overridden grade'; diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php index 2ad04b3a118..0143996f271 100644 --- a/grade/report/grader/lib.php +++ b/grade/report/grader/lib.php @@ -636,16 +636,14 @@ class grade_report_grader extends grade_report { $rows = $this->get_left_icons_row($rows, $colspan); - $rowclasses = array('even', 'odd'); - $suspendedstring = null; foreach ($this->users as $userid => $user) { $userrow = new html_table_row(); $userrow->id = 'fixed_user_'.$userid; - $userrow->attributes['class'] = 'r'.$this->rowcount++.' '.$rowclasses[$this->rowcount % 2]; $usercell = new html_table_cell(); $usercell->attributes['class'] = 'user'; + $usercell->attributes['data-uid'] = $userid; $usercell->header = true; $usercell->scope = 'row'; @@ -811,6 +809,7 @@ class grade_report_grader extends grade_report { $itemcell = new html_table_cell(); $itemcell->attributes['class'] = $type . ' ' . $catlevel . ' highlightable'. ' i'. $element['object']->id; + $itemcell->attributes['data-itemid'] = $element['object']->id; if ($element['object']->is_hidden()) { $itemcell->attributes['class'] .= ' dimmed_text'; @@ -852,8 +851,6 @@ class grade_report_grader extends grade_report { } $jsscales = $scalesarray; - $rowclasses = array('even', 'odd'); - foreach ($this->users as $userid => $user) { if ($this->canviewhidden) { @@ -868,7 +865,6 @@ class grade_report_grader extends grade_report { $itemrow = new html_table_row(); $itemrow->id = 'user_'.$userid; - $itemrow->attributes['class'] = $rowclasses[$this->rowcount % 2]; $fullname = fullname($user); $jsarguments['users'][$userid] = $fullname; @@ -880,6 +876,8 @@ class grade_report_grader extends grade_report { $itemcell = new html_table_cell(); $itemcell->id = 'u'.$userid.'i'.$itemid; + $itemcell->attributes['data-itemid'] = $itemid; + $itemcell->attributes['data-uid'] = $userid; // Get the decimal points preference for this item $decimalpoints = $item->get_decimals(); @@ -928,6 +926,7 @@ class grade_report_grader extends grade_report { } if ($grade->is_overridden()) { $itemcell->attributes['class'] .= ' overridden'; + $itemcell->attributes['aria-label'] = get_string('overriddengrade', 'gradereport_grader'); } if (!empty($grade->feedback)) { diff --git a/grade/report/grader/pix/corner-fold.png b/grade/report/grader/pix/corner-fold.png deleted file mode 100644 index 14f7089f4cf..00000000000 Binary files a/grade/report/grader/pix/corner-fold.png and /dev/null differ diff --git a/grade/report/grader/styles.css b/grade/report/grader/styles.css index d11d789a716..32f38d5a008 100644 --- a/grade/report/grader/styles.css +++ b/grade/report/grader/styles.css @@ -1,798 +1,155 @@ -.path-grade-report-grader .yui3-overlay { - border: 0; - background: none; - background-color: 'initial'; - min-width: 200px; -} -.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; -} -.path-grade-report-grader .graderreportoverlay.overriden { - border-top: 22px solid #f1c32a; -} -.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; -} -.path-grade-report-grader .graderreportoverlay .overriden { - background-color: #f1c32a; - width: 100%; - text-align: center; -} -.path-grade-report-grader .graderreportoverlay .fullname { - color: #444; -} -.path-grade-report-grader .graderreportoverlay .itemname { - padding-top: 4px; - color: #666; -} -.path-grade-report-grader .gradeparent { - overflow: inherit; +/* The grade information tooltip */ +.gradeparent .grader-information-tooltip { + min-width: 200px; } -table#user-grades { - font-size: 14px; -} -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 .avg th a, -table#user-grades .avg td a, -table#user-grades .heading th a { - color: white; - font-weight: normal; -} -table#user-grades .avg .cell { - font-weight: bold; - text-align: center; -} -table#user-grades .avg .cell.header { - text-align: right; -} -table#user-grades th { - font-weight: normal; -} -table#user-grades th.cell { - height: 20px; - white-space: nowrap; -} -.path-grade-report-history table#user-grades th.cell { - white-space: normal; -} -table#user-grades .controls { - text-align: right; - background-color: #eee; - height: 20px; -} -table#user-grades tr { - height: 40px; -} -table#user-grades tr .gradevalue { - width: 100%; - text-align: center; - display: inline-block; -} -table#user-grades tr .user { - min-width: 200px; - max-width: 200px; - width: 200px; - background-color: #777777; - border-color: #666666; -} -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; +.gradeparent .graderreportoverlay { + background-color: white; width: auto; - background-color: transparent; - border-style: solid; - border-width: 1px; - margin: 0; -} -.path-grade-report-grader #overDiv table { - margin: 0; -} -.path-grade-report-grader #overDiv table td.feedback { - border: 0; -} -.path-grade-report-grader #overDiv .feedback { - font-size: 70%; - background-color: #ABF; - color: #000; - font-family: Verdana; - font-weight: 400; -} -.path-grade-report-grader #overDiv .caption { - font-size: 70%; - background-color: #56C; - color: #CCF; - font-family: Arial; - font-weight: 700; -} -.path-grade-report-grader #overDiv .intersection { - font-size: 70%; - background-color: #ABF; - color: #000; - font-family: Verdana; - font-weight: 400; -} -.path-grade-report-grader #overDiv .intersectioncaption { - background-color: #56C; - color: #CCF; - font-family: Arial; - font-weight: 700; -} -.path-grade-report-grader div.submit { - margin-top: 20px; - text-align: center; -} -table#user-grades td { - text-align: right; - border-style: solid; - border-width: 0 1px 1px 0; -} -table#user-grades th.category { - vertical-align: top; - border-style: solid; - border-width: 1px 1px 0; -} -table#user-grades th.user { - text-align: left; - border-style: solid; - border-width: 1px 0; -} -table#user-grades th.userfield { - border-style: solid; - border-width: 1px; -} -table#user-grades th.categoryitem, -table#user-grades td.topleft { - vertical-align: bottom; - border-style: solid; - border-width: 0 1px; -} -.path-grade-report-grader td,.path-grade-report-grader th { - border-color: #CECECE; -} -.path-grade-report-grader table#participants th { - vertical-align: top; - width: auto; -} -table#user-grades td.fillerfirst { - border-style: solid; - border-width: 0 0 0 1px; -} -table#user-grades td.fillerlast { - border-style: solid; - border-width: 0 1px 0 0; -} -table#user-grades th.item, -table#user-grades th.categoryitem, -table#user-grades th.courseitem { - border-bottom-color: #000; - vertical-align: bottom; - border-style: solid; - border-width: 1px; -} -div.gradertoggle { - display: inline; - margin-left: 20px; -} -table#user-grades th.range { - text-align: right; - border-style: solid; - border-width: 1px; -} -table#user-grades .userpic { - display: inline; - margin-right: 10px; -} -table#user-grades .quickfeedback { - border: 1px dashed #000; - width: auto; - margin: 0; - padding: 0; - margin-left: 10px; -} -.dir-rtl table#user-grades .quickfeedback { - margin-left: 0; - margin-right: 10px; -} -.path-grade-report-grader #siteconfiglink { - text-align: right; -} -table#user-grades .datesubmitted { - font-size: .7em; -} -table#user-grades td.cell { - padding-left: 5px; - padding-right: 5px; - vertical-align: middle; -} -.path-grade-report-grader table { - border-collapse: collapse; - background-color: #fff; - border-color: #cecece; -} -.path-grade-report-grader th { - padding: 1px 10px; -} -.path-grade-report-grader span.inclusion-links { - margin: 0 5px 0 10px; -} -table#user-grades .item { - background-color: #e9e9e9; -} -.path-grade-report-grader table tr.odd th.header { - background-color: #efefef; - background-image: none; - border-width: 0 0 1px; -} -.path-grade-report-grader table tr.heading th.header { - border-top: 1px solid #cecece; -} -table#user-grades tr.heading th.categoryitem, -table#user-grades tr.heading th.courseitem { - border-width: 0 0 0 1px; -} -table#user-grades th.category.header.catlevel1 { - vertical-align: top; - border-style: solid; - border-width: 1px 1px 0 0; -} -.path-grade-report-grader div.left_scroller th.user a { - vertical-align: middle; - margin: 0; - padding: 0; -} -table#user-grades th.categoryitem, -table#user-grades th.courseitem, -.path-grade-report-grader table td.topleft { - vertical-align: bottom; - border-color: #cecece #cecece #000; - border-style: solid; - border-width: 0 1px 1px; -} -.path-grade-report-grader .left_scroller table td.topleft { - background-color: #fff; - border-bottom-color: #cecece; -} -table#user-grades td.topleft { - background-color: #fff; -} -.path-grade-report-grader th.user img.userpicture { - border: 3px double #cecece; - vertical-align: top; - width: 2.7em; - height: 2.7em; - margin-right: 10px; -} -.path-grade-report-grader a.quickedit { - line-height: 1em; - display: block; - float: right; - clear: none; - font-size: 9px; - background-color: transparent; - margin: .1em 0 0; -} -.path-grade-report-grader a.quickedit2 { - display: block; - float: right; - clear: none; - background-color: transparent; - margin: 1.3em 0 0; -} -.path-grade-report-grader table#quick_edit { - border: 1px solid #cecece; - margin: 0 auto; -} -.path-grade-report-grader table#quick_edit td { - vertical-align: middle; - border: 1px solid #cecece; - text-align: left; - margin: 0; - padding: 5px; -} -.path-grade-report-grader table#quick_edit td img { - border: 3px double #cecece; - vertical-align: middle; - padding: 0; -} -.path-grade-report-grader td input.text { - border: 1px solid #666; - width: auto; - margin: 0; - padding: 0; + padding: 10px; + border-color: #ddd; font-size: 12px; - height: 20px; - line-height: 20px; + box-shadow: #999999 2px 2px 3px; + border-radius: 4px; +} + +.gradebook-header-cell, +.gradeparent table th { + font-size: 14px; + font-weight: normal; + padding: 4px 5px 4px 5px; + border: 0 solid #ddd; + border-left-width: 1px; + border-top-width: 1px; +} + +/* General table properties */ +.gradeparent table td, +.gradeparent table th, +.gradeparent .cell, +.gradebook-footer-cell, +.gradebook-user-cell { + padding: 4px 5px; + vertical-align: middle; +} + +/* Grade Item titles */ +.gradebook-header-cell, +.gradebook-header-cell, +#gradebook-user-header-container, +.gradeparent tr.heading th.item, +.gradeparent tr.heading th.courseitem, +.gradeparent tr.heading th.userfield, +#studentheader { + white-space: nowrap; + background-color: #333; +} + +.gradeparent .gradebook-header-cell.item, +.gradeparent .gradebook-header-cell.item a, +.gradeparent .gradebook-header-cell.courseitem, +.gradeparent .gradebook-header-cell.courseitem a, +.gradeparent .gradebook-header-cell.userfield, +.gradeparent .gradebook-header-cell.userfield a, +.gradeparent #gradebook-user-header-container, +.gradeparent #gradebook-user-header-container a, +.gradeparent .gradebook-user-cell, +.gradeparent .gradebook-user-cell a, +.gradeparent tr.heading th.item, +.gradeparent tr.heading th.item a, +.gradeparent tr.heading th.courseitem, +.gradeparent tr.heading th.courseitem a, +.gradeparent tr.heading th.userfield, +.gradeparent tr.heading th.userfield a, +.gradeparent th a, +.gradeparent #studentheader a { + color: #fff; +} + +/* The username cells */ +.gradebook-user-cell, +.gradeparent th.user { + border-top: 0; + padding: 4px; + min-width: 200px; + max-width: 200px; + width: 200px; + border-color: #666666; + border-right-width: 1px; + border-left: none; + background-color: #333; + color: #ddd; +} + +.gradebook-user-cell:nth-child(odd), +.gradeparent tr:nth-child(odd) th.user { + background-color: #777; +} + +.gradebook-user-cell:nth-child(even), +.gradeparent tr:nth-child(even) th.user { + background-color: #5c5c5c; +} + +.gradebook-user-cell .userpicture, +.gradeparent th.user .userpicture { + margin-right: 4px; + border-radius: 50px; + border: none; + vertical-align: top; +} + +/* The top-left user header cell */ +#gradebook-user-header-container, +#studentheader { + padding: 4px 5px; + border-top: 1px solid #ddd; +} + +#studentheader { + border-left: none; +} + +/* The footer row */ +.gradebook-footer-cell, +.gradeparent .gradevalue, +.gradeparent .avg .cell { text-align: center; + width: 100%; } -.path-grade-report-grader td input.submit { - margin: 10px 10px 0px 10px; + +.gradeparent .gradevalue { + display: inline-block; } -.path-grade-report-grader table#quick_edit td.fullname { - border-left: 0; - padding-left: 5px; -} -.path-grade-report-grader table#quick_edit td.picture { + +.gradeparent table#user-grades tr.avg th, +.gradeparent table#user-grades tr.avg td, +.gradebook-footer-cell { + padding: 8px; + background-color: #333; + color: white; + font-weight: bold; + text-align: center; + border: 1px solid #444; border-right: 0; -} -.path-grade-report-grader table#quick_edit td.finalgrade input { - width: 5em; -} -.path-grade-report-grader h1 { - text-align: center; - clear: both; -} -.path-grade-report-grader input.center { - margin: 10px auto 0; -} -.path-grade-report-grader .lefttbody { - width: auto; - vertical-align: middle; -} -table#user-grades th.fixedcolumn { - border: 1px solid #cecece; - vertical-align: middle; -} -.path-grade-report-grader table#fixed_column th { - border: 1px solid #cecece; - vertical-align: middle; - border-right-color: #000; -} -.path-grade-report-grader table#fixed_column th.user{ - border-right-color: #cecece; -} -.path-grade-report-grader table#fixed_column { - padding-top: 20px; - border-top: 1px solid #cecece; - background-color: #fff; -} -.path-grade-report-grader .left_scroller { - float: left; - clear: none; -} -.path-grade-report-grader.dir-rtl .left_scroller { - float: right; -} -.path-grade-report-grader .right_scroller { - width: auto; - clear: none; - overflow-x: scroll; - overflow-y: hidden; -} -.path-grade-report-grader table tr.avg, -.path-grade-report-grader table tr.groupavg td, -.path-grade-report-grader table tr.avg td, -.path-grade-report-grader table tr.groupavg th, -.path-grade-report-grader table tr.avg th, -.path-grade-report-grader table tr.controls_row, -.path-grade-report-grader table tr.controls_row th, -.path-grade-report-grader table tr.range_row, -.path-grade-report-grader table tr.range_row th, -div.right_scroller tr { - height: 2em; -} -table#user-grades tr.groupavg td.cell, -tr.groupavg th.header { - background-color: #efffef; -} -.path-grade-report-grader form td.excluded { - color: red; -} -.path-grade-report-grader .excludedfloater { - font-weight: 700; - color: red; - font-size: 9px; - float: left; -} -.path-grade-report-grader span.gradepass { - color: #298721; -} -.path-grade-report-grader span.gradefail { - color: #890d0d; -} -.path-grade-report-grader .gradeweight { - color: #461d7c; - font-weight: 700; -} -.path-grade-report-grader td select { - font-size: 100%; - padding: 0; -} -.path-grade-report-grader .right_scroller td select { - font-size: 86%; - padding: 0; -} -.path-grade-report-grader tr.avg, -.path-grade-report-grader tr.controls, -.path-grade-report-grader td.controls, -.path-grade-report-grader th.controls, -.path-grade-report-grader tr.groupavg, -.path-grade-report-grader tr.range, -.path-grade-report-grader th.range, -.path-grade-report-grader td.range, -.path-grade-report-grader tr.heading th.range { - height: 2em!important; - white-space: nowrap; -} -.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; -} -table#user-grades tr.even td.grade.vmarked.overridden { - background-color: #f4a400; -} -table#user-grades tr.even td.grade.hmarked { - background-color: #f5cf2c; - border-bottom-color: #f5cf2c; -} -table#user-grades tr.even td.grade.hmarked.overridden { - background-color: #f5cf2c; -} -table#user-grades tr.even td.grade.vmarked.hmarked { - background-color: #f1be00; - border-bottom-color: #f1be00; -} -table#user-grades tr.even td.grade.vmarked.hmarked.overridden { - background-color: #f1be00; -} -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 .overridden .grade_icons { - padding-left: 10px; -} -.path-grade-report-grader .yui3-overlay { - background-color: #FFEE69; - border-color: #D4C237 #A6982B #A6982B; - border-style: solid; - border-width: 1px; - left: 0; - padding: 2px 5px; - font-size: 0.7em; -table#user-grades .catlevel1 .action-icon img { - opacity: 0.5; -} -table#user-grades .catlevel1 .action-icon.selected img { - opacity: 1; -} - -#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; -} - -#gradebook-user-container { - background-color: #777; -} -#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;*/ + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } #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; + display: none; } + #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; + background-color: #444; + display: block; + border-bottom: 0px solid #444; } -#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 { - bottom: 0; -} - -/** MDL-43824 **/ -#page-grade-report-grader-index table#fixed_column td.topleft.cell, -#page-grade-report-grader-index.jsenabled table#fixed_column td.topleft.cell { - padding: 8px 5px; -} -#page-grade-report-grader-index table#fixed_column td.header.controls { - border-left: 1px solid #cecece; -} -.path-grade-report-grader .right_scroller td select { - line-height: 2; - margin: 0; - padding: 0; - height: 22px; -} -table#user-grades { - margin-bottom: 0; -} -table#user-grades td, -table#user-grades th.category { - padding: 8px 5px; -} -.path-grade-report-grader .gradeparent { - border-top: 1px solid #cecece; -} -.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 { - padding: 8px 5px; -} -.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); - } +.gradebook-footer-cell:first-child, +.gradeparent table#user-grades tr.avg th.range { + text-align: right; } /** 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 index 4d2378b0e49..795ffa1c827 100644 --- 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 @@ -15,383 +15,767 @@ YUI.add('moodle-gradereport_grader-gradereporttable', function (Y, NAME) { // 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. + * Grader Report Functionality. * + * @module moodle-gradereport_grader-gradereporttable * @package gradereport_grader * @copyright 2014 UC Regents - * @author Alfonso Roman * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @author Alfonso Roman */ -var LOGNS = 'moodle-gradereport_grader-gradereporttable'; +/** + * @module 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'); +var SELECTORS = { + FOOTERROW: '#user-grades .avg', + GRADECELL: 'td.grade', + GRADERTABLE: '.gradeparent table', + GRADEPARENT: '.gradeparent', + HEADERCELL: '.gradebook-header-cell', + STUDENTHEADER: '#studentheader', + USERCELL: '#user-grades .user.cell' }, - // Init module - init: function() { - Y.log('Loading grader report floating headers and columns.', 'debug', LOGNS); + CSS = { + OVERRIDDEN: 'overridden', + STICKYFOOTER: 'gradebook-footer-row-sticky', + TOOLTIPACTIVE: 'tooltipactive' + }; - // 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'); +/** + * The Grader Report Table. + * + * @namespace M.gradereport_grader + * @class ReportTable + * @constructor + */ +function ReportTable() { + ReportTable.superclass.constructor.apply(this, arguments); +} - // 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(); +Y.extend(ReportTable, Y.Base, { + /** + * Array of EventHandles. + * + * @type EventHandle[] + * @property _eventHandles + * @protected + */ + _eventHandles: [], - // Onscroll event updates all the floating header/column positions. - var onscroll = function() { + /** + * A Node reference to the grader table. + * + * @property graderTable + * @type Node + */ + graderTable: null, - // 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 + /** + * Setup the grader report table. + * + * @method initializer + */ + initializer: function() { + // Some useful references within our target area. + this.graderRegion = Y.one(SELECTORS.GRADEPARENT); + this.graderTable = Y.one(SELECTORS.GRADERTABLE); - // - // First get all the readable values needed. + // Setup the floating headers. + this.setupFloatingHeaders(); - // Header row - var headercontainer = document.getElementById('gradebook-header-container'); - var userheadercell = document.getElementById('studentheader'); + // Setup the mouse tooltips. + this.setupTooltips(); - var usercolumnheader = document.getElementById('gradebook-user-header-container'); + // Hide the loading spinner - we've finished for the moment. + this._hideSpinner(); + }, - var headercelltop = userheadercell.offsetTop + userheadercell.offsetParent.offsetTop; + /** + * Show the loading spinner. + * + * @method showSpinner + * @protected + */ + showSpinner: function() { + // Show the grading spinner. + Y.one(SELECTORS.SPINNER).show(); + }, - // User column - var pageleftcutoff = window.pageXOffset; - var firstusercell = document.querySelectorAll("#user-grades .user.cell")[0]; - var firstusercellpos = firstusercell.offsetLeft + firstusercell.offsetParent.offsetLeft; + /** + * Hide the loading spinner. + * + * @method hideSpinner + * @protected + */ + hideSpinner: function() { + // Hide the grading spinner. + Y.one(SELECTORS.SPINNER).hide(); + }, - var usercolumn = document.getElementById('gradebook-user-container'); + /** + * Get the text content of the username for the specified grade item. + * + * @method getGradeUserName + * @param {Node} cell The grade item cell to obtain the username for + * @return {String} The string content of the username cell. + */ + getGradeUserName: function(cell) { + var userrow = cell.ancestor('tr'), + usercell = userrow.one("th.user .username"); - // Footer row - var lastrow = document.querySelectorAll('#user-grades .avg')[0]; - var footer, lastrowpos; + if (usercell) { + return usercell.get('text'); + } else { + return ''; + } + }, - // Check that Average footer is available. - if (lastrow !== undefined) { - footer = document.getElementById('gradebook-footer-container'); - lastrowpos = lastrow.offsetTop + lastrow.offsetParent.offsetTop; - } + /** + * Get the text content of the item name for the specified grade item. + * + * @method getGradeItemName + * @param {Node} cell The grade item cell to obtain the item name for + * @return {String} The string content of the item name cell. + */ + getGradeItemName: function(cell) { + var itemcell = Y.one("th.item[data-itemid='" + cell.getData('itemid') + "']"); + if (itemcell) { + return itemcell.get('text'); + } else { + return ''; + } + }, - // Viewport values - var pageYOffset = window.pageYOffset; - var windowInnerHeight = window.innerHeight; + /** + * Get the text content of any feedback associated with the grade item. + * + * @method getGradeFeedback + * @param {Node} cell The grade item cell to obtain the item name for + * @return {String} The string content of the feedback. + */ + getGradeFeedback: function(cell) { + return cell.getData('feedback'); + } +}); - // - // Next do all the writing. +Y.namespace('M.gradereport_grader').ReportTable = ReportTable; +Y.namespace('M.gradereport_grader').init = function(config) { + return new Y.M.gradereport_grader.ReportTable(config); +}; +// 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 . - // 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'; - } +/** + * @module moodle-gradereport_grader-gradereporttable + * @submodule floatingheaders + */ - // 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'; - } +/** + * Provides floating headers to the grader report. + * + * See {{#crossLink "M.gradereport_grader.ReportTable"}}{{/crossLink}} for details. + * + * @namespace M.gradereport_grader + * @class FloatingHeaders + */ - // Update footer - if (lastrow !== undefined) { - footer.style.left = userheadercell.offsetLeft + userheadercell.offsetParent.offsetLeft + 'px'; +var HEIGHT = 'height', + WIDTH = 'width', + OFFSETWIDTH = 'offsetWidth', + OFFSETHEIGHT = 'offsetHeight'; - 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'); - } - } - }; +function FloatingHeaders() {} - // Add the floating 'average' footer if available. - if (this.node_footer_row) { - this.float_assignment_footer(); - } +FloatingHeaders.ATTRS= { +}; - // Set floating element initial positions by simulating scroll. - onscroll(); +FloatingHeaders.prototype = { + /** + * The height of the page header if a fixed position, floating header + * was found. + * + * @property pageHeaderHeight + * @type Number + * @default 0 + * @protected + */ + pageHeaderHeight: 0, - // 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'); + /** + * A Node representing the header cell. + * + * @property headerCell + * @type Node + * @protected + */ + headerCell: null, - 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); - } + /** + * A Node representing the first cell which contains user name information. + * + * @property firstUserCell + * @type Node + * @protected + */ + firstUserCell: null, - Y.one('#gradebook-header-container').setStyle('width', newcontainerwidth); - - }; + /** + * A Node representing the original table footer row. + * + * @property tableFooterRow + * @type Node + * @protected + */ + tableFooterRow: null, + + /** + * A Node representing the floating footer row in the grading table. + * + * @property footerRow + * @type Node + * @protected + */ + footerRow: null, + + /** + * A Node representing the floating grade item header. + * + * @property gradeItemHeadingContainer + * @type Node + * @protected + */ + gradeItemHeadingContainer: null, + + /** + * A Node representing the floating user header. This is the header with the Surname/First name + * sorting. + * + * @property userColumnHeader + * @type Node + * @protected + */ + userColumnHeader: null, + + /** + * A Node representing the floating user column. This is the column containing all of the user + * names. + * + * @property userColumn + * @type Node + * @protected + */ + userColumn: null, + + /** + * The position of the bottom of the first user cell. + * This is used when processing the scroll event as an optimisation. It must be updated when + * additional rows are loaded, or the window changes in some fashion. + * + * @property firstUserCellBottom + * @type Node + * @protected + */ + firstUserCellBottom: 0, + + /** + * The position of the left of the first user cell. + * This is used when processing the scroll event as an optimisation. It must be updated when + * additional rows are loaded, or the window changes in some fashion. + * + * @property firstUserCellLeft + * @type Node + * @protected + */ + firstUserCellLeft: 0, + + /** + * The position of the top of the final user cell. + * This is used when processing the scroll event as an optimisation. It must be updated when + * additional rows are loaded, or the window changes in some fashion. + * + * @property lastUserCellTop + * @type Node + * @protected + */ + lastUserCellTop: 0, + + /** + * Array of EventHandles. + * + * @type EventHandle[] + * @property _eventHandles + * @protected + */ + _eventHandles: [], + + /** + * Setup the grader report table. + * + * @method setupFloatingHeaders + * @chainable + */ + setupFloatingHeaders: function() { + // Grab references to commonly used Nodes. + this.firstUserCell = Y.one(SELECTORS.USERCELL); + + if (!this.firstUserCell) { + // There was no first user cell - no need to do anything at this stage. + this._hideSpinner(); + return; } - // 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'); - }); + // Generate floating elements. + this._setupFloatingUserColumn(); + this._setupFloatingUserHeader(); + this._setupFloatingAssignmentHeaders(); + this._setupFloatingAssignmentFooter(); + + // Calculate the positions of edge cells. These are used for positioning of the floating headers. + // This must be called after the floating headers are setup, but before the scroll event handler is invoked. + this._calculateCellPositions(); + + // Setup the floating element initial positions by simulating scroll. + this._handleScrollEvent(); + + // Setup the event handlers. + this._setupEventHandlers(); + + return this; }, - 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'); + /** + * Calculate the positions of some cells. These values are used heavily + * in scroll event handling. + * + * @method _calculateCellPositions + * @protected + */ + _calculateCellPositions: function() { + // The header row shows the grade item headers and is floated to the top of the window. + this.headerCellTop = this.headerCell.getY(); - // 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(); + // The footer row shows the grade averages and will be floated to the page bottom. + if (this.tableFooterRow) { + this.footerRowPosition = this.tableFooterRow.getY(); + } - user_column.each(function(node) { + var userCellList = Y.all(SELECTORS.USERCELL); - // 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('
'); + // The left of the user cells matches the left of the headerCell. + this.firstUserCellLeft = this.headerCell.getX(); - // Grab the username - var usernamenode = node.cloneNode(true); - container_node.append(usernamenode.getHTML()); - usernamenode = null; + if (userCellList.size() > 1) { + // Use the top of the second cell for the bottom of the first cell. + // This is used when scrolling to fix the footer to the top edge of the window. + this.firstUserCellBottom = userCellList.item(1).getY(); - container_node.setStyles({ - 'height': node.get('offsetHeight') + 'px', - 'width': node.get('offsetWidth') + 'px', - 'position': 'absolute', - 'top': (node.getY() - user_column_offset) + 'px' - }); + // Use the top of the penultimate cell when scrolling the header. + // The header is the same size as the cells. + this.lastUserCellTop = userCellList.item(userCellList.size() - 2).getY(); + } else { + var firstItem = userCellList.item(0); + // We can't use the top of the second row as there is only one row. + this.lastUserCellTop = firstItem.getY(); - 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); + if (this.tableFooterRow) { + // The footer is present so we can use that. + this.firstUserCellBottom = this.footerRowPosition; + } else { + // No other clues - calculate the top instead. + this.firstUserCellBottom = firstItem.getY() + firstItem.get('offsetHeight'); + } + } + // Check whether a header is present and whether it is floating. + var header = Y.one('header'); + this.pageHeaderHeight = 0; + if (header) { + if (header.getComputedStyle('position') === 'fixed') { + this.pageHeaderHeight = header.get(OFFSETHEIGHT); + } + } + }, + + /** + * Setup the main event listeners. + * These deal with things like window events. + * + * @method _setupEventHandlers + * @protected + */ + _setupEventHandlers: function() { + this._eventHandles.push( + // Listen for window scrolls, resizes, and rotation events. + Y.one(Y.config.win).on('scroll', this._handleScrollEvent, this), + Y.one(Y.config.win).on('resize', this._handleResizeEvent, this), + Y.one(Y.config.win).on('orientationchange', this._handleResizeEvent, this) + ); + }, + + /** + * Create and setup the floating column of user names. + * + * @method _setupFloatingUserColumn + * @protected + */ + _setupFloatingUserColumn: function() { + // Grab all cells in the user names column. + var userColumn = Y.all(SELECTORS.USERCELL), + + // Create a floating table. + floatingUserColumn = Y.Node.create(''); + + // Generate the new fields. + userColumn.each(function(node) { + // Create and configure the new container. + var containerNode = Y.Node.create(''); + containerNode.set('innerHTML', node.get('innerHTML')) + .setAttribute('data-uid', node.ancestor('tr').getData('uid')) + .setStyles({ + height: node.getComputedStyle(HEIGHT), + width: node.getComputedStyle(WIDTH) + }); + + // Add the new nodes to our floating table. + floatingUserColumn.appendChild(containerNode); }, 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' + // Style the floating user container. + floatingUserColumn.setStyles({ + left: this.firstUserCell.getX() + 'px', + position: 'absolute', + top: this.firstUserCell.getY() + 'px' }); - Y.one('body').append(floating_user_column); + // Append to the grader region. + this.graderRegion.append(floatingUserColumn); + + // Store a reference to this for later - we use it in the event handlers. + this.userColumn = floatingUserColumn; }, - float_user_header: function() { - Y.log('Floating the user column header.', 'debug', LOGNS); + + /** + * Create and setup the floating username header cell. + * + * @method _setupFloatingUserHeader + * @protected + */ + _setupFloatingUserHeader: function() { + // We make various references to the this header cell. Store it for later. + this.headerCell = Y.one(SELECTORS.STUDENTHEADER); // Float the 'user name' header cell. - var floating_user_header_cell = Y.Node.create(''); + var floatingUserCell = 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' + floatingUserCell.set('innerHTML', this.headerCell.getHTML()); + floatingUserCell.setStyles({ + height: this.headerCell.getComputedStyle(HEIGHT), + left: this.firstUserCell.getX() + 'px', + position: 'absolute', + top: this.headerCell.getY() + 'px', + width: this.firstUserCell.getComputedStyle(WIDTH) }); - // Safe for collection - cellnode = null; + // Append to the grader region. + this.graderRegion.append(floatingUserCell); - Y.one('body').append(floating_user_header_cell); + // Store a reference to this for later - we use it in the event handlers. + this.userColumnHeader = floatingUserCell; }, - float_assignment_header: function() { - Y.log('Floating the assignment header.', 'debug', LOGNS); - var grade_headers = Y.all('#user-grades tr.heading .cell'); + /** + * Create and setup the floating grade item header row. + * + * @method _setupFloatingAssignmentHeaders + * @protected + */ + _setupFloatingAssignmentHeaders: function() { + var gradeHeaders = Y.all('#user-grades tr.heading .cell'); // Generate a floating headers - var floating_grade_headers = Y.Node.create(''); + var floatingGradeHeaders = 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 floatingGradeHeadersWidth = 0; + var floatingGradeHeadersHeight = 0; + var gradeHeadersOffset = this.headerCell.getX(); + gradeHeaders.each(function(node) { 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.append(node.getHTML()) + .addClass(node.getAttribute('class')) + .setData('itemid', node.getData('itemid')) + .setStyles({ + height: node.getComputedStyle(HEIGHT), + left: (nodepos - gradeHeadersOffset) + 'px', + position: 'absolute', + width: node.getComputedStyle(WIDTH) + }); - newnode.setStyles({ - 'width': node.get('offsetWidth') + 'px', - 'height': node.get('offsetHeight') + 'px', - 'position': 'absolute', - 'left': (nodepos - grade_headers_offset) + 'px' - }); + // Sum up total widths - these are used in the container styles. + // Use the offsetHeight and Width here as this contains the + // padding, margin, and borders. + floatingGradeHeadersWidth += parseInt(node.get(OFFSETWIDTH), 10); + floatingGradeHeadersHeight = node.get(OFFSETHEIGHT); - // 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); + // Append to our floating table. + floatingGradeHeaders.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' + floatingGradeHeaders.setStyles({ + height: floatingGradeHeadersHeight + 'px', + left: this.headerCell.getX() + 'px', + position: 'absolute', + top: this.headerCell.getY() + 'px', + width: floatingGradeHeadersWidth + 'px' }); - Y.one('body').append(floating_grade_headers); + // Insert in place before the grader headers. + this.userColumnHeader.insert(floatingGradeHeaders, 'before'); + + // Store a reference to this for later - we use it in the event handlers. + this.gradeItemHeadingContainer = floatingGradeHeaders; }, - float_assignment_footer: function() { - Y.log('Floating the averages footer.', 'debug', LOGNS); + + /** + * Create and setup the floating header row of grade item titles. + * + * @method _setupFloatingAssignmentFooter + * @protected + */ + _setupFloatingAssignmentFooter: function() { + this.tableFooterRow = Y.one('#user-grades .avg'); + if (!this.tableFooterRow) { + Y.log('Averages footer not found - unable to float it.', 'warn', LOGNS); + return; + } // Generate the sticky footer row. - // Grab the row. - var footer_row = Y.all('#user-grades .lastrow .cell'); + var footerCells = this.tableFooterRow.all('.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 floatingGraderFooter = Y.Node.create(''); + var footerWidth = 0; + var footerRowOffset = this.tableFooterRow.getX(); + // Copy cell content. + footerCells.each(function(node) { var newnode = Y.Node.create(''); - newnode.append(cellnodeclone.getHTML()); + newnode.set('innerHTML', node.getHTML()); newnode.setStyles({ - 'width': node.get('offsetWidth') + 'px', - 'height': '50px', - 'position': 'absolute', - 'left': (nodepos - footer_row_offset) + 'px' + height: this._getHeight(node), + left: (node.getX() - footerRowOffset) + 'px', + position: 'absolute', + width: this._getWidth(node) }); - floating_grade_footers.append(newnode); - floating_grade_footer_width += parseInt(node.get('offsetWidth'), 10); + floatingGraderFooter.append(newnode); + footerWidth += parseInt(node.get(OFFSETWIDTH), 10); }, this); // Attach 'Update' button. - var update_button = Y.one('#gradersubmit'); - if (update_button) { - var button = Y.Node.create(''); + var updateButton = Y.one('#gradersubmit'); + if (updateButton) { + // TODO decide what to do with classes here to make them compatible with the base themes. + var button = Y.Node.create(''); button.on('click', function() { - YUI().use('node-event-simulate', function(Y) { - Y.one('#gradersubmit').simulate('click'); - }); + updateButton.simulate('click'); }); - floating_grade_footers.one('.gradebook-footer-cell').append(button); + floatingGraderFooter.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' + floatingGraderFooter.setStyles({ + position: 'absolute', + left: this.tableFooterRow.getX() + 'px', + bottom: 0, + height: this._getHeight(this.tableFooterRow), + width: footerWidth + 'px', + borderBottomWidth: Y.DOM.getScrollbarWidth() + 'px' }); - Y.one('body').append(floating_grade_footers); + // Append to the grader region. + this.graderRegion.append(floatingGraderFooter); + + this.footerRow = floatingGraderFooter; + }, + + /** + * Process a Scroll Event on the window. + * + * @method _handleScrollEvent + * @protected + */ + _handleScrollEvent: function() { + // Performance is important in this function as it is called frequently and in quick succesion. + // To prevent layout thrashing when the DOM is repeatedly updated and queried, updated and queried, + // updates must be batched. + + // Next do all the calculations. + var gradeItemHeadingContainerStyles = {}, + userColumnHeaderStyles = {}, + userColumnStyles = {}, + footerStyles = {}; + + // Header position. + gradeItemHeadingContainerStyles.left = this.headerCell.getX(); + if (Y.config.win.pageYOffset + this.pageHeaderHeight > this.headerCellTop) { + if (Y.config.win.pageYOffset + this.pageHeaderHeight < this.lastUserCellTop) { + gradeItemHeadingContainerStyles.top = Y.config.win.pageYOffset + this.pageHeaderHeight + 'px'; + userColumnHeaderStyles.top = Y.config.win.pageYOffset + this.pageHeaderHeight + 'px'; + } else { + gradeItemHeadingContainerStyles.top = this.lastUserCellTop + 'px'; + userColumnHeaderStyles.top = this.lastUserCellTop + 'px'; + } + } else { + gradeItemHeadingContainerStyles.top = this.headerCellTop + 'px'; + userColumnHeaderStyles.top = this.headerCellTop + 'px'; + } + + // User column position. + if (Y.config.win.pageXOffset > this.firstUserCellLeft) { + userColumnStyles.left = Y.config.win.pageXOffset + 'px'; + userColumnHeaderStyles.left = Y.config.win.pageXOffset + 'px'; + } else { + userColumnStyles.left = this.firstUserCellLeft + 'px'; + userColumnHeaderStyles.left = this.firstUserCellLeft + 'px'; + } + + // Update footer. + if (this.footerRow) { + footerStyles.left = this.headerCell.getX(); + + // Determine whether the footer should now be shown as sticky. + var pageHeight = Y.config.win.pageYOffset + Y.config.win.innerHeight, + usablePageHeight = pageHeight - Y.DOM.getScrollbarWidth(); + if (usablePageHeight - this.pageHeaderHeight < this.footerRowPosition) { + // The footer is off the bottom of the page. + this.footerRow.addClass(CSS.STICKYFOOTER); + if (usablePageHeight - this.pageHeaderHeight > this.firstUserCellBottom) { + // The footer is above the bottom of the first user. + footerStyles.top = (pageHeight - this.footerRow.get(OFFSETHEIGHT)) + 'px'; + } else { + footerStyles.top = this.firstUserCellBottom; + } + } else { + footerStyles.top = this.footerRowPosition + 'px'; + this.footerRow.removeClass(CSS.STICKYFOOTER); + } + } + + // Finally, apply the styles. + this.gradeItemHeadingContainer.setStyles(gradeItemHeadingContainerStyles); + this.userColumnHeader.setStyles(userColumnHeaderStyles); + this.userColumn.setStyles(userColumnStyles); + this.footerRow.setStyles(footerStyles); + }, + + /** + * Process a size change Event on the window. + * + * @method _handleResizeEvent + * @protected + */ + _handleResizeEvent: function() { + // Recalculate the position of the edge cells for scroll positioning. + this._calculateCellPositions(); + + // Simulate a scroll. + this._handleScrollEvent(); + + // Resize headers & footers. + // This is an expensive operation, not expected to happen often. + var headers = this.gradeItemHeadingContainer.all(SELECTORS.HEADERCELL); + var resizedcells = Y.all('#user-grades .heading .cell'); + + var headeroffsetleft = this.headerCell.getX(); + var newcontainerwidth = 0; + resizedcells.each(function(cell, idx) { + var headercell = headers.item(idx); + + newcontainerwidth += cell.get(OFFSETWIDTH); + var styles = { + width: cell.getComputedStyle(WIDTH), + 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.getComputedStyle(WIDTH), + left: cell.getX() - headeroffsetleft + 'px' + }; + footercell.setStyles(styles); + }); + } + + this.gradeItemHeadingContainer.setStyle('width', newcontainerwidth); + }, + + /** + * Determine the height of the specified Node. + * + * With IE, the height used when setting a height is the offsetHeight. + * All other browsers set this as this inner height. + * + * @method _getHeight + * @protected + * @param {Node} node + * @return String + */ + _getHeight: function(node) { + if (Y.UA.ie) { + return node.get(OFFSETHEIGHT) + 'px'; + } else { + return node.getComputedStyle(HEIGHT); + } + }, + + /** + * Determine the width of the specified Node. + * + * With IE, the width used when setting a width is the offsetWidth. + * All other browsers set this as this inner width. + * + * @method _getWidth + * @protected + * @param {Node} node + * @return String + */ + _getWidth: function(node) { + if (Y.UA.ie) { + return node.get(OFFSETWIDTH) + 'px'; + } else { + return node.getComputedStyle(WIDTH); + } } }; +Y.Base.mix(Y.M.gradereport_grader.ReportTable, [FloatingHeaders]); -}, '@VERSION@'); + +}, '@VERSION@', {"requires": ["base", "node", "event", "node-event-simulate"]}); 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 index cfa5af8a406..91d7bb7a9ab 100644 --- 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 @@ -1 +1,2 @@ -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