Merge branch 'MDL-68200-master-take2' of git://github.com/rezaies/moodle

This commit is contained in:
Sara Arjona
2020-05-14 13:10:01 +02:00
16 changed files with 162 additions and 35 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
define ("core/user_date",["jquery","core/ajax","core/sessionstorage","core/config"],function(a,b,c,d){var e={},f=function(b){var c=a("html").attr("lang").replace(/-/g,"_");return"core_user_date/"+c+"/"+d.usertimezone+"/"+b.timestamp+"/"+b.format},g=function(a){return c.get(a)},h=function(a,b){c.set(a,b)},i=function(a){return"undefined"!=typeof e[a]},j=function(a){return e[a]},k=function(a,b){e[a]=b},l=function(a){var c=a.map(function(a){return{timestamp:a.timestamp,format:a.format}}),e={methodname:"core_get_user_dates",args:{contextid:d.contextid,timestamps:c}};return b.call([e],!0,!0)[0].then(function(b){b.dates.forEach(function(b,c){var d=a[c],e=f(d);h(e,b);d.deferred.resolve(b)})}).catch(function(b){a.forEach(function(a){a.deferred.reject(b)})})};return{get:function get(b){var c=[],d=[];b.forEach(function(b){var e=f(b);if(i(e)){d.push(j(e))}else{var h=a.Deferred(),l=g(e);if(l){h.resolve(l)}else{b.deferred=h;c.push(b)}k(e,h.promise());d.push(h.promise())}});if(c.length){l(c)}return a.when.apply(a,d).then(function(){return 1===arguments.length?[arguments[0]]:Array.apply(null,arguments)})},getUserMidnightForTimestamp:function getUserMidnightForTimestamp(a,b){var c=a>b,d=Math.abs(a-b),e=c?Math.floor(d/86400):Math.ceil(d/86400),f=e*86400,g=c?b+f:b-f;return g}}});
define ("core/user_date",["jquery","core/ajax","core/sessionstorage","core/config"],function(a,b,c,d){var e={},f=function(b){var c=a("html").attr("lang").replace(/-/g,"_");return"core_user_date/"+c+"/"+d.usertimezone+"/"+b.timestamp+"/"+b.format},g=function(a){return c.get(a)},h=function(a,b){c.set(a,b)},i=function(a){return"undefined"!=typeof e[a]},j=function(a){return e[a]},k=function(a,b){e[a]=b},l=function(a){var c=a.map(function(a){var b=a.hasOwnProperty("fixday")?a.fixday:1,c=a.hasOwnProperty("fixhour")?a.fixhour:1;return{timestamp:a.timestamp,format:a.format,type:a.type||"",fixday:b,fixhour:c}}),e={methodname:"core_get_user_dates",args:{contextid:d.contextid,timestamps:c}};return b.call([e],!0,!0)[0].then(function(b){b.dates.forEach(function(b,c){var d=a[c],e=f(d);h(e,b);d.deferred.resolve(b)})}).catch(function(b){a.forEach(function(a){a.deferred.reject(b)})})};return{get:function get(b){var c=[],d=[];b.forEach(function(b){var e=f(b);if(i(e)){d.push(j(e))}else{var h=a.Deferred(),l=g(e);if(l){h.resolve(l)}else{b.deferred=h;c.push(b)}k(e,h.promise());d.push(h.promise())}});if(c.length){l(c)}return a.when.apply(a,d).then(function(){return 1===arguments.length?[arguments[0]]:Array.apply(null,arguments)})},getUserMidnightForTimestamp:function getUserMidnightForTimestamp(a,b){var c=a>b,d=Math.abs(a-b),e=c?Math.floor(d/86400):Math.ceil(d/86400),f=e*86400,g=c?b+f:b-f;return g}}});
//# sourceMappingURL=user_date.min.js.map
File diff suppressed because one or more lines are too long
+12 -3
View File
@@ -107,9 +107,14 @@ define(['jquery', 'core/ajax', 'core/sessionstorage', 'core/config'],
*/
var loadDatesFromServer = function(dates) {
var args = dates.map(function(data) {
var fixDay = data.hasOwnProperty('fixday') ? data.fixday : 1;
var fixHour = data.hasOwnProperty('fixhour') ? data.fixhour : 1;
return {
timestamp: data.timestamp,
format: data.format
format: data.format,
type: data.type || '',
fixday: fixDay,
fixhour: fixHour
};
});
@@ -155,7 +160,8 @@ define(['jquery', 'core/ajax', 'core/sessionstorage', 'core/config'],
* Only dates not found in either cache will be sent to the server
* for transforming.
*
* A request object must have a timestamp key and a format key.
* A request object must have a timestamp key and a format key and
* optionally may have a type key.
*
* E.g.
* var request = [
@@ -165,7 +171,10 @@ define(['jquery', 'core/ajax', 'core/sessionstorage', 'core/config'],
* },
* {
* timestamp: 1293876000,
* format: '%A, %d %B %Y, %I:%M %p'
* format: '%A, %d %B %Y, %I:%M %p',
* type: 'gregorian',
* fixday: false,
* fixhour: false
* }
* ];
*
+14 -6
View File
@@ -120,7 +120,7 @@ class core_external extends external_api {
/**
* Returns description of get_string() result value
*
* @return string
* @return external_description
* @since Moodle 2.4
*/
public static function get_string_returns() {
@@ -189,7 +189,7 @@ class core_external extends external_api {
/**
* Returns description of get_string() result value
*
* @return array
* @return external_description
* @since Moodle 2.4
*/
public static function get_strings_returns() {
@@ -233,6 +233,9 @@ class core_external extends external_api {
[
'timestamp' => new external_value(PARAM_INT, 'unix timestamp'),
'format' => new external_value(PARAM_TEXT, 'format string'),
'type' => new external_value(PARAM_PLUGIN, 'The calendar type', VALUE_DEFAULT),
'fixday' => new external_value(PARAM_INT, 'Remove leading zero for day', VALUE_DEFAULT, 1),
'fixhour' => new external_value(PARAM_INT, 'Remove leading zero for hour', VALUE_DEFAULT, 1),
]
)
)
@@ -264,7 +267,12 @@ class core_external extends external_api {
self::validate_context($context);
$formatteddates = array_map(function($timestamp) {
return userdate($timestamp['timestamp'], $timestamp['format']);
$calendartype = $timestamp['type'];
$fixday = !empty($timestamp['fixday']);
$fixhour = !empty($timestamp['fixhour']);
$calendar = \core_calendar\type_factory::get_calendar_instance($calendartype);
return $calendar->timestamp_to_date_string($timestamp['timestamp'], $timestamp['format'], 99, $fixday, $fixhour);
}, $params['timestamps']);
return ['dates' => $formatteddates];
@@ -273,7 +281,7 @@ class core_external extends external_api {
/**
* Returns description of get_user_dates() result value
*
* @return array
* @return external_description
*/
public static function get_user_dates_returns() {
return new external_single_structure(
@@ -333,7 +341,7 @@ class core_external extends external_api {
/**
* Returns description of get_component_strings() result value
*
* @return array
* @return external_description
* @since Moodle 2.4
*/
public static function get_component_strings_returns() {
@@ -421,7 +429,7 @@ class core_external extends external_api {
/**
* Returns description of get_fragment() result value
*
* @return array
* @return external_description
* @since Moodle 3.1
*/
public static function get_fragment_returns() {
+7 -2
View File
@@ -203,7 +203,6 @@ class core_external_testcase extends externallib_advanced_testcase {
}
public function test_get_user_dates() {
global $USER, $CFG, $DB;
$this->resetAfterTest();
$this->setAdminUser();
@@ -222,6 +221,11 @@ class core_external_testcase extends externallib_advanced_testcase {
'timestamp' => 1293876000,
'format' => '%d %m %Y'
],
[
'timestamp' => 1293876000,
'format' => '%d %m %Y',
'type' => 'gregorian'
],
[
'timestamp' => 1293876000,
'format' => 'some invalid format'
@@ -233,6 +237,7 @@ class core_external_testcase extends externallib_advanced_testcase {
$this->assertEquals('Saturday, 1 January 2011, 6:00', $result['dates'][0]);
$this->assertEquals('1 01 2011', $result['dates'][1]);
$this->assertEquals('some invalid format', $result['dates'][2]);
$this->assertEquals('1 01 2011', $result['dates'][2]);
$this->assertEquals('some invalid format', $result['dates'][3]);
}
}
+92
View File
@@ -0,0 +1,92 @@
{{!
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/>.
}}
{{!
@template core/time_element
Template to display an HTML time element.
Classes required for JS:
* none
Data attributes required for JS:
* data-timestamp Number - The timestamp for the element.
* data-datetimeformat String - A valid format for the datetime attribute.
Context variables required for this template:
* timestamp Number - The timestamp for the element.
* userdateformat String - The user-facing date format
* datetimeformat String - A valid format for the datetime attribute. Defaults to the ISO-8601 format of '%Y-%m-%dT%H:%M%z'.
Example context (json):
{
"timestamp": 0,
"userdateformat": "%d %b %Y",
"datetimeformat": "%Y-%m-%dT%H:%M%z"
}
}}
<time id="time-{{$elementid}}{{uniqid}}{{/elementid}}" class="{{$elementclass}}{{timeclass}}{{/elementclass}}" datetime="{{$datetimeval}}{{datetime}}{{/datetimeval}}"
data-timestamp="{{$timestampval}}{{timestamp}}{{/timestampval}}"
data-datetimeformat="{{$datetimeformatval}}{{#datetimeformat}}{{.}}{{/datetimeformat}}{{^datetimeformat}}%Y-%m-%dT%H:%M%z{{/datetimeformat}}{{/datetimeformatval}}">
{{$datedisplay}}
{{#userdate}} {{$timestampval}}{{timestamp}}{{/timestampval}}, {{$userdateformatval}}{{userdateformat}}{{/userdateformatval}} {{/userdate}}
{{/datedisplay}}
</time>
{{#js}}
/** Fetches the formatted date/time for the time element's datetime attribute. */
require(['core/user_date'], function(UserDate) {
var root = document.getElementById('time-{{$elementid}}{{uniqid}}{{/elementid}}');
// Fetch value for the datetime attribute using core/user_date, if it's not available.
if (!root.getAttribute('datetime')) {
var dateTimeFormat = root.getAttribute('data-datetimeformat');
var timestamp = root.getAttribute('data-timestamp');
if (!dateTimeFormat.match(/%(?![YmdHMSzZ])./g)) {
var zeroPad = function(nNum, nPad) {
return ((Math.pow(10, nPad) + nNum) + '').slice(1);
};
var date = new Date(timestamp * 1000);
var datetime = dateTimeFormat.replace(/%./g, function(sMatch) {
return (({
'%Y': date.getFullYear(),
'%m': zeroPad(date.getMonth() + 1, 2),
'%d': zeroPad(date.getDate(), 2),
'%H': zeroPad(date.getHours(), 2),
'%M': zeroPad(date.getMinutes(), 2),
'%S': zeroPad(date.getSeconds(), 2),
'%z': date.toTimeString().replace(/.+GMT([+-]\d+).+/, '$1'),
'%Z': date.toTimeString().replace(/.+\((.+?)\)$/, '$1')
}[sMatch] || '') + '') || sMatch;
});
root.setAttribute('datetime', datetime);
} else {
// Otherwise, use core/user_date.
var timestamps = [{
timestamp: timestamp,
format: dateTimeFormat,
type: 'gregorian',
fixday: 0,
fixhour: 0
}];
UserDate.get(timestamps).done(function(dates) {
var datetime = dates.pop();
root.setAttribute('datetime', datetime);
});
}
}
});
{{/js}}
+4
View File
@@ -63,6 +63,10 @@ information provided here is intended especially for developers.
* The following functions have been updated to support passing in an array of group IDs (but still support passing in a single ID):
* groups_get_members_join()
* groups_get_members_ids_sql()
* Additional parameters were added to core_get_user_dates:
- type: specifies the calendar type. Optional, defaults to Gregorian.
- fixday: Whether to remove leading zero for day. Optional, defaults to 1.
- fixhour: Whether to remove leading zero for hour. Optional, defaults to 1.
=== 3.8 ===
* Add CLI option to notify all cron tasks to stop: admin/cli/cron.php --stop
+1 -2
View File
@@ -638,9 +638,8 @@ class post extends exporter {
private function get_author_subheading_html(stdClass $exportedauthor, int $timecreated) : string {
$fullname = $exportedauthor->fullname;
$profileurl = $exportedauthor->urls['profile'] ?? null;
$formatteddate = userdate($timecreated, get_string('strftimedaydatetime', 'core_langconfig'));
$name = $profileurl ? "<a href=\"{$profileurl}\">{$fullname}</a>" : $fullname;
$date = "<time>{$formatteddate}</time>";
$date = userdate_htmltime($timecreated, get_string('strftimedaydatetime', 'core_langconfig'));
return get_string('bynameondate', 'mod_forum', ['name' => $name, 'date' => $date]);
}
}
+10 -2
View File
@@ -257,7 +257,11 @@
<div class="author-info align-middle">
<div class="mb-1 line-height-3 text-truncate">{{fullname}}</div>
<div class="line-height-3">
{{#userdate}}{{discussion.times.created}}, {{#str}}strftimedatemonthabbr, langconfig{{/str}}{{/userdate}}
{{< core/time_element }}
{{$elementid}}created-{{discussion.id}}{{/elementid}}
{{$timestampval}}{{discussion.times.created}}{{/timestampval}}
{{$userdateformatval}}{{#str}}strftimedatemonthabbr, langconfig{{/str}}{{/userdateformatval}}
{{/core/time_element}}
</div>
</div>
</div>
@@ -277,7 +281,11 @@
<div class="line-height-3">
{{#latestpostid}}
<a href="{{{discussion.urls.viewlatest}}}" title="{{#userdate}}{{discussion.times.modified}},{{#str}}strftimerecentfull{{/str}}{{/userdate}}">
{{#userdate}}{{discussion.times.modified}}, {{#str}}strftimedatemonthabbr, langconfig{{/str}}{{/userdate}}
{{< core/time_element }}
{{$elementid}}modified-{{discussion.id}}{{/elementid}}
{{$timestampval}}{{discussion.times.modified}}{{/timestampval}}
{{$userdateformatval}}{{#str}}strftimedatemonthabbr, langconfig{{/str}}{{/userdateformatval}}
{{/ core/time_element }}
</a>
{{/latestpostid}}
</div>
@@ -77,7 +77,7 @@
<header id="post-header-{{id}}-{{uniqid}}">
{{^isdeleted}}
<div class="d-flex flex-wrap align-items-center mb-1">
<address class="mb-0 mr-2" tabindex="-1">
<div class="mr-2" tabindex="-1">
{{#author}}
<h4 class="h6 d-lg-inline-block mb-0 author-header mr-1">
{{#parentauthorname}}
@@ -105,10 +105,13 @@
{{/parentauthorname}}
</h4>
{{/author}}
<time class="text-muted">
{{#userdate}} {{timecreated}}, {{#str}} strftimerecentfull, core_langconfig {{/str}} {{/userdate}}
</time>
</address>
{{< core/time_element }}
{{$elementid}}created-{{id}}-{{uniqid}}{{/elementid}}
{{$elementclass}}text-muted{{/elementclass}}
{{$timestampval}}{{timecreated}}{{/timestampval}}
{{$userdateformatval}}{{#str}} strftimerecentfull, core_langconfig {{/str}}{{/userdateformatval}}
{{/core/time_element}}
</div>
<div class="d-flex align-items-center ml-auto">
{{#author.groups}}
@@ -76,14 +76,16 @@
}}>{{$subject}}{{{subject}}}{{/subject}}</h3>
{{/subjectheading}}
{{^isdeleted}}
<address tabindex="-1">
<div class="mb-3" tabindex="-1">
{{#html.authorsubheading}}{{{.}}}{{/html.authorsubheading}}
{{^html.authorsubheading}}
<time>
{{#userdate}} {{timecreated}}, {{#str}} strftimedaydatetime, core_langconfig {{/str}} {{/userdate}}
</time>
{{< core/time_element }}
{{$elementid}}created-{{id}}-{{uniqid}}{{/elementid}}
{{$timestampval}}{{timecreated}}{{/timestampval}}
{{$userdateformatval}}{{#str}} strftimedaydatetime, core_langconfig {{/str}}{{/userdateformatval}}
{{/core/time_element}}
{{/html.authorsubheading}}
</address>
</div>
{{/isdeleted}}
{{#isprivatereply}}
<div class="privatereplyinfo">
@@ -38,9 +38,7 @@
>
<a href="{{{urls.viewisolated}}}">{{subject}}</a>
{{^isdeleted}}
<address class="d-inline-block mb-0">
{{{html.authorsubheading}}}
</address>
{{{html.authorsubheading}}}
{{/isdeleted}}
<div data-region="replies-container">
+1 -2
View File
@@ -371,9 +371,8 @@ class mod_forum_generator extends testing_module_generator {
public function get_author_subheading_html(stdClass $exportedauthor, int $timecreated) : string {
$fullname = $exportedauthor->fullname;
$profileurl = $exportedauthor->urls['profile'] ?? null;
$formatteddate = userdate($timecreated, get_string('strftimedaydatetime', 'core_langconfig'));
$name = $profileurl ? "<a href=\"{$profileurl}\">{$fullname}</a>" : $fullname;
$date = "<time>{$formatteddate}</time>";
$date = userdate_htmltime($timecreated, get_string('strftimedaydatetime', 'core_langconfig'));
return get_string('bynameondate', 'mod_forum', ['name' => $name, 'date' => $date]);
}
}
+1 -1
View File
@@ -108,7 +108,7 @@ $PAGE->set_heading($course->fullname);
$PAGE->set_button(forum_search_form($course, $search));
if ($istypesingle && $displaymode == FORUM_MODE_NESTED_V2) {
$PAGE->add_body_class('reset-style');
$PAGE->add_body_class('nested-v2-display-mode reset-style');
$settingstrigger = $OUTPUT->render_from_template('mod_forum/settings_drawer_trigger', null);
$PAGE->add_header_action($settingstrigger);
}
+1 -1
View File
@@ -236,7 +236,7 @@ $allow-reset-style: true !default;
vertical-align: top;
div[role="main"] {
flex: 1;
flex: 1 0 auto;
}
.activity-navigation {
+1 -1
View File
@@ -17737,7 +17737,7 @@ body.reset-style #page-content {
padding-right: 1.25rem;
vertical-align: top; }
body.reset-style #page-content #region-main-box #region-main div[role="main"] {
flex: 1; }
flex: 1 0 auto; }
body.reset-style #page-content #region-main-box #region-main .activity-navigation {
overflow: hidden; }
body.reset-style #page-content #region-main-box #region-main.has-blocks {