From 82b945dbbef467ecdf532074424f2042b61e8c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Massart?= <fred@moodle.com> Date: Fri, 23 Sep 2016 12:40:48 +0200 Subject: [PATCH] MDL-56095 output: Make the progress bar templatable The order of inclusion of weblib and outputlib had to change as the progress_bar (weblib) uses interfaces defined in outputlib. --- lib/javascript-static.js | 39 +++++------ lib/outputrenderers.php | 14 ++++ lib/setup.php | 2 +- lib/templates/progress_bar.mustache | 64 +++++++++++++++++++ lib/weblib.php | 36 ++++++----- .../templates/core/progress_bar.mustache | 62 ++++++++++++++++++ 6 files changed, 182 insertions(+), 35 deletions(-) create mode 100644 lib/templates/progress_bar.mustache create mode 100644 theme/boost/templates/core/progress_bar.mustache diff --git a/lib/javascript-static.js b/lib/javascript-static.js index e0438e69198..dc56fe35d18 100644 --- a/lib/javascript-static.js +++ b/lib/javascript-static.js @@ -1300,30 +1300,33 @@ function stripHTML(str) { } function updateProgressBar(id, percent, msg, estimate) { - var progressIndicator = Y.one('#' + id); - if (!progressIndicator) { + var event, + el = document.getElementById(id), + eventData = {}; + + if (!el) { return; } - var progressBar = progressIndicator.one('.bar'), - statusIndicator = progressIndicator.one('h2'), - estimateIndicator = progressIndicator.one('p'); + eventData.message = msg; + eventData.percent = percent; + eventData.estimate = estimate; - statusIndicator.set('innerHTML', Y.Escape.html(msg)); - progressBar.set('innerHTML', Y.Escape.html('' + percent + '%')); - if (percent === 100) { - progressIndicator.addClass('progress-success'); - estimateIndicator.set('innerHTML', null); - } else { - if (estimate) { - estimateIndicator.set('innerHTML', Y.Escape.html(estimate)); - } else { - estimateIndicator.set('innerHTML', null); + try { + event = new CustomEvent('update', { + bubbles: false, + cancelable: true, + detail: eventData + }); + } catch (exception) { + if (!(exception instanceof TypeError)) { + throw exception; } - progressIndicator.removeClass('progress-success'); + event = document.createEvent('Event'); + event.initCustomEvent('update', false, true, eventData); } - progressBar.setAttribute('aria-valuenow', percent); - progressBar.setStyle('width', percent + '%'); + + el.dispatchEvent(event); } // ===== Deprecated core Javascript functions for Moodle ==== diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index fc95c5d5eb2..01f6c2588c0 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -4333,6 +4333,20 @@ EOD; return false; } } + + /** + * Renders a progress bar. + * + * Do not use $OUTPUT->render($bar), instead use progress_bar::create(). + * + * @param progress_bar $bar The bar. + * @return string HTML fragment + */ + public function render_progress_bar(progress_bar $bar) { + global $PAGE; + $data = $bar->export_for_template($this); + return $this->render_from_template('core/progress_bar', $data); + } } /** diff --git a/lib/setup.php b/lib/setup.php index b5970239918..612f077728e 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -587,8 +587,8 @@ core_date::store_default_php_timezone(); // Load up standard libraries require_once($CFG->libdir .'/filterlib.php'); // Functions for filtering test as it is output require_once($CFG->libdir .'/ajax/ajaxlib.php'); // Functions for managing our use of JavaScript and YUI -require_once($CFG->libdir .'/weblib.php'); // Functions relating to HTTP and content require_once($CFG->libdir .'/outputlib.php'); // Functions for generating output +require_once($CFG->libdir .'/weblib.php'); // Functions relating to HTTP and content require_once($CFG->libdir .'/navigationlib.php'); // Class for generating Navigation structure require_once($CFG->libdir .'/dmllib.php'); // Database access require_once($CFG->libdir .'/datalib.php'); // Legacy lib with a big-mix of functions. diff --git a/lib/templates/progress_bar.mustache b/lib/templates/progress_bar.mustache new file mode 100644 index 00000000000..7a2653e80eb --- /dev/null +++ b/lib/templates/progress_bar.mustache @@ -0,0 +1,64 @@ +{{! + 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 <http://www.gnu.org/licenses/>. +}} +{{! + Progress bar. + + Example context (json): + { + id: 'progressbar_test', + width: '500' + } +}} +<div class="progressbar_container" style="width: {{width}}px;" id="{{id}}"> + <h2 id="{{id}}_status"></h2> + <div class="progress progress-striped active"> + <div id="{{id}}_bar" class="bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"> </div> + </div> + <p id="{{id}}_estimate"></p> +</div> + +{{! We must not use the JS helper otherwise this gets executed too late. }} +<script type="text/javascript"> +(function() { + var el = document.getElementById('{{id}}'), + progressBar = document.getElementById('{{id}}_bar'), + statusIndicator = document.getElementById('{{id}}_status'), + estimateIndicator = document.getElementById('{{id}}_estimate'); + + el.addEventListener('update', function(e) { + var msg = e.detail.message, + percent = e.detail.percent, + estimate = e.detail.estimate; + + statusIndicator.textContent = msg; + progressBar.textContent = '' + percent + '%'; + if (percent === 100) { + el.classList.add('progress-success'); + estimateIndicator.textContent = ''; + } else { + if (estimate) { + estimateIndicator.textContent = estimate; + } else { + estimateIndicator.textContent = ''; + } + el.classList.remove('progress-success'); + } + progressBar.setAttribute('aria-valuenow', percent); + progressBar.setAttribute('style', 'width: ' + percent + '%'); + }); +})(); +</script> diff --git a/lib/weblib.php b/lib/weblib.php index 69160ab1003..db4d76e6c78 100644 --- a/lib/weblib.php +++ b/lib/weblib.php @@ -3182,7 +3182,7 @@ function is_in_popup() { * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package core */ -class progress_bar { +class progress_bar implements renderable, templatable { /** @var string html id */ private $html_id; /** @var int total width */ @@ -3223,26 +3223,15 @@ class progress_bar { * @return void Echo's output */ public function create() { - global $PAGE; + global $OUTPUT; $this->time_start = microtime(true); if (CLI_SCRIPT) { return; // Temporary solution for cli scripts. } - $PAGE->requires->string_for_js('secondsleft', 'moodle'); - - $htmlcode = <<<EOT - <div class="progressbar_container" style="width: {$this->width}px;" id="{$this->html_id}"> - <h2></h2> - <div class="progress progress-striped active"> - <div class="bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"> </div> - </div> - <p></p> - </div> -EOT; flush(); - echo $htmlcode; + echo $OUTPUT->render($this); flush(); } @@ -3276,15 +3265,17 @@ EOT; // No significant change, no need to update anything. return; } + + $estimatemsg = null; if (is_numeric($estimate)) { - $estimate = get_string('secondsleft', 'moodle', round($estimate, 2)); + $estimatemsg = get_string('secondsleft', 'moodle', round($estimate, 2)); } $this->percent = round($percent, 2); $this->lastupdate = microtime(true); echo html_writer::script(js_writer::function_call('updateProgressBar', - array($this->html_id, $this->percent, $msg, $estimate))); + array($this->html_id, $this->percent, $msg, $estimatemsg))); flush(); } @@ -3343,6 +3334,19 @@ EOT; $this->lastupdate = 0; $this->time_start = 0; } + + /** + * Export for template. + * + * @param renderer_base $output The renderer. + * @return array + */ + public function export_for_template(renderer_base $output) { + return [ + 'id' => $this->html_id, + 'width' => $this->width, + ]; + } } /** diff --git a/theme/boost/templates/core/progress_bar.mustache b/theme/boost/templates/core/progress_bar.mustache new file mode 100644 index 00000000000..7a9d4f6193d --- /dev/null +++ b/theme/boost/templates/core/progress_bar.mustache @@ -0,0 +1,62 @@ +{{! + 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 <http://www.gnu.org/licenses/>. +}} +{{! + Progress bar. + + Example context (json): + { + id: 'progressbar_test', + width: '500' + } +}} +<div class="row" id="{{id}}" class="progressbar_container"> + <div class="col-md-6 push-md-3"> + <p id="{{id}}_status" class="text-xs-center"></p> + <progress id="{{id}}_bar" class="progress progress-striped progress-animated" value="0" max="100"></progress> + <p id="{{id}}_estimate" class="text-xs-center"></p> + </div> +</div> + +{{! We must not use the JS helper otherwise this gets executed too late. }} +<script type="text/javascript"> +(function() { + var el = document.getElementById('{{id}}'), + progressBar = document.getElementById('{{id}}_bar'), + statusIndicator = document.getElementById('{{id}}_status'), + estimateIndicator = document.getElementById('{{id}}_estimate'); + + el.addEventListener('update', function(e) { + var msg = e.detail.message, + percent = e.detail.percent, + estimate = e.detail.estimate; + + statusIndicator.textContent = msg; + progressBar.setAttribute('value', Math.round(percent)); + if (percent === 100) { + progressBar.classList.add('progress-success'); + estimateIndicator.textContent = '100%'; + } else { + if (estimate) { + estimateIndicator.textContent = estimate + ' - ' + percent + '%'; + } else { + estimateIndicator.textContent = '' + percent + '%'; + } + progressBar.classList.remove('progress-success'); + } + }); +})(); +</script>