diff --git a/admin/presets/tests/generator/lib.php b/admin/presets/tests/generator/lib.php
index b5a385c752a1..8d6ffc9385de 100644
--- a/admin/presets/tests/generator/lib.php
+++ b/admin/presets/tests/generator/lib.php
@@ -227,7 +227,6 @@ private function add_to_config_log(string $name, string $oldvalue, string $value
public function access_protected($object, string $property) {
$reflection = new ReflectionClass($object);
$property = $reflection->getProperty($property);
- $property->setAccessible(true);
return $property->getValue($object);
}
@@ -244,7 +243,6 @@ public function get_admin_preset_setting(string $category, string $settingname):
// Set method accessibility.
$method = new ReflectionMethod(manager::class, 'get_setting');
- $method->setAccessible(true);
// Get the proper adminpresets_setting instance.
$settingpage = $adminroot->locate($category);
diff --git a/admin/settings/plugins.php b/admin/settings/plugins.php
index 33ddda707519..43909fba3469 100644
--- a/admin/settings/plugins.php
+++ b/admin/settings/plugins.php
@@ -135,6 +135,18 @@
$temp->add($setting);
$ADMIN->add('authsettings', $temp);
+ // Toggle password visiblity icon.
+ $temp->add(new admin_setting_configselect('loginpasswordtoggle',
+ new lang_string('auth_loginpasswordtoggle', 'auth'),
+ new lang_string('auth_loginpasswordtoggle_desc', 'auth'),
+ TOGGLE_SENSITIVE_SMALL_SCREENS_ONLY,
+ [
+ TOGGLE_SENSITIVE_DISABLED => get_string('disabled', 'admin'),
+ TOGGLE_SENSITIVE_ENABLED => get_string('enabled', 'admin'),
+ TOGGLE_SENSITIVE_SMALL_SCREENS_ONLY => get_string('smallscreensonly', 'admin'),
+ ],
+ ));
+
$temp = new admin_externalpage('authtestsettings', get_string('testsettings', 'core_auth'), new moodle_url("/auth/test_settings.php"), 'moodle/site:config', true);
$ADMIN->add('authsettings', $temp);
diff --git a/admin/tool/dataprivacy/tests/expired_contexts_test.php b/admin/tool/dataprivacy/tests/expired_contexts_test.php
index abd8d997d6d6..ae50fbf2510b 100644
--- a/admin/tool/dataprivacy/tests/expired_contexts_test.php
+++ b/admin/tool/dataprivacy/tests/expired_contexts_test.php
@@ -2079,7 +2079,6 @@ public function test_progress_tracer_default() {
$rc = new \ReflectionClass(\tool_dataprivacy\expired_contexts_manager::class);
$rcm = $rc->getMethod('get_progress');
- $rcm->setAccessible(true);
$this->assertInstanceOf(\text_progress_trace::class, $rcm->invoke($manager));
}
@@ -2094,7 +2093,6 @@ public function test_progress_tracer_set() {
$rc = new \ReflectionClass(\tool_dataprivacy\expired_contexts_manager::class);
$rcm = $rc->getMethod('get_progress');
- $rcm->setAccessible(true);
$this->assertSame($mytrace, $rcm->invoke($manager));
}
diff --git a/admin/tool/dataprivacy/tests/filtered_userlist_test.php b/admin/tool/dataprivacy/tests/filtered_userlist_test.php
index 7d71da163707..4146e0ec7845 100644
--- a/admin/tool/dataprivacy/tests/filtered_userlist_test.php
+++ b/admin/tool/dataprivacy/tests/filtered_userlist_test.php
@@ -41,7 +41,6 @@ public function test_apply_expired_contexts_filters(array $initial, array $expir
$rc = new \ReflectionClass(\tool_dataprivacy\filtered_userlist::class);
$rcm = $rc->getMethod('set_userids');
- $rcm->setAccessible(true);
$rcm->invoke($userlist, $initial);
diff --git a/admin/tool/langimport/tests/locale_test.php b/admin/tool/langimport/tests/locale_test.php
index f2f121525adc..dbe51337b75d 100644
--- a/admin/tool/langimport/tests/locale_test.php
+++ b/admin/tool/langimport/tests/locale_test.php
@@ -84,7 +84,6 @@ public function test_set_locale(string $set, string $ret) {
$loc = new locale();
$rc = new \ReflectionClass(locale::class);
$rm = $rc->getMethod('set_locale');
- $rm->setAccessible(true);
// Capture current locale for later restore (funnily, using the set_locale() method itself.
$originallocale = $rm->invokeArgs($loc, [LC_ALL, 0]);
diff --git a/admin/tool/licensemanager/tests/manager_test.php b/admin/tool/licensemanager/tests/manager_test.php
index 2b9763c4ed49..3fdc0dcbf1a7 100644
--- a/admin/tool/licensemanager/tests/manager_test.php
+++ b/admin/tool/licensemanager/tests/manager_test.php
@@ -70,7 +70,6 @@ public function test_edit_existing_license() {
// We're testing a private method, so we need to setup reflector magic.
$method = new ReflectionMethod('\tool_licensemanager\manager', 'edit');
- $method->setAccessible(true); // Allow accessing of private method.
$method->invoke($manager, \tool_licensemanager\manager::ACTION_UPDATE, $testlicense->shortname);
// Should not create a new license when updating an existing license.
@@ -90,7 +89,6 @@ public function test_edit_license_not_exists() {
// We're testing a private method, so we need to setup reflector magic.
$method = new ReflectionMethod('\tool_licensemanager\manager', 'edit');
- $method->setAccessible(true); // Allow accessing of private method.
// Attempt to update a license that doesn't exist.
$formdata = [
@@ -111,7 +109,6 @@ public function test_edit_license_no_shortname() {
// We're testing a private method, so we need to setup reflector magic.
$method = new ReflectionMethod('\tool_licensemanager\manager', 'edit');
- $method->setAccessible(true); // Allow accessing of private method.
// Attempt to update a license without passing license shortname.
$formdata = [
@@ -148,7 +145,6 @@ public function test_edit_create_license() {
// We're testing a private method, so we need to setup reflector magic.
$method = new ReflectionMethod('\tool_licensemanager\manager', 'edit');
- $method->setAccessible(true); // Allow accessing of private method.
$method->invoke($manager, \tool_licensemanager\manager::ACTION_CREATE, $formdata['shortname']);
// Should create a new license in database.
@@ -180,7 +176,6 @@ public function test_change_license_order() {
// We're testing a private method, so we need to setup reflector magic.
$method = new ReflectionMethod('\tool_licensemanager\manager', 'change_license_order');
- $method->setAccessible(true); // Allow accessing of private method.
$method->invoke($manager, \tool_licensemanager\manager::ACTION_MOVE_UP, 'cc-nc-4.0');
$licenseorder = array_keys(license_manager::get_licenses());
diff --git a/admin/tool/mfa/factor/email/tests/factor_test.php b/admin/tool/mfa/factor/email/tests/factor_test.php
index e0923555e70f..55a45585eda3 100644
--- a/admin/tool/mfa/factor/email/tests/factor_test.php
+++ b/admin/tool/mfa/factor/email/tests/factor_test.php
@@ -39,7 +39,6 @@ public function test_check_verification_code() {
$emailfactorclass = new \factor_email\factor('email');
$rc = new \ReflectionClass($emailfactorclass::class);
$rcm = $rc->getMethod('check_verification_code');
- $rcm->setAccessible(true);
// Assigned email to be used in getting the email factor.
$USER->email = 'user@mail.com';
@@ -76,7 +75,6 @@ public function test_check_verification_code() {
// Cleans up email records once MFA passed.
$rcm = $rc->getMethod('post_pass_state');
- $rcm->setAccessible(true);
$rcm->invoke($emailfactorclass);
// Check if the email records have been deleted.
diff --git a/admin/tool/mfa/factor/sms/tests/factor_test.php b/admin/tool/mfa/factor/sms/tests/factor_test.php
index 978916fc1b43..49e3e9a33139 100644
--- a/admin/tool/mfa/factor/sms/tests/factor_test.php
+++ b/admin/tool/mfa/factor/sms/tests/factor_test.php
@@ -154,7 +154,6 @@ public function test_check_verification_code(): void {
// Check verification code.
$rcm = $rc->getMethod('check_verification_code');
- $rcm->setAccessible(true);
$this->assertTrue($rcm->invoke($smsfactor, $secretcode));
// Test that calling the revoke on the generic type revokes all.
diff --git a/admin/tool/mfa/factor/token/tests/factor_test.php b/admin/tool/mfa/factor/token/tests/factor_test.php
index 3a0b1450c66e..62c63cd92dd6 100644
--- a/admin/tool/mfa/factor/token/tests/factor_test.php
+++ b/admin/tool/mfa/factor/token/tests/factor_test.php
@@ -50,7 +50,6 @@ public function test_calculate_expiry_time_in_general() {
set_config('expireovernight', 0, 'factor_token');
$method = new \ReflectionMethod($this->factor, 'calculate_expiry_time');
- $method->setAccessible(true);
// Test that non-overnight timestamps are just exactly as configured.
// We don't need to care about 0 or negative ints, they will just make the cookie expire immediately.
@@ -95,7 +94,6 @@ public function test_calculate_expiry_time_in_general() {
public function test_calculate_expiry_time_for_overnight_expiry_with_one_day_expiry($timestamp) {
// Setup configuration.
$method = new \ReflectionMethod($this->factor, 'calculate_expiry_time');
- $method->setAccessible(true);
set_config('expireovernight', 1, 'factor_token');
set_config('expiry', DAYSECS, 'factor_token');
@@ -144,7 +142,6 @@ public function test_calculate_expiry_time_for_overnight_expiry_with_one_day_exp
public function test_calculate_expiry_time_for_overnight_expiry_with_two_day_expiry($timestamp) {
// Setup configuration.
$method = new \ReflectionMethod($this->factor, 'calculate_expiry_time');
- $method->setAccessible(true);
set_config('expireovernight', 1, 'factor_token');
set_config('expiry', 2 * DAYSECS, 'factor_token');
@@ -195,7 +192,6 @@ public function test_calculate_expiry_time_for_overnight_expiry_with_two_day_exp
public function test_calculate_expiry_time_for_overnight_expiry_with_three_hour_expiry($timestamp) {
// Setup configuration.
$method = new \ReflectionMethod($this->factor, 'calculate_expiry_time');
- $method->setAccessible(true);
set_config('expireovernight', 1, 'factor_token');
set_config('expiry', 3 * HOURSECS, 'factor_token');
@@ -240,7 +236,6 @@ public function test_calculate_expiry_time_for_overnight_expiry_with_three_hour_
public function test_calculate_expiry_time_for_overnight_expiry_with_an_hour_expiry($timestamp) {
// Setup configuration.
$method = new \ReflectionMethod($this->factor, 'calculate_expiry_time');
- $method->setAccessible(true);
set_config('expireovernight', 1, 'factor_token');
set_config('expiry', HOURSECS, 'factor_token');
diff --git a/admin/tool/mfa/tests/secret_manager_test.php b/admin/tool/mfa/tests/secret_manager_test.php
index b9b293f52ee8..d426dfe0b8f2 100644
--- a/admin/tool/mfa/tests/secret_manager_test.php
+++ b/admin/tool/mfa/tests/secret_manager_test.php
@@ -42,7 +42,6 @@ public function test_create_secret() {
// Mutate the sessionid using reflection.
$reflectedsessionid = new \ReflectionProperty($secman, 'sessionid');
- $reflectedsessionid->setAccessible(true);
$reflectedsessionid->setValue($secman, 'fakesession');
$sec1 = $secman->create_secret(1800, false);
@@ -97,7 +96,6 @@ public function test_add_secret_to_db() {
// Let's make stuff public using reflection.
$reflectedscanner = new \ReflectionClass($secman);
$reflectedmethod = $reflectedscanner->getMethod('add_secret_to_db');
- $reflectedmethod->setAccessible(true);
// Now add a secret and confirm it creates the correct record.
$reflectedmethod->invoke($secman, 'code', 1800);
@@ -164,7 +162,6 @@ public function test_validate_secret() {
// Session locked code from the same session id.
// Mutate the sessionid using reflection.
$reflectedsessionid = new \ReflectionProperty($secman, 'sessionid');
- $reflectedsessionid->setAccessible(true);
$reflectedsessionid->setValue($secman, 'fakesession');
$secret = $secman->create_secret(1800, true);
@@ -227,7 +224,6 @@ public function test_has_active_secret() {
$reflectedscanner = new \ReflectionClass($secman);
$reflectedmethod = $reflectedscanner->getMethod('has_active_secret');
- $reflectedmethod->setAccessible(true);
// DB secrets.
$this->assertFalse($reflectedmethod->invoke($secman));
@@ -244,7 +240,6 @@ public function test_has_active_secret() {
// Now check a secret with session involvement.
// Mutate the sessionid using reflection.
$reflectedsessionid = new \ReflectionProperty($secman, 'sessionid');
- $reflectedsessionid->setAccessible(true);
$reflectedsessionid->setValue($secman, 'fakesession');
$this->assertFalse($reflectedmethod->invoke($secman, true));
diff --git a/admin/tool/mobile/classes/local/hooks/output/standard_head_html_prepend.php b/admin/tool/mobile/classes/local/hook/output/before_standard_head_html_generation.php
similarity index 86%
rename from admin/tool/mobile/classes/local/hooks/output/standard_head_html_prepend.php
rename to admin/tool/mobile/classes/local/hook/output/before_standard_head_html_generation.php
index f349ea392606..7d4ddbb4dcc3 100644
--- a/admin/tool/mobile/classes/local/hooks/output/standard_head_html_prepend.php
+++ b/admin/tool/mobile/classes/local/hook/output/before_standard_head_html_generation.php
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-namespace tool_mobile\local\hooks\output;
+namespace tool_mobile\local\hook\output;
/**
* Allows plugins to add any elements to the page
html tag
@@ -23,14 +23,13 @@
* @copyright 2023 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class standard_head_html_prepend {
-
+class before_standard_head_html_generation {
/**
* Callback to add head elements.
*
- * @param \core\hook\output\standard_head_html_prepend $hook
+ * @param \core\hook\output\before_standard_head_html_generation $hook
*/
- public static function callback(\core\hook\output\standard_head_html_prepend $hook): void {
+ public static function callback(\core\hook\output\before_standard_head_html_generation $hook): void {
global $CFG, $PAGE;
// Smart App Banners meta tag is only displayed if mobile services are enabled and configured.
if (!empty($CFG->enablemobilewebservice)) {
@@ -45,7 +44,7 @@ public static function callback(\core\hook\output\standard_head_html_prepend $ho
if (!empty($mobilesettings->androidappid)) {
$mobilemanifesturl = "$CFG->wwwroot/$CFG->admin/tool/mobile/mobile.webmanifest.php";
- $hook->add_html('');
+ $hook->add_html('');
}
}
}
diff --git a/admin/tool/mobile/db/hooks.php b/admin/tool/mobile/db/hooks.php
index 60e2d927e8c8..91b54ffc7a5f 100644
--- a/admin/tool/mobile/db/hooks.php
+++ b/admin/tool/mobile/db/hooks.php
@@ -26,8 +26,8 @@
$callbacks = [
[
- 'hook' => core\hook\output\standard_head_html_prepend::class,
- 'callback' => 'tool_mobile\local\hooks\output\standard_head_html_prepend::callback',
+ 'hook' => core\hook\output\before_standard_head_html_generation::class,
+ 'callback' => 'tool_mobile\local\hook\output\before_standard_head_html_generation::callback',
'priority' => 0,
],
];
diff --git a/admin/tool/mobile/version.php b/admin/tool/mobile/version.php
index 7f18ff304820..adf67504ef0d 100644
--- a/admin/tool/mobile/version.php
+++ b/admin/tool/mobile/version.php
@@ -23,7 +23,7 @@
*/
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2023100900; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->version = 2024022600; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2023100400; // Requires this Moodle version.
$plugin->component = 'tool_mobile'; // Full name of the plugin (used for diagnostics).
$plugin->dependencies = [
diff --git a/admin/tool/usertours/classes/cache.php b/admin/tool/usertours/classes/cache.php
index 28f5eb34e10d..a053fc5fd11f 100644
--- a/admin/tool/usertours/classes/cache.php
+++ b/admin/tool/usertours/classes/cache.php
@@ -14,21 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Cache manager.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours;
-defined('MOODLE_INTERNAL') || die();
-
/**
* Cache manager.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
@@ -97,7 +88,7 @@ public static function get_matching_tourdata(\moodle_url $targetmatch) {
}
$target = $targetmatch->out_as_local_url();
- return array_filter($tours, function($tour) use ($possiblematches, $target) {
+ return array_filter($tours, function ($tour) use ($possiblematches, $target) {
if (in_array($tour->pathmatch, $possiblematches)) {
return true;
}
diff --git a/admin/tool/usertours/classes/configuration.php b/admin/tool/usertours/classes/configuration.php
index ae63554eb30e..2f18c29be7b7 100644
--- a/admin/tool/usertours/classes/configuration.php
+++ b/admin/tool/usertours/classes/configuration.php
@@ -14,26 +14,16 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Step configuration detail class.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours;
-defined('MOODLE_INTERNAL') || die();
-
/**
* Step configuration detail class.
*
- * @copyright 2016 Andrew Nicols
+ * @package tool_usertours
+ * @copyright 2024 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class configuration {
-
/**
* @var TOURDEFAULT
*/
@@ -60,7 +50,7 @@ public static function get_defaultable_keys() {
* @return mixed
*/
public static function get_default_value($key) {
- switch($key) {
+ switch ($key) {
case 'placement':
return 'bottom';
case 'orphan':
@@ -77,7 +67,7 @@ public static function get_default_value($key) {
* @return mixed
*/
public static function get_step_default_value($key) {
- switch($key) {
+ switch ($key) {
case 'placement':
case 'orphan':
case 'backdrop':
@@ -94,10 +84,10 @@ public static function get_step_default_value($key) {
*/
public static function get_placement_options($default = null) {
$values = [
- 'top' => get_string('above', 'tool_usertours'),
- 'bottom' => get_string('below', 'tool_usertours'),
- 'left' => get_string('left', 'tool_usertours'),
- 'right' => get_string('right', 'tool_usertours'),
+ 'top' => get_string('above', 'tool_usertours'),
+ 'bottom' => get_string('below', 'tool_usertours'),
+ 'left' => get_string('left', 'tool_usertours'),
+ 'right' => get_string('right', 'tool_usertours'),
];
if ($default === null) {
@@ -114,5 +104,4 @@ public static function get_placement_options($default = null) {
return $values;
}
-
}
diff --git a/admin/tool/usertours/classes/event/step_shown.php b/admin/tool/usertours/classes/event/step_shown.php
index 3537b61f7b7a..72ff3b4a6d52 100644
--- a/admin/tool/usertours/classes/event/step_shown.php
+++ b/admin/tool/usertours/classes/event/step_shown.php
@@ -14,18 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * The tool_usertours step_shown event.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\event;
-defined('MOODLE_INTERNAL') || die();
-
/**
* The tool_usertours step_shown event.
*
@@ -41,7 +31,6 @@
* }
*/
class step_shown extends \core\event\base {
-
/**
* Init method.
*/
diff --git a/admin/tool/usertours/classes/event/tour_ended.php b/admin/tool/usertours/classes/event/tour_ended.php
index 945d1e4eeb92..6853dd4a8605 100644
--- a/admin/tool/usertours/classes/event/tour_ended.php
+++ b/admin/tool/usertours/classes/event/tour_ended.php
@@ -14,18 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * The tool_usertours tour_ended event.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\event;
-defined('MOODLE_INTERNAL') || die();
-
/**
* The tool_usertours tour_ended event.
*
@@ -41,7 +31,6 @@
* }
*/
class tour_ended extends \core\event\base {
-
/**
* Init method.
*/
diff --git a/admin/tool/usertours/classes/event/tour_reset.php b/admin/tool/usertours/classes/event/tour_reset.php
index bd9e60d02c22..660f35f5db12 100644
--- a/admin/tool/usertours/classes/event/tour_reset.php
+++ b/admin/tool/usertours/classes/event/tour_reset.php
@@ -14,18 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * The tool_usertours tour_reset event.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\event;
-defined('MOODLE_INTERNAL') || die();
-
/**
* The tool_usertours tour_reset event.
*
@@ -41,7 +31,6 @@
* }
*/
class tour_reset extends \core\event\base {
-
/**
* Init method.
*/
diff --git a/admin/tool/usertours/classes/event/tour_started.php b/admin/tool/usertours/classes/event/tour_started.php
index 915cb586de37..d44114f051c2 100644
--- a/admin/tool/usertours/classes/event/tour_started.php
+++ b/admin/tool/usertours/classes/event/tour_started.php
@@ -14,18 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * The tool_usertours tour_started event.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\event;
-defined('MOODLE_INTERNAL') || die();
-
/**
* The tool_usertours tour_started event.
*
@@ -41,7 +31,6 @@
* }
*/
class tour_started extends \core\event\base {
-
/**
* Init method.
*/
diff --git a/admin/tool/usertours/classes/external/tour.php b/admin/tool/usertours/classes/external/tour.php
index 649becb5de8d..9ecad8e43ac2 100644
--- a/admin/tool/usertours/classes/external/tour.php
+++ b/admin/tool/usertours/classes/external/tour.php
@@ -43,10 +43,10 @@ public static function fetch_and_start_tour($tourid, $context, $pageurl) {
global $PAGE;
$params = self::validate_parameters(self::fetch_and_start_tour_parameters(), [
- 'tourid' => $tourid,
- 'context' => $context,
- 'pageurl' => $pageurl,
- ]);
+ 'tourid' => $tourid,
+ 'context' => $context,
+ 'pageurl' => $pageurl,
+ ]);
$context = \context_helper::instance_by_id($params['context']);
self::validate_context($context);
@@ -60,8 +60,8 @@ public static function fetch_and_start_tour($tourid, $context, $pageurl) {
\tool_usertours\event\tour_started::create([
'contextid' => $context->id,
- 'objectid' => $tour->get_id(),
- 'other' => [
+ 'objectid' => $tour->get_id(),
+ 'other' => [
'pageurl' => $params['pageurl'],
],
])->trigger();
@@ -78,9 +78,9 @@ public static function fetch_and_start_tour($tourid, $context, $pageurl) {
*/
public static function fetch_and_start_tour_parameters() {
return new external_function_parameters([
- 'tourid' => new external_value(PARAM_INT, 'Tour ID'),
- 'context' => new external_value(PARAM_INT, 'Context ID'),
- 'pageurl' => new external_value(PARAM_URL, 'Page URL'),
+ 'tourid' => new external_value(PARAM_INT, 'Tour ID'),
+ 'context' => new external_value(PARAM_INT, 'Context ID'),
+ 'pageurl' => new external_value(PARAM_URL, 'Page URL'),
]);
}
@@ -91,12 +91,12 @@ public static function fetch_and_start_tour_parameters() {
*/
public static function fetch_and_start_tour_returns() {
return new external_single_structure([
- 'tourconfig' => new external_single_structure([
- 'name' => new external_value(PARAM_RAW, 'Tour Name'),
- 'steps' => new external_multiple_structure(self::step_structure_returns()),
- 'endtourlabel' => new external_value(PARAM_RAW, 'Label of the end tour button'),
+ 'tourconfig' => new external_single_structure([
+ 'name' => new external_value(PARAM_RAW, 'Tour Name'),
+ 'steps' => new external_multiple_structure(self::step_structure_returns()),
+ 'endtourlabel' => new external_value(PARAM_RAW, 'Label of the end tour button'),
'displaystepnumbers' => new external_value(PARAM_BOOL, 'display step number'),
- ], 'Tour config', VALUE_OPTIONAL)
+ ], 'Tour config', VALUE_OPTIONAL),
]);
}
@@ -110,10 +110,10 @@ public static function fetch_and_start_tour_returns() {
*/
public static function reset_tour($tourid, $context, $pageurl) {
$params = self::validate_parameters(self::reset_tour_parameters(), [
- 'tourid' => $tourid,
- 'context' => $context,
- 'pageurl' => $pageurl,
- ]);
+ 'tourid' => $tourid,
+ 'context' => $context,
+ 'pageurl' => $pageurl,
+ ]);
$context = \context_helper::instance_by_id($params['context']);
self::validate_context($context);
@@ -130,9 +130,9 @@ public static function reset_tour($tourid, $context, $pageurl) {
\tool_usertours\event\tour_reset::create([
'contextid' => $context->id,
- 'objectid' => $params['tourid'],
- 'other' => [
- 'pageurl' => $params['pageurl'],
+ 'objectid' => $params['tourid'],
+ 'other' => [
+ 'pageurl' => $params['pageurl'],
],
])->trigger();
break;
@@ -149,9 +149,9 @@ public static function reset_tour($tourid, $context, $pageurl) {
*/
public static function reset_tour_parameters() {
return new external_function_parameters([
- 'tourid' => new external_value(PARAM_INT, 'Tour ID'),
- 'context' => new external_value(PARAM_INT, 'Context ID'),
- 'pageurl' => new external_value(PARAM_URL, 'Current page location'),
+ 'tourid' => new external_value(PARAM_INT, 'Tour ID'),
+ 'context' => new external_value(PARAM_INT, 'Context ID'),
+ 'pageurl' => new external_value(PARAM_URL, 'Current page location'),
]);
}
@@ -162,7 +162,7 @@ public static function reset_tour_parameters() {
*/
public static function reset_tour_returns() {
return new external_single_structure([
- 'startTour' => new external_value(PARAM_INT, 'Tour ID', VALUE_OPTIONAL),
+ 'startTour' => new external_value(PARAM_INT, 'Tour ID', VALUE_OPTIONAL),
]);
}
@@ -178,25 +178,26 @@ public static function reset_tour_returns() {
*/
public static function complete_tour($tourid, $context, $pageurl, $stepid, $stepindex) {
$params = self::validate_parameters(self::complete_tour_parameters(), [
- 'tourid' => $tourid,
- 'context' => $context,
- 'pageurl' => $pageurl,
- 'stepid' => $stepid,
- 'stepindex' => $stepindex,
- ]);
+ 'tourid' => $tourid,
+ 'context' => $context,
+ 'pageurl' => $pageurl,
+ 'stepid' => $stepid,
+ 'stepindex' => $stepindex,
+ ]);
$context = \context_helper::instance_by_id($params['context']);
self::validate_context($context);
$tour = tourinstance::instance($params['tourid']);
+
$tour->mark_user_completed();
\tool_usertours\event\tour_ended::create([
'contextid' => $context->id,
- 'objectid' => $params['tourid'],
- 'other' => [
- 'pageurl' => $params['pageurl'],
- 'stepid' => $params['stepid'],
+ 'objectid' => $params['tourid'],
+ 'other' => [
+ 'pageurl' => $params['pageurl'],
+ 'stepid' => $params['stepid'],
'stepindex' => $params['stepindex'],
],
])->trigger();
@@ -211,10 +212,10 @@ public static function complete_tour($tourid, $context, $pageurl, $stepid, $step
*/
public static function complete_tour_parameters() {
return new external_function_parameters([
- 'tourid' => new external_value(PARAM_INT, 'Tour ID'),
- 'context' => new external_value(PARAM_INT, 'Context ID'),
- 'pageurl' => new external_value(PARAM_LOCALURL, 'Page URL'),
- 'stepid' => new external_value(PARAM_INT, 'Step ID'),
+ 'tourid' => new external_value(PARAM_INT, 'Tour ID'),
+ 'context' => new external_value(PARAM_INT, 'Context ID'),
+ 'pageurl' => new external_value(PARAM_LOCALURL, 'Page URL'),
+ 'stepid' => new external_value(PARAM_INT, 'Step ID'),
'stepindex' => new external_value(PARAM_INT, 'Step Number'),
]);
}
@@ -240,12 +241,12 @@ public static function complete_tour_returns() {
*/
public static function step_shown($tourid, $context, $pageurl, $stepid, $stepindex) {
$params = self::validate_parameters(self::step_shown_parameters(), [
- 'tourid' => $tourid,
- 'context' => $context,
- 'pageurl' => $pageurl,
- 'stepid' => $stepid,
- 'stepindex' => $stepindex,
- ]);
+ 'tourid' => $tourid,
+ 'context' => $context,
+ 'pageurl' => $pageurl,
+ 'stepid' => $stepid,
+ 'stepindex' => $stepindex,
+ ]);
$context = \context_helper::instance_by_id($params['context']);
self::validate_context($context);
@@ -257,11 +258,11 @@ public static function step_shown($tourid, $context, $pageurl, $stepid, $stepind
\tool_usertours\event\step_shown::create([
'contextid' => $context->id,
- 'objectid' => $params['stepid'],
+ 'objectid' => $params['stepid'],
- 'other' => [
- 'pageurl' => $params['pageurl'],
- 'tourid' => $params['tourid'],
+ 'other' => [
+ 'pageurl' => $params['pageurl'],
+ 'tourid' => $params['tourid'],
'stepindex' => $params['stepindex'],
],
])->trigger();
@@ -276,10 +277,10 @@ public static function step_shown($tourid, $context, $pageurl, $stepid, $stepind
*/
public static function step_shown_parameters() {
return new external_function_parameters([
- 'tourid' => new external_value(PARAM_INT, 'Tour ID'),
- 'context' => new external_value(PARAM_INT, 'Context ID'),
- 'pageurl' => new external_value(PARAM_URL, 'Page URL'),
- 'stepid' => new external_value(PARAM_INT, 'Step ID'),
+ 'tourid' => new external_value(PARAM_INT, 'Tour ID'),
+ 'context' => new external_value(PARAM_INT, 'Context ID'),
+ 'pageurl' => new external_value(PARAM_URL, 'Page URL'),
+ 'stepid' => new external_value(PARAM_INT, 'Step ID'),
'stepindex' => new external_value(PARAM_INT, 'Step Number'),
]);
}
@@ -300,24 +301,47 @@ public static function step_shown_returns() {
*/
public static function step_structure_returns() {
return new external_single_structure([
- 'title' => new external_value(PARAM_RAW,
- 'Step Title'),
- 'content' => new external_value(PARAM_RAW,
- 'Step Content'),
- 'element' => new external_value(PARAM_TEXT,
- 'Step Target'),
- 'placement' => new external_value(PARAM_TEXT,
- 'Step Placement'),
- 'delay' => new external_value(PARAM_INT,
- 'Delay before showing the step (ms)', VALUE_OPTIONAL),
- 'backdrop' => new external_value(PARAM_BOOL,
- 'Whether a backdrop should be used', VALUE_OPTIONAL),
- 'reflex' => new external_value(PARAM_BOOL,
- 'Whether to move to the next step when the target element is clicked', VALUE_OPTIONAL),
- 'orphan' => new external_value(PARAM_BOOL,
- 'Whether to display the step even if it could not be found', VALUE_OPTIONAL),
- 'stepid' => new external_value(PARAM_INT,
- 'The actual ID of the step', VALUE_OPTIONAL),
+ 'title' => new external_value(
+ PARAM_RAW,
+ 'Step Title'
+ ),
+ 'content' => new external_value(
+ PARAM_RAW,
+ 'Step Content'
+ ),
+ 'element' => new external_value(
+ PARAM_TEXT,
+ 'Step Target'
+ ),
+ 'placement' => new external_value(
+ PARAM_TEXT,
+ 'Step Placement'
+ ),
+ 'delay' => new external_value(
+ PARAM_INT,
+ 'Delay before showing the step (ms)',
+ VALUE_OPTIONAL
+ ),
+ 'backdrop' => new external_value(
+ PARAM_BOOL,
+ 'Whether a backdrop should be used',
+ VALUE_OPTIONAL
+ ),
+ 'reflex' => new external_value(
+ PARAM_BOOL,
+ 'Whether to move to the next step when the target element is clicked',
+ VALUE_OPTIONAL
+ ),
+ 'orphan' => new external_value(
+ PARAM_BOOL,
+ 'Whether to display the step even if it could not be found',
+ VALUE_OPTIONAL
+ ),
+ 'stepid' => new external_value(
+ PARAM_INT,
+ 'The actual ID of the step',
+ VALUE_OPTIONAL
+ ),
]);
}
}
diff --git a/admin/tool/usertours/classes/helper.php b/admin/tool/usertours/classes/helper.php
index 6c2befa697a9..8327dbd0ed44 100644
--- a/admin/tool/usertours/classes/helper.php
+++ b/admin/tool/usertours/classes/helper.php
@@ -14,29 +14,18 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Tour helper.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours;
use core\output\inplace_editable;
-use tool_usertours\local\clientside_filter\clientside_filter;
-
-defined('MOODLE_INTERNAL') || die();
/**
* Tour helper.
*
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package tool_usertours
*/
class helper {
-
/**
* @var MOVE_UP
*/
@@ -158,10 +147,10 @@ public static function get_view_tour_link($tourid) {
*/
public static function get_reset_tour_for_all_link($tourid) {
return new \moodle_url('/admin/tool/usertours/configure.php', [
- 'id' => $tourid,
- 'action' => manager::ACTION_RESETFORALL,
- 'sesskey' => sesskey(),
- ]);
+ 'id' => $tourid,
+ 'action' => manager::ACTION_RESETFORALL,
+ 'sesskey' => sesskey(),
+ ]);
}
/**
@@ -204,9 +193,9 @@ public static function get_import_tour_link() {
*/
public static function get_export_tour_link($tourid) {
$link = new \moodle_url('/admin/tool/usertours/configure.php', [
- 'action' => manager::ACTION_EXPORTTOUR,
- 'id' => $tourid,
- ]);
+ 'action' => manager::ACTION_EXPORTTOUR,
+ 'id' => $tourid,
+ ]);
return $link;
}
@@ -219,8 +208,8 @@ public static function get_export_tour_link($tourid) {
*/
public static function get_duplicate_tour_link($tourid) {
$link = new \moodle_url('/admin/tool/usertours/configure.php', [
- 'action' => manager::ACTION_DUPLICATETOUR,
- 'id' => $tourid,
+ 'action' => manager::ACTION_DUPLICATETOUR,
+ 'id' => $tourid,
]);
return $link;
@@ -234,10 +223,10 @@ public static function get_duplicate_tour_link($tourid) {
*/
public static function get_delete_tour_link($tourid) {
return new \moodle_url('/admin/tool/usertours/configure.php', [
- 'id' => $tourid,
- 'action' => manager::ACTION_DELETETOUR,
- 'sesskey' => sesskey(),
- ]);
+ 'id' => $tourid,
+ 'action' => manager::ACTION_DELETETOUR,
+ 'sesskey' => sesskey(),
+ ]);
}
/**
@@ -262,18 +251,17 @@ public static function get_list_tour_link() {
* @param array $options Display options.
* @return string
*/
- public static function format_icon_link($url, $icon, $alt, $iconcomponent = 'moodle', $options = array()) {
+ public static function format_icon_link($url, $icon, $alt, $iconcomponent = 'moodle', $options = []) {
global $OUTPUT;
return $OUTPUT->action_icon(
- $url,
- new \pix_icon($icon, $alt, $iconcomponent, [
- 'title' => $alt,
- ]),
- null,
- $options
- );
-
+ $url,
+ new \pix_icon($icon, $alt, $iconcomponent, [
+ 'title' => $alt,
+ ]),
+ null,
+ $options
+ );
}
/**
@@ -282,7 +270,7 @@ public static function format_icon_link($url, $icon, $alt, $iconcomponent = 'moo
* @param array $options Display options.
* @return string
*/
- public static function get_filler_icon($options = array()) {
+ public static function get_filler_icon($options = []) {
global $OUTPUT;
return \html_writer::span(
@@ -299,10 +287,10 @@ public static function get_filler_icon($options = array()) {
*/
public static function get_delete_step_link($stepid) {
return new \moodle_url('/admin/tool/usertours/configure.php', [
- 'action' => manager::ACTION_DELETESTEP,
- 'id' => $stepid,
- 'sesskey' => sesskey(),
- ]);
+ 'action' => manager::ACTION_DELETESTEP,
+ 'id' => $stepid,
+ 'sesskey' => sesskey(),
+ ]);
}
/**
@@ -314,16 +302,16 @@ public static function get_delete_step_link($stepid) {
public static function render_tourname_inplace_editable(tour $tour): inplace_editable {
$name = format_text(static::get_string_from_input($tour->get_name()), FORMAT_HTML);
return new inplace_editable(
- 'tool_usertours',
- 'tourname',
- $tour->get_id(),
- true,
- \html_writer::link(
- $tour->get_view_link(),
- $name
- ),
- $tour->get_name()
- );
+ 'tool_usertours',
+ 'tourname',
+ $tour->get_id(),
+ true,
+ \html_writer::link(
+ $tour->get_view_link(),
+ $name
+ ),
+ $tour->get_name()
+ );
}
/**
@@ -335,13 +323,13 @@ public static function render_tourname_inplace_editable(tour $tour): inplace_edi
public static function render_tourdescription_inplace_editable(tour $tour): inplace_editable {
$description = format_text(static::get_string_from_input($tour->get_description()), FORMAT_HTML);
return new inplace_editable(
- 'tool_usertours',
- 'tourdescription',
- $tour->get_id(),
- true,
- $description,
- $tour->get_description()
- );
+ 'tool_usertours',
+ 'tourdescription',
+ $tour->get_id(),
+ true,
+ $description,
+ $tour->get_description()
+ );
}
/**
@@ -364,15 +352,15 @@ public static function render_tourenabled_inplace_editable(tour $tour): inplace_
}
$editable = new inplace_editable(
- 'tool_usertours',
- 'tourenabled',
- $tour->get_id(),
- true,
- $OUTPUT->pix_icon($icon, $alt, 'moodle', [
- 'title' => $alt,
- ]),
- $value
- );
+ 'tool_usertours',
+ 'tourenabled',
+ $tour->get_id(),
+ true,
+ $OUTPUT->pix_icon($icon, $alt, 'moodle', [
+ 'title' => $alt,
+ ]),
+ $value
+ );
$editable->set_type_toggle();
return $editable;
@@ -388,16 +376,16 @@ public static function render_stepname_inplace_editable(step $step): inplace_edi
$title = format_text(static::get_string_from_input($step->get_title()), FORMAT_HTML);
return new inplace_editable(
- 'tool_usertours',
- 'stepname',
- $step->get_id(),
- true,
- \html_writer::link(
- $step->get_edit_link(),
- $title
- ),
- $step->get_title()
- );
+ 'tool_usertours',
+ 'stepname',
+ $step->get_id(),
+ true,
+ \html_writer::link(
+ $step->get_edit_link(),
+ $title
+ ),
+ $step->get_title()
+ );
}
/**
@@ -408,7 +396,7 @@ public static function render_stepname_inplace_editable(step $step): inplace_edi
public static function get_tours() {
global $DB;
- $tours = $DB->get_records('tool_usertours_tours', array(), 'sortorder ASC');
+ $tours = $DB->get_records('tool_usertours_tours', [], 'sortorder ASC');
$return = [];
foreach ($tours as $tour) {
$return[$tour->id] = tour::load_from_record($tour);
@@ -435,7 +423,7 @@ public static function get_tour($tourid) {
public static function get_tour_from_sortorder($sortorder) {
global $DB;
- $tour = $DB->get_record('tool_usertours_tours', array('sortorder' => $sortorder));
+ $tour = $DB->get_record('tool_usertours_tours', ['sortorder' => $sortorder]);
return tour::load_from_record($tour);
}
@@ -460,7 +448,7 @@ public static function reset_tour_sortorder() {
$index = 0;
foreach ($tours as $tour) {
if ($tour->sortorder != $index) {
- $DB->set_field('tool_usertours_tours', 'sortorder', $index, array('id' => $tour->id));
+ $DB->set_field('tool_usertours_tours', 'sortorder', $index, ['id' => $tour->id]);
}
$index++;
}
@@ -508,7 +496,7 @@ public static function get_step($stepid) {
public static function get_step_from_sortorder($tourid, $sortorder) {
global $DB;
- $step = $DB->get_record('tool_usertours_steps', array('tourid' => $tourid, 'sortorder' => $sortorder));
+ $step = $DB->get_record('tool_usertours_steps', ['tourid' => $tourid, 'sortorder' => $sortorder]);
return step::load_from_record($step);
}
@@ -538,11 +526,11 @@ public static function bootstrap() {
if ($tours) {
$filters = static::get_all_clientside_filters();
- $tourdetails = array_map(function($tour) use ($filters) {
+ $tourdetails = array_map(function ($tour) use ($filters) {
return [
- 'tourId' => $tour->get_id(),
- 'startTour' => $tour->should_show_for_user(),
- 'filtervalues' => $tour->get_client_filter_values($filters),
+ 'tourId' => $tour->get_id(),
+ 'startTour' => $tour->should_show_for_user(),
+ 'filtervalues' => $tour->get_client_filter_values($filters),
];
}, $tours);
@@ -552,8 +540,8 @@ public static function bootstrap() {
}
$PAGE->requires->js_call_amd('tool_usertours/usertours', 'init', [
- $tourdetails,
- $filternames,
+ $tourdetails,
+ $filternames,
]);
}
}
@@ -567,7 +555,7 @@ public static function get_all_filters() {
$filters = \core_component::get_component_classes_in_namespace('tool_usertours', 'local\filter');
$filters = array_keys($filters);
- $filters = array_filter($filters, function($filterclass) {
+ $filters = array_filter($filters, function ($filterclass) {
$rc = new \ReflectionClass($filterclass);
return $rc->isInstantiable();
});
@@ -586,7 +574,7 @@ public static function get_all_clientside_filters() {
$filters = \core_component::get_component_classes_in_namespace('tool_usertours', 'local\clientside_filter');
$filters = array_keys($filters);
- $filters = array_filter($filters, function($filterclass) {
+ $filters = array_filter($filters, function ($filterclass) {
$rc = new \ReflectionClass($filterclass);
return $rc->isInstantiable();
});
diff --git a/admin/tool/usertours/classes/local/clientside_filter/clientside_filter.php b/admin/tool/usertours/classes/local/clientside_filter/clientside_filter.php
index 6fa403ac57a0..ed394f29be63 100644
--- a/admin/tool/usertours/classes/local/clientside_filter/clientside_filter.php
+++ b/admin/tool/usertours/classes/local/clientside_filter/clientside_filter.php
@@ -14,18 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Clientside filter base.
- *
- * @package tool_usertours
- * @copyright 2020 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\local\clientside_filter;
-defined('MOODLE_INTERNAL') || die();
-
use stdClass;
use tool_usertours\local\filter\base;
use tool_usertours\tour;
@@ -33,6 +23,7 @@
/**
* Clientside filter base.
*
+ * @package tool_usertours
* @copyright 2020 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
@@ -46,10 +37,10 @@ abstract class clientside_filter extends base {
public static function get_client_side_values(tour $tour): stdClass {
$data = (object) [];
- if (is_a(static::class, clientside_filter::class, true)) {
+ if (is_a(static::class, self::class, true)) {
$data->filterdata = $tour->get_filter_values(static::get_filter_name());
}
return $data;
}
-}
\ No newline at end of file
+}
diff --git a/admin/tool/usertours/classes/local/clientside_filter/cssselector.php b/admin/tool/usertours/classes/local/clientside_filter/cssselector.php
index e6d6c2d778eb..ef30c5895928 100644
--- a/admin/tool/usertours/classes/local/clientside_filter/cssselector.php
+++ b/admin/tool/usertours/classes/local/clientside_filter/cssselector.php
@@ -14,13 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Selector filter.
- *
- * @package tool_usertours
- * @copyright 2020 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
namespace tool_usertours\local\clientside_filter;
use stdClass;
@@ -29,6 +22,7 @@
/**
* Course filter.
*
+ * @package tool_usertours
* @copyright 2020 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
@@ -107,7 +101,7 @@ public static function get_client_side_values(tour $tour): stdClass {
// Filter values might not exist for tours that were created before this filter existed.
if (!$filtervalues) {
- return new stdClass;
+ return new stdClass();
}
return (object) $filtervalues;
diff --git a/admin/tool/usertours/classes/local/filter/accessdate.php b/admin/tool/usertours/classes/local/filter/accessdate.php
index 26fecd4b8c7e..7ca30008d65e 100644
--- a/admin/tool/usertours/classes/local/filter/accessdate.php
+++ b/admin/tool/usertours/classes/local/filter/accessdate.php
@@ -13,29 +13,19 @@
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-
-/**
- * Access Date filter.
- *
- * @package tool_usertours
- * @copyright 2019 Tom Dickman
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
namespace tool_usertours\local\filter;
-defined('MOODLE_INTERNAL') || die();
-
use context;
use tool_usertours\tour;
/**
* Access date filter. Used to determine if USER should see a tour based on a particular access date.
*
+ * @package tool_usertours
* @copyright 2019 Tom Dickman
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class accessdate extends base {
-
/**
* Access date filtering constant for setting base date as account creation date.
*/
@@ -74,12 +64,11 @@ public static function get_filter_name() {
*/
public static function get_filter_options() {
- return array(
+ return [
self::FILTER_ACCOUNT_CREATION => get_string('filter_date_account_creation', 'tool_usertours'),
self::FILTER_FIRST_LOGIN => get_string('filter_date_first_login', 'tool_usertours'),
self::FILTER_LAST_LOGIN => get_string('filter_date_last_login', 'tool_usertours'),
- );
-
+ ];
}
/**
@@ -96,8 +85,14 @@ public static function add_filter_to_form(\MoodleQuickForm &$mform) {
$range = "{$key}_range";
$enabled = "{$key}_enabled";
- $mform->addElement('advcheckbox', $enabled, get_string($key, 'tool_usertours'),
- get_string('filter_accessdate_enabled', 'tool_usertours'), null, array(0, 1));
+ $mform->addElement(
+ 'advcheckbox',
+ $enabled,
+ get_string($key, 'tool_usertours'),
+ get_string('filter_accessdate_enabled', 'tool_usertours'),
+ null,
+ [0, 1]
+ );
$mform->addHelpButton($enabled, $enabled, 'tool_usertours');
$mform->addElement('select', $key, ' ', self::get_filter_options());
@@ -110,7 +105,6 @@ public static function add_filter_to_form(\MoodleQuickForm &$mform) {
]);
$mform->setDefault($range, 90 * DAYSECS);
$mform->hideIf($range, $enabled, 'notchecked');
-
}
/**
@@ -224,4 +218,4 @@ public static function filter_matches(tour $tour, context $context) {
}
return $result;
}
-}
\ No newline at end of file
+}
diff --git a/admin/tool/usertours/classes/local/filter/base.php b/admin/tool/usertours/classes/local/filter/base.php
index ff1de4442a97..fc73c58dedda 100644
--- a/admin/tool/usertours/classes/local/filter/base.php
+++ b/admin/tool/usertours/classes/local/filter/base.php
@@ -14,24 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Filter base.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\local\filter;
-defined('MOODLE_INTERNAL') || die();
-
use tool_usertours\tour;
use context;
/**
* Filter base.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
diff --git a/admin/tool/usertours/classes/local/filter/category.php b/admin/tool/usertours/classes/local/filter/category.php
index 0b1f119853d9..fd5566d998c0 100644
--- a/admin/tool/usertours/classes/local/filter/category.php
+++ b/admin/tool/usertours/classes/local/filter/category.php
@@ -14,24 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Category filter.
- *
- * @package tool_usertours
- * @copyright 2017 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\local\filter;
-defined('MOODLE_INTERNAL') || die();
-
use tool_usertours\tour;
use context;
/**
* Category filter.
*
+ * @package tool_usertours
* @copyright 2017 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
diff --git a/admin/tool/usertours/classes/local/filter/course.php b/admin/tool/usertours/classes/local/filter/course.php
index 32fb21ddb5da..a440bc0598c7 100644
--- a/admin/tool/usertours/classes/local/filter/course.php
+++ b/admin/tool/usertours/classes/local/filter/course.php
@@ -14,24 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Course filter.
- *
- * @package tool_usertours
- * @copyright 2017 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\local\filter;
-defined('MOODLE_INTERNAL') || die();
-
use tool_usertours\tour;
use context;
/**
* Course filter.
*
+ * @package tool_usertours
* @copyright 2017 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
diff --git a/admin/tool/usertours/classes/local/filter/courseformat.php b/admin/tool/usertours/classes/local/filter/courseformat.php
index 95e2b7c86132..de2ca1435237 100644
--- a/admin/tool/usertours/classes/local/filter/courseformat.php
+++ b/admin/tool/usertours/classes/local/filter/courseformat.php
@@ -14,24 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Course format filter.
- *
- * @package tool_usertours
- * @copyright 2017 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\local\filter;
-defined('MOODLE_INTERNAL') || die();
-
use tool_usertours\tour;
use context;
/**
* Course format filter.
*
+ * @package tool_usertours
* @copyright 2017 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
diff --git a/admin/tool/usertours/classes/local/filter/role.php b/admin/tool/usertours/classes/local/filter/role.php
index a64ee83585c2..e3c67ebe5a23 100644
--- a/admin/tool/usertours/classes/local/filter/role.php
+++ b/admin/tool/usertours/classes/local/filter/role.php
@@ -14,24 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Theme filter.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\local\filter;
-defined('MOODLE_INTERNAL') || die();
-
use tool_usertours\tour;
use context;
/**
* Theme filter.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
@@ -106,7 +97,7 @@ public static function filter_matches(tour $tour, context $context) {
}
// Use a request cache to save on DB queries.
- // We may be checking multiple tours and they'll all be for the same userid, and contextid
+ // We may be checking multiple tours and they'll all be for the same userid, and contextid.
$cache = \cache::make_from_params(\cache_store::MODE_REQUEST, 'tool_usertours', 'filter_role');
// Get all of the roles used in this context, including special roles such as user, and frontpageuser.
diff --git a/admin/tool/usertours/classes/local/filter/theme.php b/admin/tool/usertours/classes/local/filter/theme.php
index 786684c9c13f..e041d172cc37 100644
--- a/admin/tool/usertours/classes/local/filter/theme.php
+++ b/admin/tool/usertours/classes/local/filter/theme.php
@@ -14,24 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Theme filter.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\local\filter;
-defined('MOODLE_INTERNAL') || die();
-
use tool_usertours\tour;
use context;
/**
* Theme filter.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
diff --git a/admin/tool/usertours/classes/local/forms/editstep.php b/admin/tool/usertours/classes/local/forms/editstep.php
index b9418e75e225..8c586101f33a 100644
--- a/admin/tool/usertours/classes/local/forms/editstep.php
+++ b/admin/tool/usertours/classes/local/forms/editstep.php
@@ -98,7 +98,7 @@ public function definition() {
// Content type.
$typeoptions = [
static::CONTENTTYPE_LANGSTRING => get_string('content_type_langstring', 'tool_usertours'),
- static::CONTENTTYPE_MANUAL => get_string('content_type_manual', 'tool_usertours')
+ static::CONTENTTYPE_MANUAL => get_string('content_type_manual', 'tool_usertours'),
];
$mform->addElement('select', 'contenttype', get_string('content_type', 'tool_usertours'), $typeoptions);
$mform->addHelpButton('contenttype', 'content_type', 'tool_usertours');
@@ -114,7 +114,7 @@ public function definition() {
'maxbytes' => $CFG->maxbytes,
'maxfiles' => EDITOR_UNLIMITED_FILES,
'changeformat' => 1,
- 'trusttext' => true
+ 'trusttext' => true,
];
$objs = $mform->createElement('editor', 'content', get_string('content', 'tool_usertours'), null, $editoroptions);
// TODO: MDL-68540 We need to add the editor to a group element because editor element will not work with hideIf.
diff --git a/admin/tool/usertours/classes/local/forms/edittour.php b/admin/tool/usertours/classes/local/forms/edittour.php
index 80409b1aa783..cf6f50402cd9 100644
--- a/admin/tool/usertours/classes/local/forms/edittour.php
+++ b/admin/tool/usertours/classes/local/forms/edittour.php
@@ -28,7 +28,8 @@
require_once($CFG->libdir . '/formslib.php');
-use \tool_usertours\helper;
+use tool_usertours\helper;
+use tool_usertours\tour;
/**
* Form for editing tours.
@@ -88,6 +89,17 @@ public function definition() {
$mform->addElement('checkbox', 'displaystepnumbers', get_string('displaystepnumbers', 'tool_usertours'));
$mform->addHelpButton('displaystepnumbers', 'displaystepnumbers', 'tool_usertours');
+ $mform->addElement(
+ 'select',
+ 'showtourwhen',
+ get_string('showtourwhen', 'tool_usertours'),
+ [
+ tour::SHOW_TOUR_UNTIL_COMPLETE => get_string('showtouruntilcomplete', 'tool_usertours'),
+ tour::SHOW_TOUR_ON_EACH_PAGE_VISIT => get_string('showtoureachtime', 'tool_usertours'),
+ ]
+ );
+ $mform->setDefault('showtourwhen', tour::SHOW_TOUR_UNTIL_COMPLETE);
+
// Configuration.
$this->tour->add_config_to_form($mform);
diff --git a/admin/tool/usertours/classes/local/table/step_list.php b/admin/tool/usertours/classes/local/table/step_list.php
index c774c6e63f6f..87937d7b0e11 100644
--- a/admin/tool/usertours/classes/local/table/step_list.php
+++ b/admin/tool/usertours/classes/local/table/step_list.php
@@ -39,7 +39,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class step_list extends \flexible_table {
-
/**
* @var int $tourid The id of the tour.
*/
@@ -54,25 +53,25 @@ public function __construct($tourid) {
parent::__construct('steps');
$this->tourid = $tourid;
- $baseurl = new \moodle_url('/tool/usertours/configure.php', array(
+ $baseurl = new \moodle_url('/tool/usertours/configure.php', [
'id' => $tourid,
- ));
+ ]);
$this->define_baseurl($baseurl);
// Column definition.
- $this->define_columns(array(
+ $this->define_columns([
'title',
'content',
'target',
'actions',
- ));
+ ]);
- $this->define_headers(array(
- get_string('title', 'tool_usertours'),
+ $this->define_headers([
+ get_string('title', 'tool_usertours'),
get_string('content', 'tool_usertours'),
- get_string('target', 'tool_usertours'),
+ get_string('target', 'tool_usertours'),
get_string('actions', 'tool_usertours'),
- ));
+ ]);
$this->set_attribute('class', 'admintable generaltable steptable');
$this->setup();
@@ -98,8 +97,14 @@ protected function col_title(step $step) {
protected function col_content(step $step) {
$content = $step->get_content();
$systemcontext = \context_system::instance();
- $content = file_rewrite_pluginfile_urls($content, 'pluginfile.php', $systemcontext->id,
- 'tool_usertours', 'stepcontent', $step->get_id());
+ $content = file_rewrite_pluginfile_urls(
+ $content,
+ 'pluginfile.php',
+ $systemcontext->id,
+ 'tool_usertours',
+ 'stepcontent',
+ $step->get_id()
+ );
$content = helper::get_string_from_input($content);
$content = step::get_step_image_from_input($content);
@@ -135,8 +140,11 @@ protected function col_actions(step $step) {
if ($step->is_last_step()) {
$actions[] = helper::get_filler_icon();
} else {
- $actions[] = helper::format_icon_link($step->get_movedown_link(), 't/down',
- get_string('movestepdown', 'tool_usertours'));
+ $actions[] = helper::format_icon_link(
+ $step->get_movedown_link(),
+ 't/down',
+ get_string('movestepdown', 'tool_usertours')
+ );
}
$actions[] = helper::format_icon_link($step->get_edit_link(), 't/edit', get_string('edit'));
diff --git a/admin/tool/usertours/classes/local/table/tour_list.php b/admin/tool/usertours/classes/local/table/tour_list.php
index 0ea20a13dbc4..dd5298cd8d1c 100644
--- a/admin/tool/usertours/classes/local/table/tour_list.php
+++ b/admin/tool/usertours/classes/local/table/tour_list.php
@@ -38,7 +38,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tour_list extends \flexible_table {
-
/** @var int The count of all tours. */
protected int $tourcount = 0;
@@ -52,21 +51,21 @@ public function __construct() {
$this->define_baseurl($baseurl);
// Column definition.
- $this->define_columns(array(
+ $this->define_columns([
'name',
'description',
'appliesto',
'enabled',
'actions',
- ));
+ ]);
- $this->define_headers(array(
+ $this->define_headers([
get_string('name', 'tool_usertours'),
get_string('description', 'tool_usertours'),
get_string('appliesto', 'tool_usertours'),
get_string('enabled', 'tool_usertours'),
get_string('actions', 'tool_usertours'),
- ));
+ ]);
$this->set_attribute('class', 'admintable generaltable');
$this->setup();
@@ -129,22 +128,32 @@ protected function col_actions(tour $tour) {
if ($tour->is_first_tour()) {
$actions[] = helper::get_filler_icon();
} else {
- $actions[] = helper::format_icon_link($tour->get_moveup_link(), 't/up',
- get_string('movetourup', 'tool_usertours'));
+ $actions[] = helper::format_icon_link(
+ $tour->get_moveup_link(),
+ 't/up',
+ get_string('movetourup', 'tool_usertours')
+ );
}
if ($tour->is_last_tour($this->tourcount)) {
$actions[] = helper::get_filler_icon();
} else {
- $actions[] = helper::format_icon_link($tour->get_movedown_link(), 't/down',
- get_string('movetourdown', 'tool_usertours'));
+ $actions[] = helper::format_icon_link(
+ $tour->get_movedown_link(),
+ 't/down',
+ get_string('movetourdown', 'tool_usertours')
+ );
}
$actions[] = helper::format_icon_link($tour->get_view_link(), 't/viewdetails', get_string('view'));
$actions[] = helper::format_icon_link($tour->get_edit_link(), 't/edit', get_string('edit'));
$actions[] = helper::format_icon_link($tour->get_duplicate_link(), 't/copy', get_string('duplicate'));
- $actions[] = helper::format_icon_link($tour->get_export_link(), 't/export',
- get_string('exporttour', 'tool_usertours'), 'tool_usertours');
+ $actions[] = helper::format_icon_link(
+ $tour->get_export_link(),
+ 't/export',
+ get_string('exporttour', 'tool_usertours'),
+ 'tool_usertours'
+ );
$actions[] = helper::format_icon_link($tour->get_delete_link(), 't/delete', get_string('delete'), null, [
'data-action' => 'delete',
'data-id' => $tour->get_id(),
diff --git a/admin/tool/usertours/classes/local/target/base.php b/admin/tool/usertours/classes/local/target/base.php
index 663e5bf03b68..e3b829bfb049 100644
--- a/admin/tool/usertours/classes/local/target/base.php
+++ b/admin/tool/usertours/classes/local/target/base.php
@@ -14,23 +14,14 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Target base.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\local\target;
-defined('MOODLE_INTERNAL') || die();
-
use tool_usertours\step;
/**
* Target base.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
diff --git a/admin/tool/usertours/classes/local/target/block.php b/admin/tool/usertours/classes/local/target/block.php
index 095e9018c4c9..06071c7d5cb9 100644
--- a/admin/tool/usertours/classes/local/target/block.php
+++ b/admin/tool/usertours/classes/local/target/block.php
@@ -14,28 +14,16 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Block target.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\local\target;
-defined('MOODLE_INTERNAL') || die();
-
-use tool_usertours\step;
-
/**
* Block target.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class block extends base {
-
/**
* Convert the target value to a valid CSS selector for use in the
* output configuration.
@@ -101,8 +89,12 @@ public static function add_config_to_form(\MoodleQuickForm $mform) {
* @param MoodleQuickForm $mform The form to add configuration to.
*/
public static function add_disabled_constraints_to_form(\MoodleQuickForm $mform) {
- $mform->hideIf('targetvalue_block', 'targettype', 'noteq',
- \tool_usertours\target::get_target_constant_for_class(self::class));
+ $mform->hideIf(
+ 'targetvalue_block',
+ 'targettype',
+ 'noteq',
+ \tool_usertours\target::get_target_constant_for_class(self::class)
+ );
}
/**
diff --git a/admin/tool/usertours/classes/local/target/selector.php b/admin/tool/usertours/classes/local/target/selector.php
index b0cc92682f03..16057c0e04c7 100644
--- a/admin/tool/usertours/classes/local/target/selector.php
+++ b/admin/tool/usertours/classes/local/target/selector.php
@@ -14,28 +14,16 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Selector target.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\local\target;
-defined('MOODLE_INTERNAL') || die();
-
-use tool_usertours\step;
-
/**
* Selector target.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class selector extends base {
-
/**
* Convert the target value to a valid CSS selector for use in the
* output configuration.
@@ -91,8 +79,12 @@ public static function add_config_to_form(\MoodleQuickForm $mform) {
* @param MoodleQuickForm $mform The form to add configuration to.
*/
public static function add_disabled_constraints_to_form(\MoodleQuickForm $mform) {
- $mform->hideIf('targetvalue_selector', 'targettype', 'noteq',
- \tool_usertours\target::get_target_constant_for_class(self::class));
+ $mform->hideIf(
+ 'targetvalue_selector',
+ 'targettype',
+ 'noteq',
+ \tool_usertours\target::get_target_constant_for_class(self::class)
+ );
}
/**
diff --git a/admin/tool/usertours/classes/local/target/unattached.php b/admin/tool/usertours/classes/local/target/unattached.php
index 316fdea4b853..0c5303687100 100644
--- a/admin/tool/usertours/classes/local/target/unattached.php
+++ b/admin/tool/usertours/classes/local/target/unattached.php
@@ -14,23 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * A step designed to be orphaned.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\local\target;
-defined('MOODLE_INTERNAL') || die();
-
-use tool_usertours\step;
-
/**
* A step designed to be orphaned.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
diff --git a/admin/tool/usertours/classes/manager.php b/admin/tool/usertours/classes/manager.php
index ab207e6ce5c8..cd9c22ebfeed 100644
--- a/admin/tool/usertours/classes/manager.php
+++ b/admin/tool/usertours/classes/manager.php
@@ -14,18 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Tour manager.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours;
-defined('MOODLE_INTERNAL') || die();
-
use tool_usertours\local\forms;
use tool_usertours\local\table;
use core\notification;
@@ -33,11 +23,11 @@
/**
* Tour manager.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class manager {
-
/**
* @var ACTION_LISTTOURS The action to get the list of tours.
*/
@@ -163,7 +153,7 @@ public function execute($action) {
$PAGE->set_primary_active_tab('siteadminnode');
// Add the main content.
- switch($action) {
+ switch ($action) {
case self::ACTION_NEWTOUR:
case self::ACTION_EDITTOUR:
$this->edit_tour(optional_param('id', null, PARAM_INT));
@@ -356,7 +346,6 @@ protected function edit_tour($id = null) {
if ($id) {
$tour = tour::instance($id);
$PAGE->navbar->add(helper::get_string_from_input($tour->get_name()), $tour->get_edit_link());
-
} else {
$tour = new tour();
$PAGE->navbar->add(get_string('newtour', 'tool_usertours'), $tour->get_edit_link());
@@ -374,6 +363,7 @@ protected function edit_tour($id = null) {
$tour->set_enabled(!empty($data->enabled));
$tour->set_endtourlabel($data->endtourlabel);
$tour->set_display_step_numbers(!empty($data->displaystepnumbers));
+ $tour->set_showtourwhen($data->showtourwhen);
foreach (configuration::get_defaultable_keys() as $key) {
$tour->set_config($key, $data->$key);
@@ -403,6 +393,7 @@ protected function edit_tour($id = null) {
foreach (helper::get_all_filters() as $filterclass) {
$filterclass::prepare_filter_values_for_form($tour, $data);
}
+
$form->set_data($data);
}
@@ -568,7 +559,7 @@ protected function show_hide_tour($tourid, $visibility) {
require_sesskey();
- $tour = $DB->get_record('tool_usertours_tours', array('id' => $tourid));
+ $tour = $DB->get_record('tool_usertours_tours', ['id' => $tourid]);
$tour->enabled = $visibility;
$DB->update_record('tool_usertours_tours', $tour);
@@ -784,9 +775,10 @@ protected function move_tour($id) {
*/
protected static function _move_tour(tour $tour, $direction) {
// We can't move the first tour higher, nor the last tour any lower.
- if (($tour->is_first_tour() && $direction == helper::MOVE_UP) ||
- ($tour->is_last_tour() && $direction == helper::MOVE_DOWN)) {
-
+ if (
+ ($tour->is_first_tour() && $direction == helper::MOVE_UP) ||
+ ($tour->is_last_tour() && $direction == helper::MOVE_DOWN)
+ ) {
return;
}
diff --git a/admin/tool/usertours/classes/output/renderer.php b/admin/tool/usertours/classes/output/renderer.php
index 27c1ae37901c..6c9ed28f8ba4 100644
--- a/admin/tool/usertours/classes/output/renderer.php
+++ b/admin/tool/usertours/classes/output/renderer.php
@@ -14,21 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Renderer.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\output;
-defined('MOODLE_INTERNAL') || die();
-
/**
* Renderer.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
diff --git a/admin/tool/usertours/classes/output/step.php b/admin/tool/usertours/classes/output/step.php
index a3f5f81a0240..a85a0a5664ab 100644
--- a/admin/tool/usertours/classes/output/step.php
+++ b/admin/tool/usertours/classes/output/step.php
@@ -38,7 +38,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class step implements \renderable {
-
/**
* @var The step instance.
*/
@@ -65,8 +64,14 @@ public function export_for_template(\renderer_base $output) {
$content = $step->get_content();
$systemcontext = \context_system::instance();
- $content = file_rewrite_pluginfile_urls($content, 'pluginfile.php', $systemcontext->id,
- 'tool_usertours', 'stepcontent', $step->get_id());
+ $content = file_rewrite_pluginfile_urls(
+ $content,
+ 'pluginfile.php',
+ $systemcontext->id,
+ 'tool_usertours',
+ 'stepcontent',
+ $step->get_id()
+ );
$content = helper::get_string_from_input($content);
$content = $step::get_step_image_from_input($content);
@@ -74,17 +79,17 @@ public function export_for_template(\renderer_base $output) {
$result = (object) [
'stepid' => $step->get_id(),
'title' => \core_external\util::format_text(
- helper::get_string_from_input($step->get_title()),
- FORMAT_HTML,
- $PAGE->context->id,
- 'tool_usertours'
- )[0],
+ helper::get_string_from_input($step->get_title()),
+ FORMAT_HTML,
+ $PAGE->context->id,
+ 'tool_usertours'
+ )[0],
'content' => \core_external\util::format_text(
- $content,
- $step->get_contentformat(),
- $PAGE->context->id,
- 'tool_usertours'
- )[0],
+ $content,
+ $step->get_contentformat(),
+ $PAGE->context->id,
+ 'tool_usertours'
+ )[0],
'element' => $step->get_target()->convert_to_css(),
];
diff --git a/admin/tool/usertours/classes/output/tour.php b/admin/tool/usertours/classes/output/tour.php
index 6e933fb7cc43..d232e44d1636 100644
--- a/admin/tool/usertours/classes/output/tour.php
+++ b/admin/tool/usertours/classes/output/tour.php
@@ -14,28 +14,18 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Tour renderable.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\output;
-defined('MOODLE_INTERNAL') || die();
-
use tool_usertours\tour as toursource;
/**
* Tour renderable.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tour implements \renderable {
-
/**
* @var The tour instance.
*/
diff --git a/admin/tool/usertours/classes/privacy/provider.php b/admin/tool/usertours/classes/privacy/provider.php
index db71ee9a1a98..c65b204860fa 100644
--- a/admin/tool/usertours/classes/privacy/provider.php
+++ b/admin/tool/usertours/classes/privacy/provider.php
@@ -14,25 +14,16 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Privacy Subsystem implementation for tool_usertours.
- *
- * @package tool_usertours
- * @copyright 2018 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours\privacy;
-use \core_privacy\local\request\writer;
-use \core_privacy\local\metadata\collection;
-use \core_privacy\local\request\transform;
-
-defined('MOODLE_INTERNAL') || die();
+use core_privacy\local\request\writer;
+use core_privacy\local\metadata\collection;
+use core_privacy\local\request\transform;
/**
* Implementation of the privacy subsystem plugin provider for the user tours feature.
*
+ * @package tool_usertours
* @copyright 2018 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
@@ -41,9 +32,7 @@ class provider implements
\core_privacy\local\metadata\provider,
// This plugin has some sitewide user preferences to export.
- \core_privacy\local\request\user_preference_provider
-{
-
+ \core_privacy\local\request\user_preference_provider {
/**
* Returns meta data about this system.
*
diff --git a/admin/tool/usertours/classes/step.php b/admin/tool/usertours/classes/step.php
index 95715e177adf..485bc081536e 100644
--- a/admin/tool/usertours/classes/step.php
+++ b/admin/tool/usertours/classes/step.php
@@ -14,29 +14,19 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Step class.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours;
use context_system;
use stdClass;
-defined('MOODLE_INTERNAL') || die();
-
/**
* Step class.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class step {
-
/**
* @var int $id The id of the step.
*/
@@ -137,7 +127,7 @@ protected function fetch($id) {
global $DB;
return $this->reload_from_record(
- $DB->get_record('tool_usertours_steps', array('id' => $id))
+ $DB->get_record('tool_usertours_steps', ['id' => $id])
);
}
@@ -414,7 +404,7 @@ public function get_movedown_link() {
*/
public function get_config($key = null, $default = null) {
if ($this->config === null) {
- $this->config = (object) array();
+ $this->config = (object) [];
}
if ($key === null) {
@@ -448,7 +438,7 @@ public function get_config($key = null, $default = null) {
*/
public function set_config($key, $value) {
if ($this->config === null) {
- $this->config = (object) array();
+ $this->config = (object) [];
}
if ($value === null) {
@@ -497,7 +487,7 @@ protected function embed_files(): array {
'name' => $file->get_filename(),
'path' => $file->get_filepath(),
'content' => base64_encode($file->get_content()),
- 'encode' => 'base64'
+ 'encode' => 'base64',
];
}
@@ -635,7 +625,7 @@ public function remove() {
return;
}
- $DB->delete_records('tool_usertours_steps', array('id' => $this->id));
+ $DB->delete_records('tool_usertours_steps', ['id' => $this->id]);
$this->get_tour()->reset_step_sortorder();
// Notify of a change to the step configuration.
@@ -817,15 +807,19 @@ public static function get_step_image_from_input(string $content): string {
return $content;
}
- $content = preg_replace_callback('%@@PIXICON::(?P([^::]*))::(?P([^@@]*))@@%',
- function(array $matches) {
+ $content = preg_replace_callback(
+ '%@@PIXICON::(?P([^::]*))::(?P([^@@]*))@@%',
+ function (array $matches) {
global $OUTPUT;
$component = $matches['component'];
if ($component == 'moodle') {
$component = 'core';
}
- return \html_writer::img($OUTPUT->image_url($matches['identifier'], $component)->out(false), '',
- ['class' => 'img-fluid']);
+ return \html_writer::img(
+ $OUTPUT->image_url($matches['identifier'], $component)->out(false),
+ '',
+ ['class' => 'img-fluid']
+ );
},
$content
);
diff --git a/admin/tool/usertours/classes/target.php b/admin/tool/usertours/classes/target.php
index f65c2caa0e29..9299ca5180cd 100644
--- a/admin/tool/usertours/classes/target.php
+++ b/admin/tool/usertours/classes/target.php
@@ -14,26 +14,16 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Target class.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours;
-defined('MOODLE_INTERNAL') || die();
-
/**
* Target class.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class target {
-
/**
* @var TARGET_SELECTOR The target is a CSS selector.
*/
diff --git a/admin/tool/usertours/classes/tour.php b/admin/tool/usertours/classes/tour.php
index c51f9e85f0de..61001c5745d1 100644
--- a/admin/tool/usertours/classes/tour.php
+++ b/admin/tool/usertours/classes/tour.php
@@ -14,28 +14,16 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Tour class.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours;
-use tool_usertours\local\clientside_filter\clientside_filter;
-
-defined('MOODLE_INTERNAL') || die();
-
/**
* Tour class.
*
+ * @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tour {
-
/**
* The tour is currently disabled
*
@@ -64,6 +52,12 @@ class tour {
*/
const TOUR_REQUESTED_BY_USER = 'tool_usertours_tour_reset_time_';
+ /** @var int Whether to show the tour only until it has been marked complete */
+ const SHOW_TOUR_UNTIL_COMPLETE = 1;
+
+ /** @var int Whether to show the tour every time a page matches */
+ const SHOW_TOUR_ON_EACH_PAGE_VISIT = 2;
+
/**
* @var $id The tour ID.
*/
@@ -157,7 +151,7 @@ protected function fetch($id) {
global $DB;
return $this->reload_from_record(
- $DB->get_record('tool_usertours_tours', array('id' => $id), '*', MUST_EXIST)
+ $DB->get_record('tool_usertours_tours', ['id' => $id], '*', MUST_EXIST)
);
}
@@ -424,7 +418,7 @@ public function get_delete_link() {
* @return object
*/
public function to_record() {
- return (object) array(
+ return (object) [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
@@ -434,7 +428,7 @@ public function to_record() {
'endtourlabel' => $this->endtourlabel,
'configdata' => json_encode($this->config),
'displaystepnumbers' => $this->displaystepnumbers,
- );
+ ];
}
/**
@@ -519,7 +513,7 @@ public function get_movedown_link() {
*/
public function get_config($key = null, $default = null) {
if ($this->config === null) {
- $this->config = (object) array();
+ $this->config = (object) [];
}
if ($key === null) {
return $this->config;
@@ -545,7 +539,7 @@ public function get_config($key = null, $default = null) {
*/
public function set_config($key, $value) {
if ($this->config === null) {
- $this->config = (object) array();
+ $this->config = (object) [];
}
$this->config->$key = $value;
$this->dirty = true;
@@ -602,7 +596,7 @@ public function remove() {
}
// Remove the configuration for the tour.
- $DB->delete_records('tool_usertours_tours', array('id' => $this->id));
+ $DB->delete_records('tool_usertours_tours', ['id' => $this->id]);
helper::reset_tour_sortorder();
$this->remove_user_preferences();
@@ -617,11 +611,11 @@ public function remove() {
*/
public function reset_step_sortorder() {
global $DB;
- $steps = $DB->get_records('tool_usertours_steps', array('tourid' => $this->id), 'sortorder ASC', 'id');
+ $steps = $DB->get_records('tool_usertours_steps', ['tourid' => $this->id], 'sortorder ASC', 'id');
$index = 0;
foreach ($steps as $step) {
- $DB->set_field('tool_usertours_steps', 'sortorder', $index, array('id' => $step->id));
+ $DB->set_field('tool_usertours_steps', 'sortorder', $index, ['id' => $step->id]);
$index++;
}
@@ -653,6 +647,11 @@ public function should_show_for_user() {
return false;
}
+ if ($this->get_showtourwhen() === self::SHOW_TOUR_ON_EACH_PAGE_VISIT) {
+ // The tour should be shown on every page visit.
+ return true;
+ }
+
if ($tourcompletiondate = get_user_preferences(self::TOUR_LAST_COMPLETED_BY_USER . $this->get_id(), null)) {
if ($tourresetdate = get_user_preferences(self::TOUR_REQUESTED_BY_USER . $this->get_id(), null)) {
if ($tourresetdate >= $tourcompletiondate) {
@@ -775,6 +774,7 @@ protected function add_config_field_to_form(\MoodleQuickForm &$mform, $key) {
*/
public function prepare_data_for_form() {
$data = $this->to_record();
+ $data->showtourwhen = $this->get_showtourwhen();
foreach (configuration::get_defaultable_keys() as $key) {
$data->$key = $this->get_config($key, configuration::get_default_value($key));
}
@@ -872,4 +872,29 @@ public function set_display_step_numbers(bool $value): tour {
public function get_display_step_numbers(): bool {
return $this->displaystepnumbers;
}
+
+ /**
+ * Set the value for the when to show the tour.
+ *
+ * @see self::SHOW_TOUR_UNTIL_COMPLETE
+ * @see self::SHOW_TOUR_ON_EACH_PAGE_VISIT
+ *
+ * @param int $value
+ * @return self
+ */
+ public function set_showtourwhen(int $value): tour {
+ return $this->set_config('showtourwhen', $value);
+ }
+
+ /**
+ * When to show the tour.
+ *
+ * @see self::SHOW_TOUR_UNTIL_COMPLETE
+ * @see self::SHOW_TOUR_ON_EACH_PAGE_VISIT
+ *
+ * @return int
+ */
+ public function get_showtourwhen(): int {
+ return $this->get_config('showtourwhen', self::SHOW_TOUR_UNTIL_COMPLETE);
+ }
}
diff --git a/admin/tool/usertours/configure.php b/admin/tool/usertours/configure.php
index cb7bc9832182..5ff066b18e93 100644
--- a/admin/tool/usertours/configure.php
+++ b/admin/tool/usertours/configure.php
@@ -31,5 +31,5 @@
$PAGE->set_context(context_system::instance());
$pluginmanager->execute(
- $action
- );
+ $action
+);
diff --git a/admin/tool/usertours/db/access.php b/admin/tool/usertours/db/access.php
index 1e8e6b927c90..4dd38c2245d8 100644
--- a/admin/tool/usertours/db/access.php
+++ b/admin/tool/usertours/db/access.php
@@ -24,13 +24,13 @@
defined('MOODLE_INTERNAL') || die();
-$capabilities = array(
+$capabilities = [
'tool/usertours:managetours' => [
'captype' => 'write',
'riskbitmask' => RISK_XSS,
'contextlevel' => CONTEXT_SYSTEM,
'archetypes' => [
'manager' => CAP_ALLOW,
- ]
+ ],
],
-);
+];
diff --git a/admin/tool/usertours/db/caches.php b/admin/tool/usertours/db/caches.php
index 3ae3c8fb4c7d..28e384656994 100644
--- a/admin/tool/usertours/db/caches.php
+++ b/admin/tool/usertours/db/caches.php
@@ -24,19 +24,19 @@
defined('MOODLE_INTERNAL') || die();
-$definitions = array(
- 'tourdata' => array(
+$definitions = [
+ 'tourdata' => [
'mode' => cache_store::MODE_APPLICATION,
'simplekeys' => true,
'simpledata' => true,
'staticacceleration' => true,
'staticaccelerationsize' => 1,
- ),
- 'stepdata' => array(
+ ],
+ 'stepdata' => [
'mode' => cache_store::MODE_APPLICATION,
'simplekeys' => true,
'simpledata' => true,
'staticacceleration' => true,
'staticaccelerationsize' => 1,
- ),
-);
+ ],
+];
diff --git a/admin/tool/usertours/db/services.php b/admin/tool/usertours/db/services.php
index 38e65eaa5a52..9b47633c5d67 100644
--- a/admin/tool/usertours/db/services.php
+++ b/admin/tool/usertours/db/services.php
@@ -24,40 +24,40 @@
defined('MOODLE_INTERNAL') || die();
-$functions = array(
- 'tool_usertours_fetch_and_start_tour' => array(
+$functions = [
+ 'tool_usertours_fetch_and_start_tour' => [
'classname' => 'tool_usertours\external\tour',
'methodname' => 'fetch_and_start_tour',
'description' => 'Fetch the specified tour',
'type' => 'read',
'capabilities' => '',
'ajax' => true,
- ),
+ ],
- 'tool_usertours_step_shown' => array(
+ 'tool_usertours_step_shown' => [
'classname' => 'tool_usertours\external\tour',
'methodname' => 'step_shown',
'description' => 'Mark the specified step as completed for the current user',
'type' => 'write',
'capabilities' => '',
'ajax' => true,
- ),
+ ],
- 'tool_usertours_complete_tour' => array(
+ 'tool_usertours_complete_tour' => [
'classname' => 'tool_usertours\external\tour',
'methodname' => 'complete_tour',
'description' => 'Mark the specified tour as completed for the current user',
'type' => 'write',
'capabilities' => '',
'ajax' => true,
- ),
+ ],
- 'tool_usertours_reset_tour' => array(
+ 'tool_usertours_reset_tour' => [
'classname' => 'tool_usertours\external\tour',
'methodname' => 'reset_tour',
'description' => 'Remove the specified tour',
'type' => 'write',
'capabilities' => '',
'ajax' => true,
- ),
-);
+ ],
+];
diff --git a/admin/tool/usertours/lang/en/tool_usertours.php b/admin/tool/usertours/lang/en/tool_usertours.php
index 0672417b728a..815806de4a9a 100644
--- a/admin/tool/usertours/lang/en/tool_usertours.php
+++ b/admin/tool/usertours/lang/en/tool_usertours.php
@@ -36,6 +36,9 @@
Alternatively, a language string ID may be entered in the format identifier,component (with no brackets or space after the comma).';
$string['displaystepnumbers'] = 'Display step numbers';
$string['displaystepnumbers_help'] = 'Whether to display a step number count e.g. 1/4, 2/4 etc. to indicate the length of the user tour.';
+$string['showtourwhen'] = 'Show tour';
+$string['showtoureachtime'] = 'each time a filter matches it';
+$string['showtouruntilcomplete'] = 'until it has been closed';
$string['confirmstepremovalquestion'] = 'Are you sure that you wish to remove this step?';
$string['confirmstepremovaltitle'] = 'Confirm step removal';
$string['confirmtourremovalquestion'] = 'Are you sure that you wish to remove this tour?';
diff --git a/admin/tool/usertours/tests/accessdate_filter_test.php b/admin/tool/usertours/tests/accessdate_filter_test.php
index 52b44c3c31b4..1458ee14763c 100644
--- a/admin/tool/usertours/tests/accessdate_filter_test.php
+++ b/admin/tool/usertours/tests/accessdate_filter_test.php
@@ -24,9 +24,9 @@
* @package tool_usertours
* @copyright 2019 Tom Dickman
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @covers \tool_usertours\local\filter\accessdate
*/
class accessdate_filter_test extends \advanced_testcase {
-
public function setUp(): void {
$this->resetAfterTest(true);
}
@@ -36,7 +36,7 @@ public function setUp(): void {
*
* @return array
*/
- public function filter_matches_provider() {
+ public static function filter_matches_provider(): array {
return [
'No config set; Matches' => [
[],
@@ -45,61 +45,61 @@ public function filter_matches_provider() {
],
'Filter is not enabled; Match' => [
['filter_accessdate' => accessdate::FILTER_ACCOUNT_CREATION, 'filter_accessdate_range' => 90 * DAYSECS,
- 'filter_accessdate_enabled' => 0],
+ 'filter_accessdate_enabled' => 0, ],
['timecreated' => time() - (89 * DAYSECS)],
true,
],
'Filter is not enabled (tour would not be displayed if it was); Match' => [
['filter_accessdate' => accessdate::FILTER_ACCOUNT_CREATION, 'filter_accessdate_range' => 90 * DAYSECS,
- 'filter_accessdate_enabled' => 0],
+ 'filter_accessdate_enabled' => 0, ],
['timecreated' => time() - (91 * DAYSECS)],
true,
],
'Inside range of account creation date; Match' => [
['filter_accessdate' => accessdate::FILTER_ACCOUNT_CREATION, 'filter_accessdate_range' => 90 * DAYSECS,
- 'filter_accessdate_enabled' => 1],
+ 'filter_accessdate_enabled' => 1, ],
['timecreated' => time() - (89 * DAYSECS)],
true,
],
'Outside range of account creation date; No match' => [
['filter_accessdate' => accessdate::FILTER_ACCOUNT_CREATION, 'filter_accessdate_range' => 90 * DAYSECS,
- 'filter_accessdate_enabled' => 1],
+ 'filter_accessdate_enabled' => 1, ],
['timecreated' => time() - (91 * DAYSECS)],
false,
],
'Inside range of first login date; Match' => [
['filter_accessdate' => accessdate::FILTER_FIRST_LOGIN, 'filter_accessdate_range' => 90 * DAYSECS,
- 'filter_accessdate_enabled' => 1],
+ 'filter_accessdate_enabled' => 1, ],
['firstaccess' => time() - (89 * DAYSECS)],
true,
],
'Outside range of first login date; No match' => [
['filter_accessdate' => accessdate::FILTER_FIRST_LOGIN, 'filter_accessdate_range' => 90 * DAYSECS,
- 'filter_accessdate_enabled' => 1],
+ 'filter_accessdate_enabled' => 1, ],
['firstaccess' => time() - (91 * DAYSECS)],
false,
],
'Inside range of last login date; Match' => [
['filter_accessdate' => accessdate::FILTER_LAST_LOGIN, 'filter_accessdate_range' => 90 * DAYSECS,
- 'filter_accessdate_enabled' => 1],
+ 'filter_accessdate_enabled' => 1, ],
['lastlogin' => time() - (89 * DAYSECS)],
true,
],
'Outside range of last login date; No match' => [
['filter_accessdate' => accessdate::FILTER_LAST_LOGIN, 'filter_accessdate_range' => 90 * DAYSECS,
- 'filter_accessdate_enabled' => 1],
+ 'filter_accessdate_enabled' => 1, ],
['lastlogin' => time() - (91 * DAYSECS)],
false,
],
'User has never logged in, but tour should be visible; Match' => [
['filter_accessdate' => accessdate::FILTER_LAST_LOGIN, 'filter_accessdate_range' => 90 * DAYSECS,
- 'filter_accessdate_enabled' => 1],
+ 'filter_accessdate_enabled' => 1, ],
['lastlogin' => 0, 'timecreated' => time() - (89 * DAYSECS)],
true,
],
'User has never logged in, and tour should not be visible; No match' => [
['filter_accessdate' => accessdate::FILTER_LAST_LOGIN, 'filter_accessdate_range' => 90 * DAYSECS,
- 'filter_accessdate_enabled' => 1],
+ 'filter_accessdate_enabled' => 1, ],
['lastlogin' => 0, 'timecreated' => time() - (91 * DAYSECS)],
false,
],
@@ -115,7 +115,7 @@ public function filter_matches_provider() {
* @param array $userstate any user state required for test.
* @param bool $expected result expected.
*/
- public function test_filter_matches($filtervalues, $userstate, $expected) {
+ public function test_filter_matches($filtervalues, $userstate, $expected): void {
$course = $this->getDataGenerator()->create_course();
$context = \context_course::instance($course->id);
@@ -127,5 +127,4 @@ public function test_filter_matches($filtervalues, $userstate, $expected) {
$this->assertEquals($expected, accessdate::filter_matches($tour, $context));
}
-
}
diff --git a/admin/tool/usertours/tests/behat/behat_tool_usertours.php b/admin/tool/usertours/tests/behat/behat_tool_usertours.php
index ef00bd2f7a01..797f5b5142a9 100644
--- a/admin/tool/usertours/tests/behat/behat_tool_usertours.php
+++ b/admin/tool/usertours/tests/behat/behat_tool_usertours.php
@@ -25,7 +25,7 @@
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
-use Behat\Gherkin\Node\TableNode as TableNode;
+use Behat\Gherkin\Node\TableNode;
/**
* User tour related steps definitions.
*
@@ -35,7 +35,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_tool_usertours extends behat_base {
-
/**
* Add a new user tour.
*
@@ -90,8 +89,9 @@ public function i_add_steps_to_the_tour(TableNode $table) {
* @Given /^I open the User tour settings page$/
*/
public function i_open_the_user_tour_settings_page() {
- $this->execute('behat_navigation::i_navigate_to_in_site_administration',
- get_string('appearance', 'admin') . ' > ' .
+ $this->execute(
+ 'behat_navigation::i_navigate_to_in_site_administration',
+ get_string('appearance', 'admin') . ' > ' .
get_string('usertours', 'tool_usertours')
);
}
diff --git a/admin/tool/usertours/tests/behat/tour_prevents_completion.feature b/admin/tool/usertours/tests/behat/tour_prevents_completion.feature
new file mode 100644
index 000000000000..0b2e687be9f5
--- /dev/null
+++ b/admin/tool/usertours/tests/behat/tour_prevents_completion.feature
@@ -0,0 +1,29 @@
+@tool @tool_usertours
+Feature: Prevent yours from being marked as complete
+ In order to impart key information
+ As an administrator
+ I can prevent a user tour from being marked as complete
+
+ Background:
+ Given I log in as "admin"
+ And I add a new user tour with:
+ | Name | First tour |
+ | Description | My first tour |
+ | Apply to URL match | FRONTPAGE |
+ | Tour is enabled | 1 |
+ | Show with backdrop | 1 |
+ # 2 = tour::SHOW_TOUR_ON_EACH_PAGE_VISIT
+ | Show tour | 2 |
+ And I add steps to the "First tour" tour:
+ | targettype | Title | id_content | Content type |
+ | Display in middle of page | Welcome | Welcome tour. | Manual |
+
+ @javascript
+ Scenario: Ending the tour should not mark it as complete
+ # Changing the window viewport to mobile so we will have the footer section.
+ Given I am on site homepage
+ And I should see "Welcome"
+ And I press "Got it"
+ And I should not see "Welcome"
+ When I am on site homepage
+ Then I should see "Welcome"
diff --git a/admin/tool/usertours/tests/cache_test.php b/admin/tool/usertours/tests/cache_test.php
index 27f96008d12a..54cadfaf578a 100644
--- a/admin/tool/usertours/tests/cache_test.php
+++ b/admin/tool/usertours/tests/cache_test.php
@@ -27,6 +27,7 @@
* @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @covers \tool_usertours\cache
*/
class cache_test extends \advanced_testcase {
// There are shared helpers for these tests in the helper trait.
@@ -35,7 +36,7 @@ class cache_test extends \advanced_testcase {
/**
* Test that get_enabled_tourdata does not return disabled tours.
*/
- public function test_get_enabled_tourdata_disabled() {
+ public function test_get_enabled_tourdata_disabled(): void {
$this->resetAfterTest();
$tour = $this->helper_create_tour((object)['enabled' => false]);
@@ -48,7 +49,7 @@ public function test_get_enabled_tourdata_disabled() {
/**
* Test that get_enabled_tourdata does not return an enabled but empty tour.
*/
- public function test_get_enabled_tourdata_enabled_no_steps() {
+ public function test_get_enabled_tourdata_enabled_no_steps(): void {
$this->resetAfterTest();
$this->helper_create_tour();
@@ -60,7 +61,7 @@ public function test_get_enabled_tourdata_enabled_no_steps() {
/**
* Test that get_enabled_tourdata returns a tour with steps.
*/
- public function test_get_enabled_tourdata_enabled() {
+ public function test_get_enabled_tourdata_enabled(): void {
$this->resetAfterTest();
// Create two tours. Only the second has steps.
@@ -79,7 +80,7 @@ public function test_get_enabled_tourdata_enabled() {
/**
* Test that get_enabled_tourdata returns tours in the correct sortorder
*/
- public function test_get_enabled_tourdata_enabled_sortorder() {
+ public function test_get_enabled_tourdata_enabled_sortorder(): void {
$this->resetAfterTest();
$tour1 = $this->helper_create_tour();
@@ -100,7 +101,7 @@ public function test_get_enabled_tourdata_enabled_sortorder() {
/**
* Test that caching prevents additional DB reads.
*/
- public function test_get_enabled_tourdata_single_fetch() {
+ public function test_get_enabled_tourdata_single_fetch(): void {
global $DB;
$this->resetAfterTest();
@@ -118,7 +119,6 @@ public function test_get_enabled_tourdata_single_fetch() {
// No subsequent reads for any further calls.
$matches = \tool_usertours\cache::get_enabled_tourdata();
$this->assertEquals(1, $DB->perf_get_reads() - $startreads);
-
}
/**
@@ -126,31 +126,31 @@ public function test_get_enabled_tourdata_single_fetch() {
*
* @return array
*/
- public function get_matching_tourdata_provider() {
+ public static function get_matching_tourdata_provider(): array {
$tourconfigs = [
(object) [
'name' => 'my_exact_1',
- 'pathmatch' => '/my/view.php'
+ 'pathmatch' => '/my/view.php',
],
(object) [
'name' => 'my_failed_regex',
- 'pathmatch' => '/my/*.php'
+ 'pathmatch' => '/my/*.php',
],
(object) [
'name' => 'my_glob_1',
- 'pathmatch' => '/my/%'
+ 'pathmatch' => '/my/%',
],
(object) [
'name' => 'my_glob_2',
- 'pathmatch' => '/my/%'
+ 'pathmatch' => '/my/%',
],
(object) [
'name' => 'frontpage_only',
- 'pathmatch' => 'FRONTPAGE'
+ 'pathmatch' => 'FRONTPAGE',
],
(object) [
'name' => 'frontpage_match',
- 'pathmatch' => '/?%'
+ 'pathmatch' => '/?%',
],
];
@@ -186,7 +186,7 @@ public function get_matching_tourdata_provider() {
* @param string $targetmatch The match to be tested
* @param array $expected An array containing the ordered names of the expected tours
*/
- public function test_get_matching_tourdata($tourconfigs, $targetmatch, $expected) {
+ public function test_get_matching_tourdata($tourconfigs, $targetmatch, $expected): void {
$this->resetAfterTest();
foreach ($tourconfigs as $tourconfig) {
$tour = $this->helper_create_tour($tourconfig);
@@ -205,7 +205,7 @@ public function test_get_matching_tourdata($tourconfigs, $targetmatch, $expected
/**
* Test that notify_tour_change clears the cache.
*/
- public function test_notify_tour_change() {
+ public function test_notify_tour_change(): void {
global $DB;
$this->resetAfterTest();
@@ -236,7 +236,7 @@ public function test_notify_tour_change() {
/**
* Test that get_stepdata returns an empty array when no steps were found.
*/
- public function test_get_stepdata_no_steps() {
+ public function test_get_stepdata_no_steps(): void {
$this->resetAfterTest();
$tour = $this->helper_create_tour((object)['enabled' => false]);
@@ -249,7 +249,7 @@ public function test_get_stepdata_no_steps() {
/**
* Test that get_stepdata returns an empty array when no steps were found.
*/
- public function test_get_stepdata_correct_tour() {
+ public function test_get_stepdata_correct_tour(): void {
$this->resetAfterTest();
$tour1 = $this->helper_create_tour((object)['enabled' => false]);
@@ -274,7 +274,7 @@ public function test_get_stepdata_correct_tour() {
* This is very difficult to determine because the act of changing the
* order will likely change the DB natural sorting.
*/
- public function test_get_stepdata_ordered_steps() {
+ public function test_get_stepdata_ordered_steps(): void {
$this->resetAfterTest();
$tour = $this->helper_create_tour((object)['enabled' => false]);
@@ -290,7 +290,7 @@ public function test_get_stepdata_ordered_steps() {
$this->assertCount(4, $data);
// Re-order the steps.
- usort($steps, function($a, $b) {
+ usort($steps, function ($a, $b) {
return ($a->get_sortorder() < $b->get_sortorder()) ? -1 : 1;
});
@@ -303,7 +303,7 @@ public function test_get_stepdata_ordered_steps() {
/**
* Test that caching prevents additional DB reads.
*/
- public function test_get_stepdata_single_fetch() {
+ public function test_get_stepdata_single_fetch(): void {
global $DB;
$this->resetAfterTest();
@@ -324,7 +324,7 @@ public function test_get_stepdata_single_fetch() {
/**
* Test that notify_step_change clears the cache.
*/
- public function test_notify_step_change() {
+ public function test_notify_step_change(): void {
global $DB;
$this->resetAfterTest();
diff --git a/admin/tool/usertours/tests/helper_test.php b/admin/tool/usertours/tests/helper_test.php
index f6c574b30776..3a2f1cdad262 100644
--- a/admin/tool/usertours/tests/helper_test.php
+++ b/admin/tool/usertours/tests/helper_test.php
@@ -14,35 +14,25 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Tests for helper.
- *
- * @package tool_usertours
- * @copyright 2022 Huong Nguyen
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace tool_usertours;
use advanced_testcase;
-defined('MOODLE_INTERNAL') || die();
-
/**
* Tests for helper.
*
* @package tool_usertours
* @copyright 2022 Huong Nguyen
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @covers \tool_usertours\helper
*/
class helper_test extends advanced_testcase {
-
/**
* Data Provider for get_string_from_input.
*
* @return array
*/
- public function get_string_from_input_provider(): array {
+ public static function get_string_from_input_provider(): array {
return [
'Text' => [
'example',
@@ -78,7 +68,7 @@ public function get_string_from_input_provider(): array {
* @param string $string The string to test
* @param string $expected The expected result
*/
- public function test_get_string_from_input($string, $expected) {
+ public function test_get_string_from_input($string, $expected): void {
$this->assertEquals($expected, helper::get_string_from_input($string));
}
}
diff --git a/admin/tool/usertours/tests/helper_trait.php b/admin/tool/usertours/tests/helper_trait.php
index c3638a1d41bf..988ace5abcd4 100644
--- a/admin/tool/usertours/tests/helper_trait.php
+++ b/admin/tool/usertours/tests/helper_trait.php
@@ -14,16 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Helpers for unit tests.
- *
- * @package tool_usertours
- * @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
/**
* Helpers for unit tests.
*
@@ -47,7 +37,7 @@ public function helper_create_tour(\stdClass $tourconfig = null, $persist = true
'name' => '',
'description' => '',
'configdata' => '',
- 'displaystepnumbers' => true
+ 'displaystepnumbers' => true,
];
if ($tourconfig === null) {
diff --git a/admin/tool/usertours/tests/manager_test.php b/admin/tool/usertours/tests/manager_test.php
index 17751f0aa745..924ba268e85f 100644
--- a/admin/tool/usertours/tests/manager_test.php
+++ b/admin/tool/usertours/tests/manager_test.php
@@ -28,6 +28,7 @@
* @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @covers \tool_usertours\manager
*/
class manager_test extends \advanced_testcase {
// There are shared helpers for these tests in the helper trait.
@@ -74,28 +75,28 @@ public function mock_database() {
*
* @return array
*/
- public function sesskey_required_provider() {
+ public static function sesskey_required_provider(): array {
$tourid = rand(1, 100);
$stepid = rand(1, 100);
return [
- 'Tour removal' => [
- 'delete_tour',
- [$tourid],
- ],
- 'Step removal' => [
- 'delete_step',
- [$stepid],
- ],
- 'Tour visibility' => [
- 'show_hide_tour',
- [$tourid, true],
- ],
- 'Move step' => [
- 'move_step',
- [$stepid],
- ],
- ];
+ 'Tour removal' => [
+ 'delete_tour',
+ [$tourid],
+ ],
+ 'Step removal' => [
+ 'delete_step',
+ [$stepid],
+ ],
+ 'Tour visibility' => [
+ 'show_hide_tour',
+ [$tourid, true],
+ ],
+ 'Move step' => [
+ 'move_step',
+ [$stepid],
+ ],
+ ];
}
/**
@@ -105,12 +106,11 @@ public function sesskey_required_provider() {
* @param string $function The function to test
* @param array $arguments The arguments to pass with it
*/
- public function test_sesskey_required($function, $arguments) {
+ public function test_sesskey_required($function, $arguments): void {
$manager = new \tool_usertours\manager();
$rc = new \ReflectionClass('\tool_usertours\manager');
$rcm = $rc->getMethod($function);
- $rcm->setAccessible(true);
$this->expectException('moodle_exception');
$rcm->invokeArgs($manager, $arguments);
@@ -121,7 +121,7 @@ public function test_sesskey_required($function, $arguments) {
*
* @return array
*/
- public function move_tour_provider() {
+ public static function move_tour_provider(): array {
$alltours = [
['name' => 'Tour 1'],
['name' => 'Tour 2'],
@@ -167,7 +167,7 @@ public function move_tour_provider() {
* @param int $expectedsortorder
* @return void
*/
- public function test_move_tour($alltours, $movetourname, $direction, $expectedsortorder) {
+ public function test_move_tour($alltours, $movetourname, $direction, $expectedsortorder): void {
global $DB;
$this->resetAfterTest();
@@ -186,7 +186,6 @@ public function test_move_tour($alltours, $movetourname, $direction, $expectedso
// Call protected method via reflection.
$class = new \ReflectionClass(\tool_usertours\manager::class);
$method = $class->getMethod('_move_tour');
- $method->setAccessible(true);
$method->invokeArgs(null, [$tour, $direction]);
// Assert expected sortorder.
@@ -198,114 +197,115 @@ public function test_move_tour($alltours, $movetourname, $direction, $expectedso
*
* @return array
*/
- public function get_matching_tours_provider() {
+ public static function get_matching_tours_provider(): array {
global $CFG;
$alltours = [
[
- 'pathmatch' => '/my/%',
- 'enabled' => false,
- 'name' => 'Failure',
- 'description' => '',
- 'configdata' => '',
- ],
+ 'pathmatch' => '/my/%',
+ 'enabled' => false,
+ 'name' => 'Failure',
+ 'description' => '',
+ 'configdata' => '',
+ ],
[
- 'pathmatch' => '/my/%',
- 'enabled' => true,
- 'name' => 'My tour enabled',
- 'description' => '',
- 'configdata' => '',
- ],
+ 'pathmatch' => '/my/%',
+ 'enabled' => true,
+ 'name' => 'My tour enabled',
+ 'description' => '',
+ 'configdata' => '',
+ ],
[
- 'pathmatch' => '/my/%',
- 'enabled' => true,
- 'name' => 'My tour enabled 2',
- 'description' => '',
- 'configdata' => '',
- ],
+ 'pathmatch' => '/my/%',
+ 'enabled' => true,
+ 'name' => 'My tour enabled 2',
+ 'description' => '',
+ 'configdata' => '',
+ ],
[
- 'pathmatch' => '/my/%',
- 'enabled' => false,
- 'name' => 'Failure',
- 'description' => '',
- 'configdata' => '',
- ],
+ 'pathmatch' => '/my/%',
+ 'enabled' => false,
+ 'name' => 'Failure',
+ 'description' => '',
+ 'configdata' => '',
+ ],
[
- 'pathmatch' => '/course/?id=%foo=bar',
- 'enabled' => false,
- 'name' => 'Failure',
- 'description' => '',
- 'configdata' => '',
- ],
+ 'pathmatch' => '/course/?id=%foo=bar',
+ 'enabled' => false,
+ 'name' => 'Failure',
+ 'description' => '',
+ 'configdata' => '',
+ ],
[
- 'pathmatch' => '/course/?id=%foo=bar',
- 'enabled' => true,
- 'name' => 'course tour with additional params enabled',
- 'description' => '',
- 'configdata' => '',
- ],
+ 'pathmatch' => '/course/?id=%foo=bar',
+ 'enabled' => true,
+ 'name' => 'course tour with additional params enabled',
+ 'description' => '',
+ 'configdata' => '',
+ ],
[
- 'pathmatch' => '/course/?id=%foo=bar',
- 'enabled' => false,
- 'name' => 'Failure',
- 'description' => '',
- 'configdata' => '',
- ],
+ 'pathmatch' => '/course/?id=%foo=bar',
+ 'enabled' => false,
+ 'name' => 'Failure',
+ 'description' => '',
+ 'configdata' => '',
+ ],
[
- 'pathmatch' => '/course/?id=%',
- 'enabled' => false,
- 'name' => 'Failure',
- 'description' => '',
- 'configdata' => '',
- ],
+ 'pathmatch' => '/course/?id=%',
+ 'enabled' => false,
+ 'name' => 'Failure',
+ 'description' => '',
+ 'configdata' => '',
+ ],
[
- 'pathmatch' => '/course/?id=%',
- 'enabled' => true,
- 'name' => 'course tour enabled',
- 'description' => '',
- 'configdata' => '',
- ],
+ 'pathmatch' => '/course/?id=%',
+ 'enabled' => true,
+ 'name' => 'course tour enabled',
+ 'description' => '',
+ 'configdata' => '',
+ ],
[
- 'pathmatch' => '/course/?id=%',
- 'enabled' => false,
- 'name' => 'Failure',
- 'description' => '',
- 'configdata' => '',
- ],
+ 'pathmatch' => '/course/?id=%',
+ 'enabled' => false,
+ 'name' => 'Failure',
+ 'description' => '',
+ 'configdata' => '',
+ ],
];
- return [
- 'No matches found' => [
- $alltours,
- $CFG->wwwroot . '/some/invalid/value',
- [],
- ],
- 'Never return a disabled tour' => [
- $alltours,
- $CFG->wwwroot . '/my/index.php',
- ['My tour enabled', 'My tour enabled 2'],
- ],
- 'My not course' => [
- $alltours,
- $CFG->wwwroot . '/my/index.php',
- ['My tour enabled', 'My tour enabled 2'],
- ],
- 'My with params' => [
- $alltours,
- $CFG->wwwroot . '/my/index.php?id=42',
- ['My tour enabled', 'My tour enabled 2'],
- ],
- 'Course with params' => [
- $alltours,
- $CFG->wwwroot . '/course/?id=42',
- ['course tour enabled'],
- ],
- 'Course with params and trailing content' => [
- $alltours,
- $CFG->wwwroot . '/course/?id=42&foo=bar',
- ['course tour with additional params enabled', 'course tour enabled'],
- ],
- ];
+ return
+ [
+ 'No matches found' => [
+ $alltours,
+ $CFG->wwwroot . '/some/invalid/value',
+ [],
+ ],
+ 'Never return a disabled tour' => [
+ $alltours,
+ $CFG->wwwroot . '/my/index.php',
+ ['My tour enabled', 'My tour enabled 2'],
+ ],
+ 'My not course' => [
+ $alltours,
+ $CFG->wwwroot . '/my/index.php',
+ ['My tour enabled', 'My tour enabled 2'],
+ ],
+ 'My with params' => [
+ $alltours,
+ $CFG->wwwroot . '/my/index.php?id=42',
+ ['My tour enabled', 'My tour enabled 2'],
+ ],
+ 'Course with params' => [
+ $alltours,
+ $CFG->wwwroot . '/course/?id=42',
+ ['course tour enabled'],
+ ],
+ 'Course with params and trailing content' => [
+ $alltours,
+ $CFG->wwwroot . '/course/?id=42&foo=bar',
+ ['course tour with additional params enabled', 'course tour enabled'],
+ ],
+ ];
}
/**
@@ -316,7 +316,7 @@ public function get_matching_tours_provider() {
* @param string $url The URL to test.
* @param array $expected List of names of the expected matching tours.
*/
- public function test_get_matching_tours(array $alltours, string $url, array $expected) {
+ public function test_get_matching_tours(array $alltours, string $url, array $expected): void {
$this->resetAfterTest();
$this->setGuestUser();
@@ -336,7 +336,7 @@ public function test_get_matching_tours(array $alltours, string $url, array $exp
/**
* Test that no matching tours are returned if there is pending site policy agreement.
*/
- public function test_get_matching_tours_for_user_without_site_policy_agreed() {
+ public function test_get_matching_tours_for_user_without_site_policy_agreed(): void {
global $CFG;
$this->resetAfterTest();
diff --git a/admin/tool/usertours/tests/privacy/provider_test.php b/admin/tool/usertours/tests/privacy/provider_test.php
index 907feb483524..e63ace554d3c 100644
--- a/admin/tool/usertours/tests/privacy/provider_test.php
+++ b/admin/tool/usertours/tests/privacy/provider_test.php
@@ -14,18 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Unit tests for the tool_usertours implementation of the privacy API.
- *
- * @package tool_usertours
- * @category test
- * @copyright 2018 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
namespace tool_usertours\privacy;
-defined('MOODLE_INTERNAL') || die();
-
use core_privacy\local\metadata\collection;
use core_privacy\local\request\writer;
use tool_usertours\tour;
@@ -34,11 +24,13 @@
/**
* Unit tests for the tool_usertours implementation of the privacy API.
*
+ * @package tool_usertours
+ * @category test
* @copyright 2018 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @covers \tool_usertours\privacy\provider
*/
class provider_test extends \core_privacy\tests\provider_testcase {
-
/**
* Helper method for creating a tour
*
@@ -56,7 +48,7 @@ protected function create_test_tour(): tour {
/**
* Ensure that get_metadata exports valid content.
*/
- public function test_get_metadata() {
+ public function test_get_metadata(): void {
$items = new collection('tool_usertours');
$result = provider::get_metadata($items);
$this->assertSame($items, $result);
@@ -66,7 +58,7 @@ public function test_get_metadata() {
/**
* Ensure that export_user_preferences returns no data if the user has completed no tours.
*/
- public function test_export_user_preferences_no_pref() {
+ public function test_export_user_preferences_no_pref(): void {
$user = \core_user::get_user_by_username('admin');
provider::export_user_preferences($user->id);
@@ -78,7 +70,7 @@ public function test_export_user_preferences_no_pref() {
/**
* Ensure that export_user_preferences returns request completion data.
*/
- public function test_export_user_preferences_completed() {
+ public function test_export_user_preferences_completed(): void {
global $DB;
$this->resetAfterTest();
@@ -101,7 +93,7 @@ public function test_export_user_preferences_completed() {
/**
* Ensure that export_user_preferences returns request completion data.
*/
- public function test_export_user_preferences_requested() {
+ public function test_export_user_preferences_requested(): void {
global $DB;
$this->resetAfterTest();
@@ -149,14 +141,16 @@ public function test_export_user_preferences_correct_user(): void {
$this->assertCount(1, $prefs);
// We should have received back the "completed tour" preference of the test user.
- $this->assertStringStartsWith('You last marked the "' . $tour->get_name() . '" user tour as completed on',
- reset($prefs)->description);
+ $this->assertStringStartsWith(
+ 'You last marked the "' . $tour->get_name() . '" user tour as completed on',
+ reset($prefs)->description
+ );
}
/**
* Ensure that export_user_preferences excludes deleted tours.
*/
- public function test_export_user_preferences_deleted_tour() {
+ public function test_export_user_preferences_deleted_tour(): void {
global $DB;
$this->resetAfterTest();
diff --git a/admin/tool/usertours/tests/role_filter_test.php b/admin/tool/usertours/tests/role_filter_test.php
index 20ee1be96298..ceff72fb39ba 100644
--- a/admin/tool/usertours/tests/role_filter_test.php
+++ b/admin/tool/usertours/tests/role_filter_test.php
@@ -22,9 +22,9 @@
* @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @covers \tool_usertours\local\filter\role
*/
class role_filter_test extends \advanced_testcase {
-
/**
* @var $course Test course
*/
@@ -72,7 +72,7 @@ public function setUp(): void {
/**
* Test the filter_matches function when any is set.
*/
- public function test_filter_matches_any() {
+ public function test_filter_matches_any(): void {
$context = \context_course::instance($this->course->id);
// Note: No need to persist this tour.
@@ -93,7 +93,7 @@ public function test_filter_matches_any() {
/**
* Test the filter_matches function when one role is set.
*/
- public function test_filter_matches_single_role() {
+ public function test_filter_matches_single_role(): void {
$context = \context_course::instance($this->course->id);
$roles = [
@@ -122,7 +122,7 @@ public function test_filter_matches_single_role() {
/**
* Test the filter_matches function when multiple roles are set.
*/
- public function test_filter_matches_multiple_role() {
+ public function test_filter_matches_multiple_role(): void {
$context = \context_course::instance($this->course->id);
$roles = [
@@ -152,7 +152,7 @@ public function test_filter_matches_multiple_role() {
/**
* Test the filter_matches function when one user has multiple roles.
*/
- public function test_filter_matches_multiple_role_one_user() {
+ public function test_filter_matches_multiple_role_one_user(): void {
$context = \context_course::instance($this->course->id);
$roles = [
@@ -184,7 +184,7 @@ public function test_filter_matches_multiple_role_one_user() {
/**
* Test the filter_matches function when it is targetted at an admin.
*/
- public function test_filter_matches_multiple_role_only_admin() {
+ public function test_filter_matches_multiple_role_only_admin(): void {
$context = \context_course::instance($this->course->id);
$roles = [
@@ -212,7 +212,7 @@ public function test_filter_matches_multiple_role_only_admin() {
/**
* Test the filter_matches function when multiple roles are set, including an admin user.
*/
- public function test_filter_matches_multiple_role_including_admin() {
+ public function test_filter_matches_multiple_role_including_admin(): void {
$context = \context_course::instance($this->course->id);
$roles = [
@@ -243,7 +243,7 @@ public function test_filter_matches_multiple_role_including_admin() {
/**
* Test the filter_matches function when an admin user has multiple roles.
*/
- public function test_filter_matches_multiple_role_admin_user() {
+ public function test_filter_matches_multiple_role_admin_user(): void {
global $USER;
$context = \context_course::instance($this->course->id);
@@ -266,7 +266,7 @@ public function test_filter_matches_multiple_role_admin_user() {
/**
* Test that the get_filter_options function does not include the guest roles.
*/
- public function test_get_filter_options_no_guest_roles() {
+ public function test_get_filter_options_no_guest_roles(): void {
create_role('Test Role', 'testrole', 'This is a test role', 'guest');
$allroles = role_get_names(null, ROLENAME_ALIAS);
diff --git a/admin/tool/usertours/tests/step_test.php b/admin/tool/usertours/tests/step_test.php
index 434908e01d53..8ba2cafa2faf 100644
--- a/admin/tool/usertours/tests/step_test.php
+++ b/admin/tool/usertours/tests/step_test.php
@@ -27,9 +27,9 @@
* @package tool_usertours
* @copyright 2016 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @covers \tool_usertours\step
*/
class step_test extends \advanced_testcase {
-
/**
* @var moodle_database
*/
@@ -62,8 +62,7 @@ public function mock_database() {
global $DB;
$DB = $this->getMockBuilder('moodle_database')
- ->getMock()
- ;
+ ->getMock();
return $DB;
}
@@ -73,64 +72,61 @@ public function mock_database() {
*
* @return array
*/
- public function dirty_value_provider() {
- return [
+ public static function dirty_value_provider(): array {
+ return
+ [
'tourid' => [
- 'tourid',
- [1],
- ],
+ 'tourid',
+ [1],
+ ],
'title' => [
- 'title',
- ['Lorem'],
- ],
+ 'title',
+ ['Lorem'],
+ ],
'content' => [
- 'content',
- ['Lorem'],
- ],
+ 'content',
+ ['Lorem'],
+ ],
'targettype' => [
- 'targettype',
- ['Lorem'],
- ],
+ 'targettype',
+ ['Lorem'],
+ ],
'targetvalue' => [
- 'targetvalue',
- ['Lorem'],
- ],
+ 'targetvalue',
+ ['Lorem'],
+ ],
'sortorder' => [
- 'sortorder',
- [1],
- ],
+ 'sortorder',
+ [1],
+ ],
'config' => [
- 'config',
- ['key', 'value'],
- ],
+ 'config',
+ ['key', 'value'],
+ ],
];
}
/**
* Test the fetch function.
*/
- public function test_fetch() {
+ public function test_fetch(): void {
$step = $this->getMockBuilder(\tool_usertours\step::class)
->onlyMethods(['reload_from_record'])
- ->getMock()
- ;
+ ->getMock();
$idretval = rand(1, 100);
$DB = $this->mock_database();
$DB->method('get_record')
- ->willReturn($idretval)
- ;
+ ->willReturn($idretval);
$retval = rand(1, 100);
$step->expects($this->once())
->method('reload_from_record')
->with($this->equalTo($idretval))
- ->wilLReturn($retval)
- ;
+ ->wilLReturn($retval);
$rc = new \ReflectionClass(\tool_usertours\step::class);
$rcm = $rc->getMethod('fetch');
- $rcm->setAccessible(true);
$id = rand(1, 100);
$this->assertEquals($retval, $rcm->invoke($step, 'fetch', $id));
@@ -143,14 +139,13 @@ public function test_fetch() {
* @param string $name The key to update
* @param string $value The value to set
*/
- public function test_dirty_values($name, $value) {
+ public function test_dirty_values($name, $value): void {
$step = new \tool_usertours\step();
$method = 'set_' . $name;
call_user_func_array([$step, $method], $value);
$rc = new \ReflectionClass(\tool_usertours\step::class);
$rcp = $rc->getProperty('dirty');
- $rcp->setAccessible(true);
$this->assertTrue($rcp->getValue($step));
}
@@ -160,12 +155,12 @@ public function test_dirty_values($name, $value) {
*
* @return array
*/
- public function step_sortorder_provider() {
+ public static function step_sortorder_provider(): array {
return [
- [0, 5, true, false],
- [1, 5, false, false],
- [4, 5, false, true],
- ];
+ [0, 5, true, false],
+ [1, 5, false, false],
+ [4, 5, false, true],
+ ];
}
/**
@@ -177,15 +172,14 @@ public function step_sortorder_provider() {
* @param bool $isfirst Whether this is the first step
* @param bool $islast Whether this is the last step
*/
- public function test_is_first_step($sortorder, $count, $isfirst, $islast) {
+ public function test_is_first_step($sortorder, $count, $isfirst, $islast): void {
$step = $this->getMockBuilder(\tool_usertours\step::class)
->onlyMethods(['get_sortorder'])
->getMock();
$step->expects($this->once())
->method('get_sortorder')
- ->willReturn($sortorder)
- ;
+ ->willReturn($sortorder);
$this->assertEquals($isfirst, $step->is_first_step());
}
@@ -199,7 +193,7 @@ public function test_is_first_step($sortorder, $count, $isfirst, $islast) {
* @param bool $isfirst Whether this is the first step
* @param bool $islast Whether this is the last step
*/
- public function test_is_last_step($sortorder, $count, $isfirst, $islast) {
+ public function test_is_last_step($sortorder, $count, $isfirst, $islast): void {
$step = $this->getMockBuilder(\tool_usertours\step::class)
->onlyMethods(['get_sortorder', 'get_tour'])
->getMock();
@@ -210,18 +204,15 @@ public function test_is_last_step($sortorder, $count, $isfirst, $islast) {
$step->expects($this->once())
->method('get_tour')
- ->willReturn($tour)
- ;
+ ->willReturn($tour);
$tour->expects($this->once())
->method('count_steps')
- ->willReturn($count)
- ;
+ ->willReturn($count);
$step->expects($this->once())
->method('get_sortorder')
- ->willReturn($sortorder)
- ;
+ ->willReturn($sortorder);
$this->assertEquals($islast, $step->is_last_step());
}
@@ -229,20 +220,19 @@ public function test_is_last_step($sortorder, $count, $isfirst, $islast) {
/**
* Test get_config with no keys provided.
*/
- public function test_get_config_no_keys() {
+ public function test_get_config_no_keys(): void {
$step = new \tool_usertours\step();
$rc = new \ReflectionClass(\tool_usertours\step::class);
$rcp = $rc->getProperty('config');
- $rcp->setAccessible(true);
$allvalues = (object) [
- 'some' => 'value',
- 'another' => 42,
- 'key' => [
- 'somethingelse',
- ],
- ];
+ 'some' => 'value',
+ 'another' => 42,
+ 'key' => [
+ 'somethingelse',
+ ],
+ ];
$rcp->setValue($step, $allvalues);
@@ -254,92 +244,92 @@ public function test_get_config_no_keys() {
*
* @return array
*/
- public function get_config_provider() {
+ public static function get_config_provider(): array {
$allvalues = (object) [
- 'some' => 'value',
- 'another' => 42,
- 'key' => [
- 'somethingelse',
- ],
- ];
+ 'some' => 'value',
+ 'another' => 42,
+ 'key' => [
+ 'somethingelse',
+ ],
+ ];
$tourconfig = rand(1, 100);
$forcedconfig = rand(1, 100);
return [
- 'No initial config' => [
- null,
- null,
- null,
- $tourconfig,
- false,
- $forcedconfig,
- (object) [],
- ],
- 'All values' => [
- $allvalues,
- null,
- null,
- $tourconfig,
- false,
- $forcedconfig,
- $allvalues,
- ],
- 'Valid string value' => [
- $allvalues,
- 'some',
- null,
- $tourconfig,
- false,
- $forcedconfig,
- 'value',
- ],
- 'Valid array value' => [
- $allvalues,
- 'key',
- null,
- $tourconfig,
- false,
- $forcedconfig,
- ['somethingelse'],
- ],
- 'Invalid value' => [
- $allvalues,
- 'notavalue',
- null,
- $tourconfig,
- false,
- $forcedconfig,
- $tourconfig,
- ],
- 'Configuration value' => [
- $allvalues,
- 'placement',
- null,
- $tourconfig,
- false,
- $forcedconfig,
- $tourconfig,
- ],
- 'Invalid value with default' => [
- $allvalues,
- 'notavalue',
- 'somedefault',
- $tourconfig,
- false,
- $forcedconfig,
- 'somedefault',
- ],
- 'Value forced at target' => [
- $allvalues,
- 'somevalue',
- 'somedefault',
- $tourconfig,
- true,
- $forcedconfig,
- $forcedconfig,
- ],
- ];
+ 'No initial config' => [
+ null,
+ null,
+ null,
+ $tourconfig,
+ false,
+ $forcedconfig,
+ (object) [],
+ ],
+ 'All values' => [
+ $allvalues,
+ null,
+ null,
+ $tourconfig,
+ false,
+ $forcedconfig,
+ $allvalues,
+ ],
+ 'Valid string value' => [
+ $allvalues,
+ 'some',
+ null,
+ $tourconfig,
+ false,
+ $forcedconfig,
+ 'value',
+ ],
+ 'Valid array value' => [
+ $allvalues,
+ 'key',
+ null,
+ $tourconfig,
+ false,
+ $forcedconfig,
+ ['somethingelse'],
+ ],
+ 'Invalid value' => [
+ $allvalues,
+ 'notavalue',
+ null,
+ $tourconfig,
+ false,
+ $forcedconfig,
+ $tourconfig,
+ ],
+ 'Configuration value' => [
+ $allvalues,
+ 'placement',
+ null,
+ $tourconfig,
+ false,
+ $forcedconfig,
+ $tourconfig,
+ ],
+ 'Invalid value with default' => [
+ $allvalues,
+ 'notavalue',
+ 'somedefault',
+ $tourconfig,
+ false,
+ $forcedconfig,
+ 'somedefault',
+ ],
+ 'Value forced at target' => [
+ $allvalues,
+ 'somevalue',
+ 'somedefault',
+ $tourconfig,
+ true,
+ $forcedconfig,
+ $forcedconfig,
+ ],
+ ];
}
/**
@@ -354,55 +344,46 @@ public function get_config_provider() {
* @param mixed $forcedvalue The example value
* @param mixed $expected The expected value
*/
- public function test_get_config_valid_keys($values, $key, $default, $tourconfig, $isforced, $forcedvalue, $expected) {
+ public function test_get_config_valid_keys($values, $key, $default, $tourconfig, $isforced, $forcedvalue, $expected): void {
$step = $this->getMockBuilder(\tool_usertours\step::class)
->onlyMethods(['get_target', 'get_targettype', 'get_tour'])
->getMock();
$rc = new \ReflectionClass(\tool_usertours\step::class);
$rcp = $rc->getProperty('config');
- $rcp->setAccessible(true);
$rcp->setValue($step, $values);
$target = $this->getMockBuilder(\tool_usertours\local\target\base::class)
->disableOriginalConstructor()
- ->getMock()
- ;
+ ->getMock();
$target->expects($this->any())
->method('is_setting_forced')
- ->willReturn($isforced)
- ;
+ ->willReturn($isforced);
$target->expects($this->any())
->method('get_forced_setting_value')
->with($this->equalTo($key))
- ->willReturn($forcedvalue)
- ;
+ ->willReturn($forcedvalue);
$step->expects($this->any())
->method('get_targettype')
- ->willReturn('type')
- ;
+ ->willReturn('type');
$step->expects($this->any())
->method('get_target')
- ->willReturn($target)
- ;
+ ->willReturn($target);
$tour = $this->getMockBuilder(\tool_usertours\tour::class)
- ->getMock()
- ;
+ ->getMock();
$tour->expects($this->any())
->method('get_config')
- ->willReturn($tourconfig)
- ;
+ ->willReturn($tourconfig);
$step->expects($this->any())
->method('get_tour')
- ->willReturn($tour)
- ;
+ ->willReturn($tour);
$this->assertEquals($expected, $step->get_config($key, $default));
}
@@ -410,14 +391,14 @@ public function test_get_config_valid_keys($values, $key, $default, $tourconfig,
/**
* Data provider for set_config.
*/
- public function set_config_provider() {
+ public static function set_config_provider(): array {
$allvalues = (object) [
- 'some' => 'value',
- 'another' => 42,
- 'key' => [
- 'somethingelse',
- ],
- ];
+ 'some' => 'value',
+ 'another' => 42,
+ 'key' => [
+ 'somethingelse',
+ ],
+ ];
$randvalue = rand(1, 100);
@@ -426,27 +407,27 @@ public function set_config_provider() {
$newvalues = $allvalues;
$newvalues->some = 'unset';
$provider['Unset an existing value'] = [
- $allvalues,
- 'some',
- null,
- $newvalues,
- ];
+ $allvalues,
+ 'some',
+ null,
+ $newvalues,
+ ];
$newvalues = $allvalues;
$newvalues->some = $randvalue;
$provider['Set an existing value'] = [
- $allvalues,
- 'some',
- $randvalue,
- $newvalues,
- ];
+ $allvalues,
+ 'some',
+ $randvalue,
+ $newvalues,
+ ];
$provider['Set a new value'] = [
- $allvalues,
- 'newkey',
- $randvalue,
- (object) array_merge((array) $allvalues, ['newkey' => $randvalue]),
- ];
+ $allvalues,
+ 'newkey',
+ $randvalue,
+ (object) array_merge((array) $allvalues, ['newkey' => $randvalue]),
+ ];
return $provider;
}
@@ -460,23 +441,20 @@ public function set_config_provider() {
* @param mixed $newvalue The new value to set
* @param mixed $expected The expected value
*/
- public function test_set_config($initialvalues, $key, $newvalue, $expected) {
+ public function test_set_config($initialvalues, $key, $newvalue, $expected): void {
$step = new \tool_usertours\step();
$rc = new \ReflectionClass(\tool_usertours\step::class);
$rcp = $rc->getProperty('config');
- $rcp->setAccessible(true);
$rcp->setValue($step, $initialvalues);
$target = $this->getMockBuilder(\tool_usertours\local\target\base::class)
->disableOriginalConstructor()
- ->getMock()
- ;
+ ->getMock();
$target->expects($this->any())
->method('is_setting_forced')
- ->willReturn(false)
- ;
+ ->willReturn(false);
$step->set_config($key, $newvalue);
@@ -486,22 +464,19 @@ public function test_set_config($initialvalues, $key, $newvalue, $expected) {
/**
* Ensure that non-dirty tours are not persisted.
*/
- public function test_persist_non_dirty() {
+ public function test_persist_non_dirty(): void {
$step = $this->getMockBuilder(\tool_usertours\step::class)
->onlyMethods([
- 'to_record',
- 'reload',
- ])
- ->getMock()
- ;
+ 'to_record',
+ 'reload',
+ ])
+ ->getMock();
$step->expects($this->never())
- ->method('to_record')
- ;
+ ->method('to_record');
$step->expects($this->never())
- ->method('reload')
- ;
+ ->method('reload');
$this->assertSame($step, $step->persist());
}
@@ -509,45 +484,38 @@ public function test_persist_non_dirty() {
/**
* Ensure that new dirty steps are persisted.
*/
- public function test_persist_dirty_new() {
+ public function test_persist_dirty_new(): void {
// Mock the database.
$DB = $this->mock_database();
$DB->expects($this->once())
->method('insert_record')
- ->willReturn(42)
- ;
+ ->willReturn(42);
// Mock the tour.
$step = $this->getMockBuilder(\tool_usertours\step::class)
->onlyMethods([
- 'to_record',
- 'calculate_sortorder',
- 'reload',
- ])
- ->getMock()
- ;
+ 'to_record',
+ 'calculate_sortorder',
+ 'reload',
+ ])
+ ->getMock();
$step->expects($this->once())
->method('to_record')
->willReturn((object)['id' => 42]);
- ;
$step->expects($this->once())
- ->method('calculate_sortorder')
- ;
+ ->method('calculate_sortorder');
$step->expects($this->once())
- ->method('reload')
- ;
+ ->method('reload');
$rc = new \ReflectionClass(\tool_usertours\step::class);
$rcp = $rc->getProperty('dirty');
- $rcp->setAccessible(true);
$rcp->setValue($step, true);
$tour = $this->createMock(\tool_usertours\tour::class);
$rcp = $rc->getProperty('tour');
- $rcp->setAccessible(true);
$rcp->setValue($step, $tour);
$this->assertSame($step, $step->persist());
@@ -556,43 +524,37 @@ public function test_persist_dirty_new() {
/**
* Ensure that new non-dirty, forced steps are persisted.
*/
- public function test_persist_force_new() {
+ public function test_persist_force_new(): void {
global $DB;
// Mock the database.
$DB = $this->mock_database();
$DB->expects($this->once())
->method('insert_record')
- ->willReturn(42)
- ;
+ ->willReturn(42);
// Mock the tour.
$step = $this->getMockBuilder(\tool_usertours\step::class)
->onlyMethods([
- 'to_record',
- 'calculate_sortorder',
- 'reload',
- ])
- ->getMock()
- ;
+ 'to_record',
+ 'calculate_sortorder',
+ 'reload',
+ ])
+ ->getMock();
$step->expects($this->once())
->method('to_record')
->willReturn((object)['id' => 42]);
- ;
$step->expects($this->once())
- ->method('calculate_sortorder')
- ;
+ ->method('calculate_sortorder');
$step->expects($this->once())
- ->method('reload')
- ;
+ ->method('reload');
$tour = $this->createMock(\tool_usertours\tour::class);
$rc = new \ReflectionClass(\tool_usertours\step::class);
$rcp = $rc->getProperty('tour');
- $rcp->setAccessible(true);
$rcp->setValue($step, $tour);
$this->assertSame($step, $step->persist(true));
@@ -601,48 +563,40 @@ public function test_persist_force_new() {
/**
* Ensure that existing dirty steps are persisted.
*/
- public function test_persist_dirty_existing() {
+ public function test_persist_dirty_existing(): void {
// Mock the database.
$DB = $this->mock_database();
$DB->expects($this->once())
- ->method('update_record')
- ;
+ ->method('update_record');
// Mock the tour.
$step = $this->getMockBuilder(\tool_usertours\step::class)
->onlyMethods([
- 'to_record',
- 'calculate_sortorder',
- 'reload',
- ])
- ->getMock()
- ;
+ 'to_record',
+ 'calculate_sortorder',
+ 'reload',
+ ])
+ ->getMock();
$step->expects($this->once())
->method('to_record')
->willReturn((object)['id' => 42]);
- ;
$step->expects($this->never())
- ->method('calculate_sortorder')
- ;
+ ->method('calculate_sortorder');
$step->expects($this->once())
- ->method('reload')
- ;
+ ->method('reload');
$rc = new \ReflectionClass(\tool_usertours\step::class);
$rcp = $rc->getProperty('id');
- $rcp->setAccessible(true);
$rcp->setValue($step, 42);
$rcp = $rc->getProperty('dirty');
- $rcp->setAccessible(true);
$rcp->setValue($step, true);
$tour = $this->createMock(\tool_usertours\tour::class);
$rcp = $rc->getProperty('tour');
- $rcp->setAccessible(true);
$rcp->setValue($step, $tour);
$this->assertSame($step, $step->persist());
@@ -651,46 +605,39 @@ public function test_persist_dirty_existing() {
/**
* Ensure that existing non-dirty, forced steps are persisted.
*/
- public function test_persist_force_existing() {
+ public function test_persist_force_existing(): void {
global $DB;
// Mock the database.
$DB = $this->mock_database();
$DB->expects($this->once())
- ->method('update_record')
- ;
+ ->method('update_record');
// Mock the tour.
$step = $this->getMockBuilder(\tool_usertours\step::class)
->onlyMethods([
- 'to_record',
- 'calculate_sortorder',
- 'reload',
- ])
- ->getMock()
- ;
+ 'to_record',
+ 'calculate_sortorder',
+ 'reload',
+ ])
+ ->getMock();
$step->expects($this->once())
->method('to_record')
- ->willReturn((object)['id' => 42]);
- ;
+ ->willReturn((object) ['id' => 42]);
$step->expects($this->never())
- ->method('calculate_sortorder')
- ;
+ ->method('calculate_sortorder');
$step->expects($this->once())
- ->method('reload')
- ;
+ ->method('reload');
$rc = new \ReflectionClass(\tool_usertours\step::class);
$rcp = $rc->getProperty('id');
- $rcp->setAccessible(true);
$rcp->setValue($step, 42);
$tour = $this->createMock(\tool_usertours\tour::class);
$rcp = $rc->getProperty('tour');
- $rcp->setAccessible(true);
$rcp->setValue($step, $tour);
$this->assertSame($step, $step->persist(true));
@@ -699,17 +646,15 @@ public function test_persist_force_existing() {
/**
* Check that a tour which has never been persisted is removed correctly.
*/
- public function test_remove_non_persisted() {
+ public function test_remove_non_persisted(): void {
$step = $this->getMockBuilder(\tool_usertours\step::class)
->onlyMethods([])
- ->getMock()
- ;
+ ->getMock();
// Mock the database.
$DB = $this->mock_database();
$DB->expects($this->never())
- ->method('delete_records')
- ;
+ ->method('delete_records');
$this->assertNull($step->remove());
}
@@ -717,42 +662,36 @@ public function test_remove_non_persisted() {
/**
* Check that a tour which has been persisted is removed correctly.
*/
- public function test_remove_persisted() {
+ public function test_remove_persisted(): void {
$id = rand(1, 100);
$tour = $this->getMockBuilder(\tool_usertours\tour::class)
->onlyMethods([
- 'reset_step_sortorder',
- ])
- ->getMock()
- ;
+ 'reset_step_sortorder',
+ ])
+ ->getMock();
$tour->expects($this->once())
- ->method('reset_step_sortorder')
- ;
+ ->method('reset_step_sortorder');
$step = $this->getMockBuilder(\tool_usertours\step::class)
->onlyMethods([
- 'get_tour',
- ])
- ->getMock()
- ;
+ 'get_tour',
+ ])
+ ->getMock();
$step->expects($this->once())
->method('get_tour')
- ->willReturn($tour)
- ;
+ ->willReturn($tour);
// Mock the database.
$DB = $this->mock_database();
$DB->expects($this->once())
->method('delete_records')
- ->with($this->equalTo('tool_usertours_steps'), $this->equalTo(['id' => $id]))
- ;
+ ->with($this->equalTo('tool_usertours_steps'), $this->equalTo(['id' => $id]));
$rc = new \ReflectionClass(\tool_usertours\step::class);
$rcp = $rc->getProperty('id');
- $rcp->setAccessible(true);
$rcp->setValue($step, $id);
$this->assertEquals($id, $step->get_id());
@@ -764,37 +703,37 @@ public function test_remove_persisted() {
*
* @return array
*/
- public function getter_provider() {
+ public static function getter_provider(): array {
return [
- 'id' => [
- 'id',
- rand(1, 100),
- ],
- 'tourid' => [
- 'tourid',
- rand(1, 100),
- ],
- 'title' => [
- 'title',
- 'Lorem',
- ],
- 'content' => [
- 'content',
- 'Lorem',
- ],
- 'targettype' => [
- 'targettype',
- 'Lorem',
- ],
- 'targetvalue' => [
- 'targetvalue',
- 'Lorem',
- ],
- 'sortorder' => [
- 'sortorder',
- rand(1, 100),
- ],
- ];
+ 'id' => [
+ 'id',
+ rand(1, 100),
+ ],
+ 'tourid' => [
+ 'tourid',
+ rand(1, 100),
+ ],
+ 'title' => [
+ 'title',
+ 'Lorem',
+ ],
+ 'content' => [
+ 'content',
+ 'Lorem',
+ ],
+ 'targettype' => [
+ 'targettype',
+ 'Lorem',
+ ],
+ 'targetvalue' => [
+ 'targetvalue',
+ 'Lorem',
+ ],
+ 'sortorder' => [
+ 'sortorder',
+ rand(1, 100),
+ ],
+ ];
}
/**
@@ -804,13 +743,12 @@ public function getter_provider() {
* @param string $key The key to test
* @param mixed $value The expected value
*/
- public function test_getters($key, $value) {
+ public function test_getters($key, $value): void {
$step = new \tool_usertours\step();
$rc = new \ReflectionClass(\tool_usertours\step::class);
$rcp = $rc->getProperty($key);
- $rcp->setAccessible(true);
$rcp->setValue($step, $value);
$getter = 'get_' . $key;
@@ -821,7 +759,7 @@ public function test_getters($key, $value) {
/**
* Ensure that the get_step_image_from_input function replace PIXICON placeholder with the correct images correctly.
*/
- public function test_get_step_image_from_input() {
+ public function test_get_step_image_from_input(): void {
// Test step content with single image.
$stepcontent = '@@PIXICON::tour/tour_mycourses::tool_usertours@@ Test';
$stepcontent = \tool_usertours\step::get_step_image_from_input($stepcontent);
@@ -832,7 +770,8 @@ public function test_get_step_image_from_input() {
$this->assertStringNotContainsString('PIXICON', $stepcontent);
// Test step content with multiple images.
- $stepcontent = '@@PIXICON::tour/tour_mycourses::tool_usertours@@ Test @@PIXICON::tour/tour_myhomepage::tool_usertours@@';
+ $stepcontent =
+ '@@PIXICON::tour/tour_mycourses::tool_usertours@@ Test @@PIXICON::tour/tour_myhomepage::tool_usertours@@';
$stepcontent = \tool_usertours\step::get_step_image_from_input($stepcontent);
// If the format is correct, PIXICON placeholder will be replaced with the img tag.
$this->assertStringStartsWith('
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @covers \tool_usertours\local\filter\theme
*/
class theme_filter_test extends \advanced_testcase {
-
/**
* Data Provider for filter_matches function.
*
* @return array
*/
- public function filter_matches_provider() {
+ public static function filter_matches_provider(): array {
return [
'No config set; Matches' => [
null,
@@ -73,7 +73,7 @@ public function filter_matches_provider() {
* @param string $currenttheme The name of the current theme
* @param boolean $expected Whether the tour is expected to match
*/
- public function test_filter_matches($filtervalues, $currenttheme, $expected) {
+ public function test_filter_matches($filtervalues, $currenttheme, $expected): void {
global $PAGE;
$filtername = \tool_usertours\local\filter\theme::class;
diff --git a/admin/tool/usertours/tests/tour_test.php b/admin/tool/usertours/tests/tour_test.php
index f7955dd94e45..e32df99a1f81 100644
--- a/admin/tool/usertours/tests/tour_test.php
+++ b/admin/tool/usertours/tests/tour_test.php
@@ -16,25 +16,25 @@
namespace tool_usertours;
-defined('MOODLE_INTERNAL') || die();
-
-global $CFG;
-require_once($CFG->libdir . '/formslib.php');
-
/**
* Tests for tour.
*
* @package tool_usertours
* @copyright 2016 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @covers \tool_usertours\tour
*/
class tour_test extends \advanced_testcase {
-
/**
* @var moodle_database
*/
protected $db;
+ public static function setUpBeforeClass(): void {
+ global $CFG;
+ require_once($CFG->libdir . '/formslib.php');
+ }
+
/**
* Setup to store the DB reference.
*/
@@ -62,8 +62,7 @@ public function mock_database() {
global $DB;
$DB = $this->getMockBuilder(\moodle_database::class)
- ->getMock()
- ;
+ ->getMock();
return $DB;
}
@@ -73,33 +72,37 @@ public function mock_database() {
*
* @return array
*/
- public function dirty_value_provider() {
+ public static function dirty_value_provider(): array {
return [
- 'name' => [
- 'name',
- ['Lorem'],
- ],
- 'description' => [
- 'description',
- ['Lorem'],
- ],
- 'pathmatch' => [
- 'pathmatch',
- ['Lorem'],
- ],
- 'enabled' => [
- 'enabled',
- ['Lorem'],
- ],
- 'sortorder' => [
- 'sortorder',
- [1],
- ],
- 'config' => [
- 'config',
- ['key', 'value'],
- ],
- ];
+ 'name' => [
+ 'name',
+ ['Lorem'],
+ ],
+ 'description' => [
+ 'description',
+ ['Lorem'],
+ ],
+ 'pathmatch' => [
+ 'pathmatch',
+ ['Lorem'],
+ ],
+ 'enabled' => [
+ 'enabled',
+ ['Lorem'],
+ ],
+ 'sortorder' => [
+ 'sortorder',
+ [1],
+ ],
+ 'config' => [
+ 'config',
+ ['key', 'value'],
+ ],
+ 'showtourwhen' => [
+ 'showtourwhen',
+ [0],
+ ],
+ ];
}
/**
@@ -109,14 +112,13 @@ public function dirty_value_provider() {
* @param string $name The name of the key being tested
* @param mixed $value The value being set
*/
- public function test_dirty_values($name, $value) {
+ public function test_dirty_values($name, $value): void {
$tour = new \tool_usertours\tour();
$method = 'set_' . $name;
call_user_func_array([$tour, $method], $value);
$rc = new \ReflectionClass(\tool_usertours\tour::class);
$rcp = $rc->getProperty('dirty');
- $rcp->setAccessible(true);
$this->assertTrue($rcp->getValue($tour));
}
@@ -126,37 +128,37 @@ public function test_dirty_values($name, $value) {
*
* @return array
*/
- public function getter_provider() {
+ public static function getter_provider(): array {
return [
- 'id' => [
- 'id',
- rand(1, 100),
- ],
- 'name' => [
- 'name',
- 'Lorem',
- ],
- 'description' => [
- 'description',
- 'Lorem',
- ],
- 'pathmatch' => [
- 'pathmatch',
- 'Lorem',
- ],
- 'enabled' => [
- 'enabled',
- 'Lorem',
- ],
- 'sortorder' => [
- 'sortorder',
- rand(1, 100),
- ],
- 'config' => [
- 'config',
- ['key', 'value'],
- ],
- ];
+ 'id' => [
+ 'id',
+ rand(1, 100),
+ ],
+ 'name' => [
+ 'name',
+ 'Lorem',
+ ],
+ 'description' => [
+ 'description',
+ 'Lorem',
+ ],
+ 'pathmatch' => [
+ 'pathmatch',
+ 'Lorem',
+ ],
+ 'enabled' => [
+ 'enabled',
+ 'Lorem',
+ ],
+ 'sortorder' => [
+ 'sortorder',
+ rand(1, 100),
+ ],
+ 'config' => [
+ 'config',
+ ['key', 'value'],
+ ],
+ ];
}
/**
@@ -166,13 +168,12 @@ public function getter_provider() {
* @param string $key The name of the key being tested
* @param mixed $value The value being set
*/
- public function test_getters($key, $value) {
+ public function test_getters($key, $value): void {
$tour = new \tool_usertours\tour();
$rc = new \ReflectionClass(tour::class);
$rcp = $rc->getProperty($key);
- $rcp->setAccessible(true);
$rcp->setValue($tour, $value);
$getter = 'get_' . $key;
@@ -183,15 +184,13 @@ public function test_getters($key, $value) {
/**
* Ensure that non-dirty tours are not persisted.
*/
- public function test_persist_non_dirty() {
+ public function test_persist_non_dirty(): void {
$tour = $this->getMockBuilder(tour::class)
->onlyMethods(['to_record'])
- ->getMock()
- ;
+ ->getMock();
$tour->expects($this->never())
- ->method('to_record')
- ;
+ ->method('to_record');
$this->assertSame($tour, $tour->persist());
}
@@ -199,134 +198,114 @@ public function test_persist_non_dirty() {
/**
* Ensure that new dirty tours are persisted.
*/
- public function test_persist_dirty_new() {
+ public function test_persist_dirty_new(): void {
// Mock the database.
$DB = $this->mock_database();
$DB->expects($this->never())
- ->method('update_record')
- ;
+ ->method('update_record');
$id = rand(1, 100);
$DB->expects($this->once())
->method('insert_record')
- ->willReturn($id)
- ;
+ ->willReturn($id);
// Mock the tour.
$tour = $this->getMockBuilder(tour::class)
->onlyMethods([
- 'to_record',
- 'reload',
- ])
- ->getMock()
- ;
+ 'to_record',
+ 'reload',
+ ])
+ ->getMock();
$tour->expects($this->once())
- ->method('to_record')
- ;
+ ->method('to_record');
$tour->expects($this->once())
- ->method('reload')
- ;
+ ->method('reload');
$rc = new \ReflectionClass(tour::class);
$rcp = $rc->getProperty('dirty');
- $rcp->setAccessible(true);
$rcp->setValue($tour, true);
$this->assertSame($tour, $tour->persist());
$rcp = $rc->getProperty('id');
- $rcp->setAccessible(true);
$this->assertEquals($id, $rcp->getValue($tour));
}
/**
* Ensure that non-dirty, forced tours are persisted.
*/
- public function test_persist_force_new() {
+ public function test_persist_force_new(): void {
global $DB;
// Mock the database.
$DB = $this->mock_database();
$DB->expects($this->never())
- ->method('update_record')
- ;
+ ->method('update_record');
$id = rand(1, 100);
$DB->expects($this->once())
->method('insert_record')
- ->willReturn($id)
- ;
+ ->willReturn($id);
// Mock the tour.
$tour = $this->getMockBuilder(tour::class)
->onlyMethods([
- 'to_record',
- 'reload',
- ])
- ->getMock()
- ;
+ 'to_record',
+ 'reload',
+ ])
+ ->getMock();
$tour->expects($this->once())
- ->method('to_record')
- ;
+ ->method('to_record');
$tour->expects($this->once())
- ->method('reload')
- ;
+ ->method('reload');
$this->assertSame($tour, $tour->persist(true));
$rc = new \ReflectionClass(tour::class);
$rcp = $rc->getProperty('id');
- $rcp->setAccessible(true);
$this->assertEquals($id, $rcp->getValue($tour));
}
/**
* Ensure that dirty tours are persisted.
*/
- public function test_persist_dirty_existing() {
+ public function test_persist_dirty_existing(): void {
// Mock the database.
$DB = $this->mock_database();
$DB->expects($this->once())
->method('update_record')
- ->willReturn($this->returnSelf())
- ;
+ ->willReturn($this->returnSelf());
$DB->expects($this->never())
- ->method('insert_record')
- ;
+ ->method('insert_record');
// Mock the tour.
$tour = $this->getMockBuilder(tour::class)
->onlyMethods([
- 'to_record',
- 'reload',
- ])
- ->getMock()
- ;
+ 'to_record',
+ 'reload',
+ ])
+ ->getMock();
$tour->expects($this->once())
- ->method('to_record')
- ;
+ ->method('to_record');
$tour->expects($this->once())
- ->method('reload')
- ;
+ ->method('reload');
$rc = new \ReflectionClass(tour::class);
$rcp = $rc->getProperty('id');
- $rcp->setAccessible(true);
$rcp->setValue($tour, 42);
$rcp = $rc->getProperty('dirty');
- $rcp->setAccessible(true);
$rcp->setValue($tour, true);
$this->assertSame($tour, $tour->persist());
@@ -335,7 +314,7 @@ public function test_persist_dirty_existing() {
/**
* Ensure that non-dirty, forced tours are persisted.
*/
- public function test_persist_force() {
+ public function test_persist_force(): void {
global $DB;
// Mock the database.
@@ -343,38 +322,31 @@ public function test_persist_force() {
$DB->expects($this->once())
->method('update_record')
- ->willReturn($this->returnSelf())
- ;
+ ->willReturn($this->returnSelf());
$DB->expects($this->never())
- ->method('insert_record')
- ;
+ ->method('insert_record');
// Mock the tour.
$tour = $this->getMockBuilder(tour::class)
->onlyMethods([
- 'to_record',
- 'reload',
- ])
- ->getMock()
- ;
+ 'to_record',
+ 'reload',
+ ])
+ ->getMock();
$tour->expects($this->once())
- ->method('to_record')
- ;
+ ->method('to_record');
$tour->expects($this->once())
- ->method('reload')
- ;
+ ->method('reload');
$rc = new \ReflectionClass(tour::class);
$rcp = $rc->getProperty('id');
- $rcp->setAccessible(true);
$rcp->setValue($tour, 42);
$rcp = $rc->getProperty('dirty');
- $rcp->setAccessible(true);
$rcp->setValue($tour, true);
$this->assertSame($tour, $tour->persist(true));
@@ -383,42 +355,40 @@ public function test_persist_force() {
/**
* Test setting config.
*/
- public function test_set_config() {
+ public function test_set_config(): void {
$tour = new \tool_usertours\tour();
$tour->set_config('key', 'value');
$tour->set_config('another', [
- 'foo' => 'bar',
- ]);
+ 'foo' => 'bar',
+ ]);
$rc = new \ReflectionClass(tour::class);
$rcp = $rc->getProperty('config');
- $rcp->setAccessible(true);
$this->assertEquals((object) [
- 'key' => 'value',
- 'another' => [
- 'foo' => 'bar',
- ],
- ], $rcp->getValue($tour));
+ 'key' => 'value',
+ 'another' => [
+ 'foo' => 'bar',
+ ],
+ ], $rcp->getValue($tour));
}
/**
* Test get_config with no keys provided.
*/
- public function test_get_config_no_keys() {
+ public function test_get_config_no_keys(): void {
$tour = new \tool_usertours\tour();
$rc = new \ReflectionClass(tour::class);
$rcp = $rc->getProperty('config');
- $rcp->setAccessible(true);
$allvalues = (object) [
- 'some' => 'value',
- 'another' => 42,
- 'key' => [
- 'somethingelse',
- ],
- ];
+ 'some' => 'value',
+ 'another' => 42,
+ 'key' => [
+ 'somethingelse',
+ ],
+ ];
$rcp->setValue($tour, $allvalues);
@@ -430,59 +400,59 @@ public function test_get_config_no_keys() {
*
* @return array
*/
- public function get_config_provider() {
+ public static function get_config_provider(): array {
$allvalues = (object) [
- 'some' => 'value',
- 'another' => 42,
- 'key' => [
- 'somethingelse',
- ],
- ];
+ 'some' => 'value',
+ 'another' => 42,
+ 'key' => [
+ 'somethingelse',
+ ],
+ ];
return [
- 'No nitial config' => [
- null,
- null,
- null,
- (object) [],
- ],
- 'All values' => [
- $allvalues,
- null,
- null,
- $allvalues,
- ],
- 'Valid string value' => [
- $allvalues,
- 'some',
- null,
- 'value',
- ],
- 'Valid array value' => [
- $allvalues,
- 'key',
- null,
- ['somethingelse'],
- ],
- 'Invalid value' => [
- $allvalues,
- 'notavalue',
- null,
- null,
- ],
- 'Configuration value' => [
- $allvalues,
- 'placement',
- null,
- \tool_usertours\configuration::get_default_value('placement'),
- ],
- 'Invalid value with default' => [
- $allvalues,
- 'notavalue',
- 'somedefault',
- 'somedefault',
- ],
- ];
+ 'No nitial config' => [
+ null,
+ null,
+ null,
+ (object) [],
+ ],
+ 'All values' => [
+ $allvalues,
+ null,
+ null,
+ $allvalues,
+ ],
+ 'Valid string value' => [
+ $allvalues,
+ 'some',
+ null,
+ 'value',
+ ],
+ 'Valid array value' => [
+ $allvalues,
+ 'key',
+ null,
+ ['somethingelse'],
+ ],
+ 'Invalid value' => [
+ $allvalues,
+ 'notavalue',
+ null,
+ null,
+ ],
+ 'Configuration value' => [
+ $allvalues,
+ 'placement',
+ null,
+ \tool_usertours\configuration::get_default_value('placement'),
+ ],
+ 'Invalid value with default' => [
+ $allvalues,
+ 'notavalue',
+ 'somedefault',
+ 'somedefault',
+ ],
+ ];
}
/**
@@ -494,12 +464,11 @@ public function get_config_provider() {
* @param mixed $default The default value
* @param mixed $expected The expected value
*/
- public function test_get_config_valid_keys($values, $key, $default, $expected) {
+ public function test_get_config_valid_keys($values, $key, $default, $expected): void {
$tour = new \tool_usertours\tour();
$rc = new \ReflectionClass(tour::class);
$rcp = $rc->getProperty('config');
- $rcp->setAccessible(true);
$rcp->setValue($tour, $values);
$this->assertEquals($expected, $tour->get_config($key, $default));
@@ -508,23 +477,20 @@ public function test_get_config_valid_keys($values, $key, $default, $expected) {
/**
* Check that a tour which has never been persisted is removed correctly.
*/
- public function test_remove_non_persisted() {
+ public function test_remove_non_persisted(): void {
$tour = $this->getMockBuilder(tour::class)
->onlyMethods([
- 'get_steps',
- ])
- ->getMock()
- ;
+ 'get_steps',
+ ])
+ ->getMock();
$tour->expects($this->never())
- ->method('get_steps')
- ;
+ ->method('get_steps');
// Mock the database.
$DB = $this->mock_database();
$DB->expects($this->never())
- ->method('delete_records')
- ;
+ ->method('delete_records');
$this->assertNull($tour->remove());
}
@@ -532,32 +498,28 @@ public function test_remove_non_persisted() {
/**
* Check that a tour which has been persisted is removed correctly.
*/
- public function test_remove_persisted() {
+ public function test_remove_persisted(): void {
$id = rand(1, 100);
$tour = $this->getMockBuilder(tour::class)
->onlyMethods([
- 'get_steps',
- ])
- ->getMock()
- ;
+ 'get_steps',
+ ])
+ ->getMock();
$rc = new \ReflectionClass(tour::class);
$rcp = $rc->getProperty('id');
- $rcp->setAccessible(true);
$rcp->setValue($tour, $id);
$step = $this->getMockBuilder(\tool_usertours\step::class)
->onlyMethods([
- 'remove',
- ])
- ->getMock()
- ;
+ 'remove',
+ ])
+ ->getMock();
$tour->expects($this->once())
->method('get_steps')
- ->willReturn([$step])
- ;
+ ->willReturn([$step]);
// Mock the database.
$DB = $this->mock_database();
@@ -569,14 +531,12 @@ public function test_remove_persisted() {
[$this->equalTo('user_preferences'), $this->equalTo(['name' => tour::TOUR_LAST_COMPLETED_BY_USER . $id])],
[$this->equalTo('user_preferences'), $this->equalTo(['name' => tour::TOUR_REQUESTED_BY_USER . $id])]
)
- ->willReturn(null)
- ;
+ ->willReturn(null);
$DB->expects($this->once())
->method('get_records')
->with($this->equalTo('tool_usertours_tours'), $this->equalTo(null))
- ->willReturn([])
- ;
+ ->willReturn([]);
$this->assertNull($tour->remove());
}
@@ -584,7 +544,7 @@ public function test_remove_persisted() {
/**
* Teset that sortorder is reset according to sortorder with values from 0.
*/
- public function test_reset_step_sortorder() {
+ public function test_reset_step_sortorder(): void {
$tour = new \tool_usertours\tour();
$mockdata = [];
@@ -598,12 +558,10 @@ public function test_reset_step_sortorder() {
$DB = $this->mock_database();
$DB->expects($this->once())
->method('get_records')
- ->willReturn($mockdata)
- ;
+ ->willReturn($mockdata);
$setfield = $DB->expects($this->exactly(5))
- ->method('set_field')
- ;
+ ->method('set_field');
call_user_func_array([$setfield, 'withConsecutive'], $expectations);
$tour->reset_step_sortorder();
@@ -612,7 +570,7 @@ public function test_reset_step_sortorder() {
/**
* Test that a disabled tour should never be shown to users.
*/
- public function test_should_show_for_user_disabled() {
+ public function test_should_show_for_user_disabled(): void {
$tour = new \tool_usertours\tour();
$tour->set_enabled(false);
@@ -624,40 +582,54 @@ public function test_should_show_for_user_disabled() {
*
* @return array
*/
- public function should_show_for_user_provider() {
+ public static function should_show_for_user_provider(): array {
$time = time();
return [
- 'Not seen by user at all' => [
- null,
- null,
- null,
- true,
- ],
- 'Completed by user before majorupdatetime' => [
- $time - DAYSECS,
- null,
- $time,
- true,
- ],
- 'Completed by user since majorupdatetime' => [
- $time,
- null,
- $time - DAYSECS,
- false,
- ],
- 'Requested by user before current completion' => [
- $time,
- $time - DAYSECS,
- null,
- false,
- ],
- 'Requested by user since completion' => [
- $time - DAYSECS,
- $time,
- null,
- true,
- ],
- ];
+ 'Not seen by user at all' => [
+ null,
+ null,
+ null,
+ [],
+ true,
+ ],
+ 'Completed by user before majorupdatetime' => [
+ $time - DAYSECS,
+ null,
+ $time,
+ [],
+ true,
+ ],
+ 'Completed by user since majorupdatetime' => [
+ $time,
+ null,
+ $time - DAYSECS,
+ [],
+ false,
+ ],
+ 'Requested by user before current completion' => [
+ $time,
+ $time - DAYSECS,
+ $time - MINSECS,
+ [],
+ false,
+ ],
+ 'Requested by user since completion' => [
+ $time - DAYSECS,
+ $time,
+ 'null',
+ [],
+ true,
+ ],
+ 'Tour will show on each load' => [
+ $time,
+ $time - DAYSECS,
+ null,
+ [
+ 'showtourwhen' => tour::SHOW_TOUR_ON_EACH_PAGE_VISIT,
+ ],
+ true,
+ ],
+ ];
}
/**
@@ -667,30 +639,37 @@ public function should_show_for_user_provider() {
* @param mixed $completiondate The user's completion date for this tour
* @param mixed $requesteddate The user's last requested date for this tour
* @param mixed $updateddate The date this tour was last updated
+ * @param mixed $config The tour config to apply
* @param string $expectation The expected tour key
*/
- public function test_should_show_for_user($completiondate, $requesteddate, $updateddate, $expectation) {
+ public function test_should_show_for_user(
+ $completiondate,
+ $requesteddate,
+ $updateddate,
+ $config,
+ $expectation,
+ ): void {
// Uses user preferences so we must be in a user context.
$this->resetAfterTest();
$this->setAdminUser();
$tour = $this->getMockBuilder(tour::class)
->onlyMethods([
- 'get_id',
- 'get_config',
- 'is_enabled',
- ])
- ->getMock()
- ;
+ 'get_id',
+ 'is_enabled',
+ ])
+ ->getMock();
$tour->method('is_enabled')
- ->willReturn(true)
- ;
+ ->willReturn(true);
+
+ foreach ($config as $key => $value) {
+ $tour->set_config($key, $value);
+ }
$id = rand(1, 100);
$tour->method('get_id')
- ->willReturn($id)
- ;
+ ->willReturn($id);
if ($completiondate !== null) {
set_user_preference(\tool_usertours\tour::TOUR_LAST_COMPLETED_BY_USER . $id, $completiondate);
@@ -701,10 +680,7 @@ public function test_should_show_for_user($completiondate, $requesteddate, $upda
}
if ($updateddate !== null) {
- $tour->expects($this->once())
- ->method('get_config')
- ->willReturn($updateddate)
- ;
+ $tour->set_config('majorupdatetime', $updateddate);
}
$this->assertEquals($expectation, $tour->should_show_for_user());
@@ -715,44 +691,47 @@ public function test_should_show_for_user($completiondate, $requesteddate, $upda
*
* @return array
*/
- public function get_tour_key_provider() {
+ public static function get_tour_key_provider(): array {
$id = rand(1, 100);
$time = time();
return [
'No initial values' => [
- $id,
- [null, $time],
- $this->greaterThanOrEqual($time),
- true,
- null,
- sprintf('tool_usertours_\d_%d_%s', $id, $time),
- ],
+ $id,
+ [null, $time],
+ static::logicalOr(
+ new \PHPUnit\Framework\Constraint\IsEqual($time),
+ new \PHPUnit\Framework\Constraint\GreaterThan($time),
+ ),
+ true,
+ null,
+ sprintf('tool_usertours_\d_%d_%s', $id, $time),
+ ],
'Initial tour time, no user pref' => [
- $id,
- [$time],
- null,
- false,
- null,
- sprintf('tool_usertours_\d_%d_%s', $id, $time),
- ],
+ $id,
+ [$time],
+ null,
+ false,
+ null,
+ sprintf('tool_usertours_\d_%d_%s', $id, $time),
+ ],
'Initial tour time, with user reset lower' => [
- $id,
- [$time],
- null,
- false,
- $time - DAYSECS,
- sprintf('tool_usertours_\d_%d_%s', $id, $time),
- ],
+ $id,
+ [$time],
+ null,
+ false,
+ $time - DAYSECS,
+ sprintf('tool_usertours_\d_%d_%s', $id, $time),
+ ],
'Initial tour time, with user reset higher' => [
- $id,
- [$time],
- null,
- false,
- $time + DAYSECS,
- sprintf('tool_usertours_\d_%d_%s', $id, $time + DAYSECS),
- ],
+ $id,
+ [$time],
+ null,
+ false,
+ $time + DAYSECS,
+ sprintf('tool_usertours_\d_%d_%s', $id, $time + DAYSECS),
+ ],
];
}
@@ -767,83 +746,74 @@ public function get_tour_key_provider() {
* @param mixed $userpref The value to set for the user preference
* @param string $expectation The expected tour key
*/
- public function test_get_tour_key($id, $getconfig, $setconfig, $willpersist, $userpref, $expectation) {
+ public function test_get_tour_key($id, $getconfig, $setconfig, $willpersist, $userpref, $expectation): void {
// Uses user preferences so we must be in a user context.
$this->resetAfterTest();
$this->setAdminUser();
$tour = $this->getMockBuilder(tour::class)
->onlyMethods([
- 'get_config',
- 'set_config',
- 'get_id',
- 'persist',
- ])
- ->getMock()
- ;
+ 'get_config',
+ 'set_config',
+ 'get_id',
+ 'persist',
+ ])
+ ->getMock();
if ($getconfig) {
$tour->expects($this->exactly(count($getconfig)))
->method('get_config')
- ->will(call_user_func_array([$this, 'onConsecutiveCalls'], $getconfig))
- ;
+ ->will(call_user_func_array([$this, 'onConsecutiveCalls'], $getconfig));
}
if ($setconfig) {
$tour->expects($this->once())
->method('set_config')
->with($this->equalTo('majorupdatetime'), $setconfig)
- ->will($this->returnSelf())
- ;
+ ->will($this->returnSelf());
} else {
$tour->expects($this->never())
- ->method('set_config')
- ;
+ ->method('set_config');
}
if ($willpersist) {
$tour->expects($this->once())
- ->method('persist')
- ;
+ ->method('persist');
} else {
$tour->expects($this->never())
- ->method('persist')
- ;
+ ->method('persist');
}
$tour->expects($this->any())
->method('get_id')
- ->willReturn($id)
- ;
+ ->willReturn($id);
if ($userpref !== null) {
set_user_preference(\tool_usertours\tour::TOUR_REQUESTED_BY_USER . $id, $userpref);
}
$this->assertMatchesRegularExpression(
- '/' . $expectation . '/',
- $tour->get_tour_key()
- );
+ '/' . $expectation . '/',
+ $tour->get_tour_key()
+ );
}
/**
* Ensure that the request_user_reset function sets an appropriate value for the tour.
*/
- public function test_requested_user_reset() {
+ public function test_requested_user_reset(): void {
$tour = $this->getMockBuilder(tour::class)
->onlyMethods([
- 'get_id',
- ])
- ->getMock()
- ;
+ 'get_id',
+ ])
+ ->getMock();
$id = rand(1, 100);
$time = time();
$tour->expects($this->once())
->method('get_id')
- ->willReturn($id)
- ;
+ ->willReturn($id);
$tour->request_user_reset();
@@ -853,21 +823,19 @@ public function test_requested_user_reset() {
/**
* Ensure that the request_user_reset function sets an appropriate value for the tour.
*/
- public function test_mark_user_completed() {
+ public function test_mark_user_completed(): void {
$tour = $this->getMockBuilder(tour::class)
->onlyMethods([
- 'get_id',
- ])
- ->getMock()
- ;
+ 'get_id',
+ ])
+ ->getMock();
$id = rand(1, 100);
$time = time();
$tour->expects($this->once())
->method('get_id')
- ->willReturn($id)
- ;
+ ->willReturn($id);
$tour->mark_user_completed();
@@ -879,34 +847,34 @@ public function test_mark_user_completed() {
*
* @return array
*/
- public function sortorder_first_last_provider() {
+ public static function sortorder_first_last_provider(): array {
$topcount = rand(10, 100);
return [
- 'Only tour => first + last' => [
- 0,
- true,
- 1,
- true,
- ],
- 'First tour of many' => [
- 0,
- true,
- $topcount,
- false,
- ],
- 'Last tour of many' => [
- $topcount - 1,
- false,
- $topcount,
- true,
- ],
- 'Middle tour of many' => [
- 5,
- false,
- $topcount,
- false,
- ],
- ];
+ 'Only tour => first + last' => [
+ 0,
+ true,
+ 1,
+ true,
+ ],
+ 'First tour of many' => [
+ 0,
+ true,
+ $topcount,
+ false,
+ ],
+ 'Last tour of many' => [
+ $topcount - 1,
+ false,
+ $topcount,
+ true,
+ ],
+ 'Middle tour of many' => [
+ 5,
+ false,
+ $topcount,
+ false,
+ ],
+ ];
}
/**
@@ -918,12 +886,11 @@ public function sortorder_first_last_provider() {
* @param int $total The number of tours
* @param bool $islast Whether this is the last tour
*/
- public function test_is_first_tour($sortorder, $isfirst, $total, $islast) {
+ public function test_is_first_tour($sortorder, $isfirst, $total, $islast): void {
$tour = new \tool_usertours\tour();
$rc = new \ReflectionClass(tour::class);
$rcp = $rc->getProperty('sortorder');
- $rcp->setAccessible(true);
$rcp->setValue($tour, $sortorder);
$this->assertEquals($isfirst, $tour->is_first_tour());
@@ -938,20 +905,18 @@ public function test_is_first_tour($sortorder, $isfirst, $total, $islast) {
* @param int $total The number of tours
* @param bool $islast Whether this is the last tour
*/
- public function test_is_last_tour_calculated($sortorder, $isfirst, $total, $islast) {
+ public function test_is_last_tour_calculated($sortorder, $isfirst, $total, $islast): void {
$tour = new \tool_usertours\tour();
$rc = new \ReflectionClass(tour::class);
$rcp = $rc->getProperty('sortorder');
- $rcp->setAccessible(true);
$rcp->setValue($tour, $sortorder);
// The total will be calculated.
$DB = $this->mock_database();
$DB->expects($this->once())
->method('count_records')
- ->willReturn($total)
- ;
+ ->willReturn($total);
$this->assertEquals($islast, $tour->is_last_tour());
}
@@ -964,12 +929,11 @@ public function test_is_last_tour_calculated($sortorder, $isfirst, $total, $isla
* @param int $total The number of tours
* @param bool $islast Whether this is the last tour
*/
- public function test_is_last_tour_provided($sortorder, $isfirst, $total, $islast) {
+ public function test_is_last_tour_provided($sortorder, $isfirst, $total, $islast): void {
$tour = new \tool_usertours\tour();
$rc = new \ReflectionClass(tour::class);
$rcp = $rc->getProperty('sortorder');
- $rcp->setAccessible(true);
$rcp->setValue($tour, $sortorder);
// The total is provided.
@@ -977,8 +941,7 @@ public function test_is_last_tour_provided($sortorder, $isfirst, $total, $islast
$DB = $this->mock_database();
$DB->expects($this->never())
->method('count_records')
- ->willReturn(0)
- ;
+ ->willReturn(0);
$this->assertEquals($islast, $tour->is_last_tour($total));
}
@@ -987,7 +950,7 @@ public function test_is_last_tour_provided($sortorder, $isfirst, $total, $islast
*
* @return array
*/
- public function get_filter_values_provider() {
+ public static function get_filter_values_provider(): array {
$cheese = ['cheddar', 'boursin', 'mozzarella'];
$horses = ['coolie', 'dakota', 'leo', 'twiggy'];
return [
@@ -1013,7 +976,7 @@ public function get_filter_values_provider() {
'Some config for several filters' => [
[
'horses' => $horses,
- 'cheese' => $cheese
+ 'cheese' => $cheese,
],
'horses',
$horses,
@@ -1029,7 +992,7 @@ public function get_filter_values_provider() {
* @param string $filtername The name of the filter being tested
* @param array $expectedvalues The expected result
*/
- public function test_get_filter_values($fullconfig, $filtername, $expectedvalues) {
+ public function test_get_filter_values($fullconfig, $filtername, $expectedvalues): void {
$tour = $this->getMockBuilder(tour::class)
->onlyMethods(['get_config'])
->getMock();
@@ -1046,7 +1009,7 @@ public function test_get_filter_values($fullconfig, $filtername, $expectedvalues
*
* @return array
*/
- public function set_filter_values_provider() {
+ public static function set_filter_values_provider(): array {
$cheese = ['cheddar', 'boursin', 'mozzarella'];
$horses = ['coolie', 'dakota', 'leo', 'twiggy'];
@@ -1087,7 +1050,7 @@ public function set_filter_values_provider() {
* @param array $newvalues The new values to store
* @param array $expectedvalues The combined values
*/
- public function test_set_filter_values_merge($currentvalues, $filtername, $newvalues, $expectedvalues) {
+ public function test_set_filter_values_merge($currentvalues, $filtername, $newvalues, $expectedvalues): void {
$tour = $this->getMockBuilder(tour::class)
->onlyMethods(['get_config', 'set_config'])
->getMock();
diff --git a/analytics/tests/community_of_inquiry_activities_completed_by.php b/analytics/tests/community_of_inquiry_activities_completed_by.php
index cb76f02d8dbf..c8b4df5fa4db 100644
--- a/analytics/tests/community_of_inquiry_activities_completed_by.php
+++ b/analytics/tests/community_of_inquiry_activities_completed_by.php
@@ -78,7 +78,6 @@ public function test_get_activities_with_availability($availabilitylevel) {
));
$method = new ReflectionMethod($availabilityinfo, 'set_in_database');
- $method->setAccessible(true);
$method->invoke($availabilityinfo, json_encode($structure));
$this->setUser($stu1);
@@ -339,11 +338,9 @@ private function instantiate_indicator($modulename, \core_analytics\course $cour
$class = new ReflectionClass($indicator);
$property = $class->getProperty('course');
- $property->setAccessible(true);
$property->setValue($indicator, $course);
$method = new ReflectionMethod($indicator, 'get_activities');
- $method->setAccessible(true);
return array($indicator, $method);
}
diff --git a/analytics/tests/model_test.php b/analytics/tests/model_test.php
index 884ef3e610d1..b2a621379a0b 100644
--- a/analytics/tests/model_test.php
+++ b/analytics/tests/model_test.php
@@ -427,7 +427,6 @@ public function test_export_config() {
$modelconfig = new \core_analytics\model_config($this->model);
$method = new \ReflectionMethod('\\core_analytics\\model_config', 'export_model_data');
- $method->setAccessible(true);
$modeldata = $method->invoke($modelconfig);
diff --git a/auth/classes/output/login.php b/auth/classes/output/login.php
index 3800cb72ecc2..6854234c0d4b 100644
--- a/auth/classes/output/login.php
+++ b/auth/classes/output/login.php
@@ -75,6 +75,10 @@ class login implements renderable, templatable {
public $maintenance;
/** @var string ReCaptcha element HTML. */
public $recaptcha;
+ /** @var bool Toggle the password visibility icon. */
+ public $togglepassword;
+ /** @var bool Toggle the password visibility icon for small screens only. */
+ public $smallscreensonly;
/**
* Constructor.
@@ -130,6 +134,11 @@ public function __construct(array $authsequence, $username = '') {
require_once($CFG->libdir . '/recaptchalib_v2.php');
$this->recaptcha = recaptcha_get_challenge_html(RECAPTCHA_API_URL, $CFG->recaptchapublickey);
}
+
+ // Toggle password visibility icon.
+ $this->togglepassword = get_config('core', 'loginpasswordtoggle') == TOGGLE_SENSITIVE_ENABLED ||
+ get_config('core', 'loginpasswordtoggle') == TOGGLE_SENSITIVE_SMALL_SCREENS_ONLY;
+ $this->smallscreensonly = get_config('core', 'loginpasswordtoggle') == TOGGLE_SENSITIVE_SMALL_SCREENS_ONLY;
}
/**
@@ -175,6 +184,8 @@ public function export_for_template(renderer_base $output) {
$data->maintenance = format_text($this->maintenance, FORMAT_MOODLE);
$data->languagemenu = $this->languagemenu;
$data->recaptcha = $this->recaptcha;
+ $data->togglepassword = $this->togglepassword;
+ $data->smallscreensonly = $this->smallscreensonly;
return $data;
}
diff --git a/auth/tests/behat/loginform.feature b/auth/tests/behat/loginform.feature
index a87301d421a7..cc4c01338e7c 100644
--- a/auth/tests/behat/loginform.feature
+++ b/auth/tests/behat/loginform.feature
@@ -101,3 +101,21 @@ Feature: Test if the login form provides the correct feedback
And I press "Log in"
And I press the tab key
Then the focused element is "Username" "field"
+
+ Scenario: Display the password visibility toggle icon
+ Given the following config values are set as admin:
+ | loginpasswordtoggle | 1 |
+ When I follow "Log in"
+ Then "Toggle sensitive" "button" should be visible
+ And the following config values are set as admin:
+ | loginpasswordtoggle | 0 |
+ And I reload the page
+ And "Toggle sensitive" "button" should not be visible
+
+ Scenario: Display the password visibility toggle icon for small screens only
+ Given the following config values are set as admin:
+ | loginpasswordtoggle | 2 |
+ When I follow "Log in"
+ Then "Toggle sensitive" "button" should not be visible
+ And I change the viewport size to "mobile"
+ And "Toggle sensitive" "button" should be visible
diff --git a/backup/moodle2/tests/backup_stepslib_test.php b/backup/moodle2/tests/backup_stepslib_test.php
index 46dc1347cb1c..d06ec5ae69fd 100644
--- a/backup/moodle2/tests/backup_stepslib_test.php
+++ b/backup/moodle2/tests/backup_stepslib_test.php
@@ -74,7 +74,6 @@ public function test_backup_section_structure_step(): void {
$reflection = new \ReflectionClass($step);
$method = $reflection->getMethod('define_structure');
- $method->setAccessible(true);
$structure = $method->invoke($step);
$elements = $structure->get_final_elements();
diff --git a/backup/moodle2/tests/restore_gradebook_structure_step_test.php b/backup/moodle2/tests/restore_gradebook_structure_step_test.php
index 2b47e14c80fd..a541f383cb7e 100644
--- a/backup/moodle2/tests/restore_gradebook_structure_step_test.php
+++ b/backup/moodle2/tests/restore_gradebook_structure_step_test.php
@@ -77,7 +77,6 @@ public function test_rewrite_step_backup_file_for_legacy_freeze($source, $expect
$rc = new \ReflectionClass('\restore_gradebook_structure_step');
$rcm = $rc->getMethod('rewrite_step_backup_file_for_legacy_freeze');
- $rcm->setAccessible(true);
$rcm->invoke($restore, $filepath);
// Check the result.
diff --git a/backup/tests/automated_backup_test.php b/backup/tests/automated_backup_test.php
index 26831d2ab43f..42fdd102374b 100644
--- a/backup/tests/automated_backup_test.php
+++ b/backup/tests/automated_backup_test.php
@@ -116,11 +116,9 @@ public function test_automated_backup_skipped_run() {
$classobject = $this->backupcronautomatedhelper->return_this();
$method = new \ReflectionMethod('\backup_cron_automated_helper', 'get_courses');
- $method->setAccessible(true); // Allow accessing of private method.
$courses = $method->invoke($classobject);
$method = new \ReflectionMethod('\backup_cron_automated_helper', 'check_and_push_automated_backups');
- $method->setAccessible(true); // Allow accessing of private method.
$emailpending = $method->invokeArgs($classobject, [$courses, $admin]);
$this->expectOutputRegex('/Skipping course id ' . $this->course->id . ': Not scheduled for backup until/');
@@ -145,7 +143,6 @@ public function test_automated_backup_push_run() {
$classobject = $this->backupcronautomatedhelper->return_this();
$method = new \ReflectionMethod('\backup_cron_automated_helper', 'get_courses');
- $method->setAccessible(true); // Allow accessing of private method.
$courses = $method->invoke($classobject);
// Create this backup course.
@@ -161,7 +158,6 @@ public function test_automated_backup_push_run() {
$DB->update_record('backup_courses', $backupcourse);
$method = new \ReflectionMethod('\backup_cron_automated_helper', 'check_and_push_automated_backups');
- $method->setAccessible(true); // Allow accessing of private method.
$emailpending = $method->invokeArgs($classobject, [$courses, $admin]);
$this->assertTrue($emailpending);
@@ -204,7 +200,6 @@ public function test_should_skip_invisible_course() {
$nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup(null, time());
$method = new \ReflectionMethod('\backup_cron_automated_helper', 'should_skip_course_backup');
- $method->setAccessible(true); // Allow accessing of private method.
$skipped = $method->invokeArgs($classobject, [$backupcourse, $course, $nextstarttime]);
$this->assertTrue($skipped);
@@ -239,7 +234,6 @@ public function test_should_skip_not_modified_course_in_days() {
$nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup(null, time());
$method = new \ReflectionMethod('\backup_cron_automated_helper', 'should_skip_course_backup');
- $method->setAccessible(true); // Allow accessing of private method.
$skipped = $method->invokeArgs($classobject, [$backupcourse, $course, $nextstarttime]);
$this->assertTrue($skipped);
@@ -274,7 +268,6 @@ public function test_should_skip_not_modified_course_since_prev() {
$nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup(null, time());
$method = new \ReflectionMethod('\backup_cron_automated_helper', 'should_skip_course_backup');
- $method->setAccessible(true); // Allow accessing of private method.
$skipped = $method->invokeArgs($classobject, [$backupcourse, $course, $nextstarttime]);
$this->assertTrue($skipped);
@@ -298,7 +291,6 @@ public function test_task_complete_when_courseid_is_missing() {
// Create a backup task.
$method = new \ReflectionMethod('\backup_cron_automated_helper', 'push_course_backup_adhoc_task');
- $method->setAccessible(true); // Allow accessing of private method.
$method->invokeArgs($classobject, [$backupcourse, $admin]);
// Delete course for this test.
@@ -331,7 +323,6 @@ public function test_task_complete_when_backup_course_is_missing() {
// Create a backup task.
$method = new \ReflectionMethod('\backup_cron_automated_helper', 'push_course_backup_adhoc_task');
- $method->setAccessible(true); // Allow accessing of private method.
$method->invokeArgs($classobject, [$backupcourse, $admin]);
// Delete backup course for this test.
diff --git a/backup/util/dbops/tests/restore_dbops_test.php b/backup/util/dbops/tests/restore_dbops_test.php
index 325c01a4adbd..2be84704e080 100644
--- a/backup/util/dbops/tests/restore_dbops_test.php
+++ b/backup/util/dbops/tests/restore_dbops_test.php
@@ -351,7 +351,6 @@ public function test_precheck_user($dbuser, $backupuser, $samesite, $outcome) {
$dbuser = $DB->get_record('user', ['id' => $dbuser->id]);
$method = (new \ReflectionClass('restore_dbops'))->getMethod('precheck_user');
- $method->setAccessible(true);
$result = $method->invoke(null, $backupuser, $samesite, $siteid);
if (is_bool($result)) {
diff --git a/backup/util/helper/tests/restore_log_rule_test.php b/backup/util/helper/tests/restore_log_rule_test.php
index 58c0cfc6ffae..83c004ffc1b6 100644
--- a/backup/util/helper/tests/restore_log_rule_test.php
+++ b/backup/util/helper/tests/restore_log_rule_test.php
@@ -62,11 +62,9 @@ public function test_build_regexp() {
$class = new \ReflectionClass('restore_log_rule');
$method = $class->getMethod('extract_tokens');
- $method->setAccessible(true);
$tokens = $method->invoke($lr, $original);
$method = $class->getMethod('build_regexp');
- $method->setAccessible(true);
$this->assertSame($expectation, $method->invoke($lr, $original, $tokens));
}
}
diff --git a/badges/tests/badgeslib_test.php b/badges/tests/badgeslib_test.php
index df569b1cd4c7..555e2d8a7042 100644
--- a/badges/tests/badgeslib_test.php
+++ b/badges/tests/badgeslib_test.php
@@ -912,7 +912,6 @@ public function test_core_badges_myprofile_navigation() {
core_badges_myprofile_navigation($tree, $this->user, $iscurrentuser, $course);
$reflector = new ReflectionObject($tree);
$nodes = $reflector->getProperty('nodes');
- $nodes->setAccessible(true);
$this->assertArrayHasKey('localbadges', $nodes->getValue($tree));
}
@@ -935,7 +934,6 @@ public function test_core_badges_myprofile_navigation_badges_disabled() {
core_badges_myprofile_navigation($tree, $this->user, $iscurrentuser, $course);
$reflector = new ReflectionObject($tree);
$nodes = $reflector->getProperty('nodes');
- $nodes->setAccessible(true);
$this->assertArrayNotHasKey('localbadges', $nodes->getValue($tree));
}
@@ -954,7 +952,6 @@ public function test_core_badges_myprofile_navigation_with_course_badge() {
core_badges_myprofile_navigation($tree, $this->user, $iscurrentuser, $this->course);
$reflector = new ReflectionObject($tree);
$nodes = $reflector->getProperty('nodes');
- $nodes->setAccessible(true);
$this->assertArrayHasKey('localbadges', $nodes->getValue($tree));
}
diff --git a/badges/tests/behat/delete_awarded_badge.feature b/badges/tests/behat/delete_awarded_badge.feature
index 8d917144a519..39ae200b387d 100644
--- a/badges/tests/behat/delete_awarded_badge.feature
+++ b/badges/tests/behat/delete_awarded_badge.feature
@@ -34,8 +34,7 @@ Feature: Delete course badge already awarded
# Navigate to Manage Badges page in order to delete the badge
And I navigate to "Badges > Manage badges" in current page administration
# Delete the badge
- And I open the action menu in "" "table_row"
- And I choose "Delete" in the open action menu
+ And I press "Delete" action in the "" report row
And I press ""
And I am on the "Course 1" "enrolled users" page
And I click on "Student 1" "link"
diff --git a/badges/tests/behat/manage_badges.feature b/badges/tests/behat/manage_badges.feature
index c06fabc29ce9..d9b6b0055c94 100644
--- a/badges/tests/behat/manage_badges.feature
+++ b/badges/tests/behat/manage_badges.feature
@@ -54,16 +54,14 @@ Feature: Manage badges
And I set the field "Manager" to "1"
And I press "Save"
And I navigate to "Badges > Manage badges" in site administration
- And I open the action menu in "Badge #1" "table_row"
- And I choose "Enable access" in the open action menu
+ And I press "Enable access" action in the "Badge #1" report row
And I should see "Changes in badge access"
And I press "Continue"
And I should see "Access to the badges was successfully enabled"
Then the following should exist in the "reportbuilder-table" table:
| Name | Badge status |
| Badge #1 | Available |
- And I open the action menu in "Badge #1" "table_row"
- And I choose "Disable access" in the open action menu
+ And I press "Disable access" action in the "Badge #1" report row
And I should see "Access to the badges was successfully disabled"
And the following should exist in the "reportbuilder-table" table:
| Name | Badge status |
@@ -78,14 +76,12 @@ Feature: Manage badges
And I set the field "Manager" to "1"
And I press "Save"
And I navigate to "Badges > Manage badges" in site administration
- And I open the action menu in "Badge #1" "table_row"
- And I choose "Enable access" in the open action menu
+ And I press "Enable access" action in the "Badge #1" report row
And I press "Continue"
- And I open the action menu in "Badge #1" "table_row"
- And I choose "Award badge" in the open action menu
+ And I press "Award badge" action in the "Badge #1" report row
And I set the field "potentialrecipients[]" to "Admin User (moodle@example.com)"
And I press "Award badge"
And I navigate to "Badges > Manage badges" in site administration
- And the following should exist in the "reportbuilder-table" table:
+ Then the following should exist in the "reportbuilder-table" table:
| Name | Badge status | Recipients |
| Badge #1 | Available | 1 |
diff --git a/badges/tests/behat/view_badge.feature b/badges/tests/behat/view_badge.feature
index 1f7795b3b9bd..2a82efa3efa0 100644
--- a/badges/tests/behat/view_badge.feature
+++ b/badges/tests/behat/view_badge.feature
@@ -38,8 +38,7 @@ Feature: Display badges
And I navigate to "Badges > Manage badges" in site administration
And I follow "Testing system badge"
And I select "Recipients (1)" from the "jump" singleselect
- And I open the action menu in "Student 1" "table_row"
- And I choose "View issued badge" in the open action menu
+ And I press "View issued badge" action in the "Student 1" report row
Then I should see "Awarded to Student 1"
And I should see "This badge has to be awarded by a user with the following role:"
And I should not see "Expired"
@@ -64,8 +63,7 @@ Feature: Display badges
And I navigate to "Badges > Manage badges" in site administration
And I follow "Testing system badge"
And I select "Recipients (1)" from the "jump" singleselect
- And I open the action menu in "Student 1" "table_row"
- And I choose "View issued badge" in the open action menu
+ And I press "View issued badge" action in the "Student 1" report row
Then I should see "Awarded to Student 1"
And I should see "Complete ALL of the listed requirements."
And I should see "This badge has to be awarded by a user with the following role:"
@@ -86,8 +84,7 @@ Feature: Display badges
And I press "Continue"
# Check badge details are displayed.
And I select "Recipients (2)" from the "jump" singleselect
- And I open the action menu in "Student 1" "table_row"
- And I choose "View issued badge" in the open action menu
+ And I press "View issued badge" action in the "Student 1" report row
Then I should see "Awarded to Student 1"
And I should see "Complete ANY of the listed requirements."
And I should see "This badge has to be awarded by a user with the following role:"
@@ -115,8 +112,7 @@ Feature: Display badges
And I navigate to "Badges > Manage badges" in site administration
And I follow "Testing system badge"
And I select "Recipients (1)" from the "jump" singleselect
- And I open the action menu in "Student 1" "table_row"
- And I choose "View issued badge" in the open action menu
+ And I press "View issued badge" action in the "Student 1" report row
Then I should see "Expires"
And I should not see "Expired"
@@ -140,7 +136,6 @@ Feature: Display badges
And I navigate to "Badges > Manage badges" in site administration
And I follow "Testing system badge"
And I select "Recipients (1)" from the "jump" singleselect
- And I open the action menu in "Student 1" "table_row"
- And I choose "View issued badge" in the open action menu
+ And I press "View issued badge" action in the "Student 1" report row
Then I should see "Expired"
And I should not see "Expires"
diff --git a/badges/tests/output/manage_badge_action_bar_test.php b/badges/tests/output/manage_badge_action_bar_test.php
index 0979f5e8c303..b93a3c7d2eda 100644
--- a/badges/tests/output/manage_badge_action_bar_test.php
+++ b/badges/tests/output/manage_badge_action_bar_test.php
@@ -134,7 +134,6 @@ public function test_generate_badge_navigation(string $role, array $expected) {
$rc = new \ReflectionClass(manage_badge_action_bar::class);
$rcm = $rc->getMethod('generate_badge_navigation');
- $rcm->setAccessible(true);
$content = $rcm->invoke($actionbar);
$this->assertEquals($expected, array_values($content));
}
diff --git a/blocks/accessreview/tests/accessibility_review_test.php b/blocks/accessreview/tests/accessibility_review_test.php
index 00f74ad458ca..8388fd31e95f 100644
--- a/blocks/accessreview/tests/accessibility_review_test.php
+++ b/blocks/accessreview/tests/accessibility_review_test.php
@@ -39,7 +39,6 @@ public static function setUpBeforeClass(): void {
public function test_get_toggle_link() {
$rc = new ReflectionClass(block_accessreview::class);
$rm = $rc->getMethod('get_toggle_link');
- $rm->setAccessible(true);
$block = new block_accessreview();
$output = $rm->invoke($block);
@@ -60,7 +59,6 @@ public function test_get_download_link() {
$rc = new ReflectionClass(block_accessreview::class);
$rm = $rc->getMethod('get_download_link');
- $rm->setAccessible(true);
$block = new block_accessreview();
$this->setUser($user1);
@@ -86,7 +84,6 @@ public function test_get_report_link() {
$rc = new ReflectionClass(block_accessreview::class);
$rm = $rc->getMethod('get_report_link');
- $rm->setAccessible(true);
$block = new block_accessreview();
$this->setUser($user1);
diff --git a/blocks/myoverview/classes/output/main.php b/blocks/myoverview/classes/output/main.php
index e9bb671e376c..abe98d9e2091 100644
--- a/blocks/myoverview/classes/output/main.php
+++ b/blocks/myoverview/classes/output/main.php
@@ -363,7 +363,14 @@ public function get_customfield_values_for_export() {
if (!$this->displaygroupingcustomfield) {
return [];
}
- $fieldid = $DB->get_field('customfield_field', 'id', ['shortname' => $this->customfiltergrouping]);
+
+ // Get the relevant customfield ID within the core_course/course component/area.
+ $fieldid = $DB->get_field_sql("
+ SELECT f.id
+ FROM {customfield_field} f
+ JOIN {customfield_category} c ON c.id = f.categoryid
+ WHERE f.shortname = :shortname AND c.component = 'core_course' AND c.area = 'course'
+ ", ['shortname' => $this->customfiltergrouping]);
if (!$fieldid) {
return [];
}
diff --git a/blog/tests/lib_test.php b/blog/tests/lib_test.php
index 345e9d2936e8..0eb80f70e9b7 100644
--- a/blog/tests/lib_test.php
+++ b/blog/tests/lib_test.php
@@ -175,7 +175,6 @@ public function test_core_blog_myprofile_navigation() {
core_blog_myprofile_navigation($tree, $USER, $iscurrentuser, $course);
$reflector = new \ReflectionObject($tree);
$nodes = $reflector->getProperty('nodes');
- $nodes->setAccessible(true);
$this->assertArrayHasKey('blogs', $nodes->getValue($tree));
}
@@ -197,7 +196,6 @@ public function test_core_blog_myprofile_navigation_as_guest() {
core_blog_myprofile_navigation($tree, $USER, $iscurrentuser, $course);
$reflector = new \ReflectionObject($tree);
$nodes = $reflector->getProperty('nodes');
- $nodes->setAccessible(true);
$this->assertArrayNotHasKey('blogs', $nodes->getValue($tree));
}
@@ -220,7 +218,6 @@ public function test_core_blog_myprofile_navigation_blogs_disabled() {
core_blog_myprofile_navigation($tree, $USER, $iscurrentuser, $course);
$reflector = new \ReflectionObject($tree);
$nodes = $reflector->getProperty('nodes');
- $nodes->setAccessible(true);
$this->assertArrayNotHasKey('blogs', $nodes->getValue($tree));
}
diff --git a/cache/stores/redis/lib.php b/cache/stores/redis/lib.php
index 3b3229302bb9..16a8d25d8f49 100644
--- a/cache/stores/redis/lib.php
+++ b/cache/stores/redis/lib.php
@@ -851,7 +851,6 @@ public static function initialise_test_instance(cache_definition $definition) {
if (!empty($config->test_ttl)) {
$definition = clone $definition;
$property = (new ReflectionClass($definition))->getProperty('ttl');
- $property->setAccessible(true);
$property->setValue($definition, 999);
}
$cache = new cachestore_redis('Redis test', $configuration);
diff --git a/cache/tests/cache_test.php b/cache/tests/cache_test.php
index ac6df7fe274c..a080816856c3 100644
--- a/cache/tests/cache_test.php
+++ b/cache/tests/cache_test.php
@@ -2332,11 +2332,8 @@ public function test_application_locking_multiple_layers_failures(): void {
// We need to get the individual stores so as to set up the right behaviour here.
$ref = new \ReflectionClass('\cache');
$definitionprop = $ref->getProperty('definition');
- $definitionprop->setAccessible(true);
$storeprop = $ref->getProperty('store');
- $storeprop->setAccessible(true);
$loaderprop = $ref->getProperty('loader');
- $loaderprop->setAccessible(true);
$definition = $definitionprop->getValue($cache);
$localstore = $storeprop->getValue($cache);
@@ -2346,7 +2343,6 @@ public function test_application_locking_multiple_layers_failures(): void {
// Set the lock waiting time to 1 second so it doesn't take forever to run the test.
$ref = new \ReflectionClass('\cachestore_file');
$lockwaitprop = $ref->getProperty('lockwait');
- $lockwaitprop->setAccessible(true);
$lockwaitprop->setValue($localstore, 1);
$lockwaitprop->setValue($sharedstore, 1);
diff --git a/calendar/amd/build/calendar_threemonth.min.js b/calendar/amd/build/calendar_threemonth.min.js
deleted file mode 100644
index 93cae7033aaf..000000000000
--- a/calendar/amd/build/calendar_threemonth.min.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * This module handles display of multiple mini calendars in a view, and
- * movement through them.
- *
- * @deprecated since 4.0 MDL-72810.
- * @todo MDL-73117 This will be deleted in Moodle 4.4.
- * @module core_calendar/calendar_threemonth
- * @copyright 2017 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-define("core_calendar/calendar_threemonth",["jquery","core/notification","core_calendar/selectors","core_calendar/events","core/templates","core_calendar/view_manager"],(function($,Notification,CalendarSelectors,CalendarEvents,Templates,CalendarViewManager){return{init:function(root){!function(root){$("body").on([CalendarEvents.monthChanged,CalendarEvents.dayChanged].join(" "),(function(e,year,month,courseId,categoryId){root.queue((function(next){return processRequest(e,year,month,courseId,categoryId).then((function(){return next()})).fail(Notification.exception)}))}));var processRequest=function(e,year,month,courseId,categoryId){var newParent=root.find('[data-year="'+year+'"][data-month="'+month+'"]').closest(CalendarSelectors.calendarPeriods.month),allMonths=root.find(CalendarSelectors.calendarPeriods.month),previousMonth=$(allMonths[0]),nextMonth=$(allMonths[2]),placeHolder=$("");placeHolder.attr("data-template","core_calendar/threemonth_month"),placeHolder.attr("data-includenavigation",!1),placeHolder.attr("data-mini",!0);var requestYear,requestMonth,oldMonth,placeHolderContainer=$("
");if(placeHolderContainer.hide(),placeHolderContainer.append(placeHolder),newParent.is(previousMonth))placeHolderContainer.insertBefore(previousMonth),requestYear=previousMonth.data("previousYear"),requestMonth=previousMonth.data("previousMonth"),oldMonth=nextMonth;else{if(!newParent.is(nextMonth))return $.Deferred().resolve();placeHolderContainer.insertAfter(nextMonth),requestYear=nextMonth.data("nextYear"),requestMonth=nextMonth.data("nextMonth"),oldMonth=previousMonth}return CalendarViewManager.refreshMonthContent(placeHolder,requestYear,requestMonth,courseId,categoryId,placeHolder).then((function(){var slideUpPromise=$.Deferred(),slideDownPromise=$.Deferred();return oldMonth.slideUp("fast",(function(){$(this).remove(),slideUpPromise.resolve()})),placeHolderContainer.slideDown("fast",(function(){slideDownPromise.resolve()})),$.when(slideUpPromise,slideDownPromise)}))};root.on("click",CalendarSelectors.links.miniDayLink,(function(e){var miniDayLink=$(e.target),year=miniDayLink.data("year"),month=miniDayLink.data("month"),day=miniDayLink.text(),courseId=miniDayLink.data("courseid"),categoryId=miniDayLink.data("categoryid"),calendarRoot=$("body").find(CalendarSelectors.calendarMain);CalendarViewManager.refreshDayContent(calendarRoot,year,month,day,courseId,categoryId,calendarRoot.find('[id^="calendar-"][data-template^="core_calendar/"]'),"core_calendar/calendar_day"),e.preventDefault(),CalendarViewManager.updateUrl("?view=day")}))}(root=$(root))}}}));
-
-//# sourceMappingURL=calendar_threemonth.min.js.map
\ No newline at end of file
diff --git a/calendar/amd/build/calendar_threemonth.min.js.map b/calendar/amd/build/calendar_threemonth.min.js.map
deleted file mode 100644
index fc4a2155b072..000000000000
--- a/calendar/amd/build/calendar_threemonth.min.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"file":"calendar_threemonth.min.js","sources":["../src/calendar_threemonth.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * This module handles display of multiple mini calendars in a view, and\n * movement through them.\n *\n * @deprecated since 4.0 MDL-72810.\n * @todo MDL-73117 This will be deleted in Moodle 4.4.\n * @module core_calendar/calendar_threemonth\n * @copyright 2017 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/notification',\n 'core_calendar/selectors',\n 'core_calendar/events',\n 'core/templates',\n 'core_calendar/view_manager',\n],\nfunction(\n $,\n Notification,\n CalendarSelectors,\n CalendarEvents,\n Templates,\n CalendarViewManager\n) {\n\n /**\n * Listen to and handle any calendar events fired by the calendar UI.\n *\n * @method registerCalendarEventListeners\n * @param {object} root The calendar root element\n */\n var registerCalendarEventListeners = function(root) {\n var body = $('body');\n body.on([CalendarEvents.monthChanged, CalendarEvents.dayChanged].join(' '), function(e, year, month, courseId, categoryId) {\n // We have to use a queue here because the calling code is decoupled from these listeners.\n // It's possible for the event to be called multiple times before one call is fully resolved.\n root.queue(function(next) {\n return processRequest(e, year, month, courseId, categoryId)\n .then(function() {\n return next();\n })\n .fail(Notification.exception)\n ;\n });\n });\n\n var processRequest = function(e, year, month, courseId, categoryId) {\n var newCurrentMonth = root.find('[data-year=\"' + year + '\"][data-month=\"' + month + '\"]');\n var newParent = newCurrentMonth.closest(CalendarSelectors.calendarPeriods.month);\n var allMonths = root.find(CalendarSelectors.calendarPeriods.month);\n\n var previousMonth = $(allMonths[0]);\n var nextMonth = $(allMonths[2]);\n\n var placeHolder = $('');\n placeHolder.attr('data-template', 'core_calendar/threemonth_month');\n placeHolder.attr('data-includenavigation', false);\n placeHolder.attr('data-mini', true);\n var placeHolderContainer = $('
');\n placeHolderContainer.hide();\n placeHolderContainer.append(placeHolder);\n\n var requestYear;\n var requestMonth;\n var oldMonth;\n\n if (newParent.is(previousMonth)) {\n // Fetch the new previous month.\n placeHolderContainer.insertBefore(previousMonth);\n\n requestYear = previousMonth.data('previousYear');\n requestMonth = previousMonth.data('previousMonth');\n oldMonth = nextMonth;\n } else if (newParent.is(nextMonth)) {\n // Fetch the new next month.\n placeHolderContainer.insertAfter(nextMonth);\n requestYear = nextMonth.data('nextYear');\n requestMonth = nextMonth.data('nextMonth');\n oldMonth = previousMonth;\n } else {\n return $.Deferred().resolve();\n }\n\n return CalendarViewManager.refreshMonthContent(\n placeHolder,\n requestYear,\n requestMonth,\n courseId,\n categoryId,\n placeHolder\n )\n .then(function() {\n var slideUpPromise = $.Deferred();\n var slideDownPromise = $.Deferred();\n oldMonth.slideUp('fast', function() {\n $(this).remove();\n slideUpPromise.resolve();\n });\n placeHolderContainer.slideDown('fast', function() {\n slideDownPromise.resolve();\n });\n\n return $.when(slideUpPromise, slideDownPromise);\n });\n };\n\n // Listen for a click on the day link in the three month block to load the day view.\n root.on('click', CalendarSelectors.links.miniDayLink, function(e) {\n\n var miniDayLink = $(e.target);\n var year = miniDayLink.data('year'),\n month = miniDayLink.data('month'),\n day = miniDayLink.text(),\n courseId = miniDayLink.data('courseid'),\n categoryId = miniDayLink.data('categoryid'),\n calendarRoot = $('body').find(CalendarSelectors.calendarMain);\n CalendarViewManager.refreshDayContent(calendarRoot, year, month, day, courseId, categoryId,\n calendarRoot.find('[id^=\"calendar-\"][data-template^=\"core_calendar/\"]'), 'core_calendar/calendar_day');\n e.preventDefault();\n CalendarViewManager.updateUrl('?view=day');\n });\n };\n\n return {\n init: function(root) {\n root = $(root);\n\n registerCalendarEventListeners(root);\n }\n };\n});\n"],"names":["define","$","Notification","CalendarSelectors","CalendarEvents","Templates","CalendarViewManager","init","root","on","monthChanged","dayChanged","join","e","year","month","courseId","categoryId","queue","next","processRequest","then","fail","exception","newParent","find","closest","calendarPeriods","allMonths","previousMonth","nextMonth","placeHolder","attr","requestYear","requestMonth","oldMonth","placeHolderContainer","hide","append","is","insertBefore","data","Deferred","resolve","insertAfter","refreshMonthContent","slideUpPromise","slideDownPromise","slideUp","this","remove","slideDown","when","links","miniDayLink","target","day","text","calendarRoot","calendarMain","refreshDayContent","preventDefault","updateUrl","registerCalendarEventListeners"],"mappings":";;;;;;;;;;AAyBAA,2CAAO,CACH,SACA,oBACA,0BACA,uBACA,iBACA,+BAEJ,SACIC,EACAC,aACAC,kBACAC,eACAC,UACAC,2BAqGO,CACHC,KAAM,SAASC,OA7FkB,SAASA,MAC/BP,EAAE,QACRQ,GAAG,CAACL,eAAeM,aAAcN,eAAeO,YAAYC,KAAK,MAAM,SAASC,EAAGC,KAAMC,MAAOC,SAAUC,YAG3GT,KAAKU,OAAM,SAASC,aACTC,eAAeP,EAAGC,KAAMC,MAAOC,SAAUC,YAC/CI,MAAK,kBACKF,UAEVG,KAAKpB,aAAaqB,qBAKvBH,eAAiB,SAASP,EAAGC,KAAMC,MAAOC,SAAUC,gBAEhDO,UADkBhB,KAAKiB,KAAK,eAAiBX,KAAO,kBAAoBC,MAAQ,MACpDW,QAAQvB,kBAAkBwB,gBAAgBZ,OACtEa,UAAYpB,KAAKiB,KAAKtB,kBAAkBwB,gBAAgBZ,OAExDc,cAAgB5B,EAAE2B,UAAU,IAC5BE,UAAY7B,EAAE2B,UAAU,IAExBG,YAAc9B,EAAE,UACpB8B,YAAYC,KAAK,gBAAiB,kCAClCD,YAAYC,KAAK,0BAA0B,GAC3CD,YAAYC,KAAK,aAAa,OAK1BC,YACAC,aACAC,SANAC,qBAAuBnC,EAAE,YAC7BmC,qBAAqBC,OACrBD,qBAAqBE,OAAOP,aAMxBP,UAAUe,GAAGV,eAEbO,qBAAqBI,aAAaX,eAElCI,YAAcJ,cAAcY,KAAK,gBACjCP,aAAeL,cAAcY,KAAK,iBAClCN,SAAWL,cACR,CAAA,IAAIN,UAAUe,GAAGT,kBAOb7B,EAAEyC,WAAWC,UALpBP,qBAAqBQ,YAAYd,WACjCG,YAAcH,UAAUW,KAAK,YAC7BP,aAAeJ,UAAUW,KAAK,aAC9BN,SAAWN,qBAKRvB,oBAAoBuC,oBACvBd,YACAE,YACAC,aACAlB,SACAC,WACAc,aAEHV,MAAK,eACEyB,eAAiB7C,EAAEyC,WACnBK,iBAAmB9C,EAAEyC,kBACzBP,SAASa,QAAQ,QAAQ,WACrB/C,EAAEgD,MAAMC,SACRJ,eAAeH,aAEnBP,qBAAqBe,UAAU,QAAQ,WACnCJ,iBAAiBJ,aAGd1C,EAAEmD,KAAKN,eAAgBC,sBAKtCvC,KAAKC,GAAG,QAASN,kBAAkBkD,MAAMC,aAAa,SAASzC,OAEnDyC,YAAcrD,EAAEY,EAAE0C,QAClBzC,KAAOwC,YAAYb,KAAK,QACxB1B,MAAQuC,YAAYb,KAAK,SACzBe,IAAMF,YAAYG,OAClBzC,SAAWsC,YAAYb,KAAK,YAC5BxB,WAAaqC,YAAYb,KAAK,cAC9BiB,aAAezD,EAAE,QAAQwB,KAAKtB,kBAAkBwD,cACpDrD,oBAAoBsD,kBAAkBF,aAAc5C,KAAMC,MAAOyC,IAAKxC,SAAUC,WAC5EyC,aAAajC,KAAK,sDAAuD,8BAC7EZ,EAAEgD,iBACFvD,oBAAoBwD,UAAU,gBAQlCC,CAFAvD,KAAOP,EAAEO"}
\ No newline at end of file
diff --git a/calendar/amd/src/calendar_threemonth.js b/calendar/amd/src/calendar_threemonth.js
deleted file mode 100644
index 576f6c10bc58..000000000000
--- a/calendar/amd/src/calendar_threemonth.js
+++ /dev/null
@@ -1,148 +0,0 @@
-// 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 .
-
-/**
- * This module handles display of multiple mini calendars in a view, and
- * movement through them.
- *
- * @deprecated since 4.0 MDL-72810.
- * @todo MDL-73117 This will be deleted in Moodle 4.4.
- * @module core_calendar/calendar_threemonth
- * @copyright 2017 Andrew Nicols
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-define([
- 'jquery',
- 'core/notification',
- 'core_calendar/selectors',
- 'core_calendar/events',
- 'core/templates',
- 'core_calendar/view_manager',
-],
-function(
- $,
- Notification,
- CalendarSelectors,
- CalendarEvents,
- Templates,
- CalendarViewManager
-) {
-
- /**
- * Listen to and handle any calendar events fired by the calendar UI.
- *
- * @method registerCalendarEventListeners
- * @param {object} root The calendar root element
- */
- var registerCalendarEventListeners = function(root) {
- var body = $('body');
- body.on([CalendarEvents.monthChanged, CalendarEvents.dayChanged].join(' '), function(e, year, month, courseId, categoryId) {
- // We have to use a queue here because the calling code is decoupled from these listeners.
- // It's possible for the event to be called multiple times before one call is fully resolved.
- root.queue(function(next) {
- return processRequest(e, year, month, courseId, categoryId)
- .then(function() {
- return next();
- })
- .fail(Notification.exception)
- ;
- });
- });
-
- var processRequest = function(e, year, month, courseId, categoryId) {
- var newCurrentMonth = root.find('[data-year="' + year + '"][data-month="' + month + '"]');
- var newParent = newCurrentMonth.closest(CalendarSelectors.calendarPeriods.month);
- var allMonths = root.find(CalendarSelectors.calendarPeriods.month);
-
- var previousMonth = $(allMonths[0]);
- var nextMonth = $(allMonths[2]);
-
- var placeHolder = $('');
- placeHolder.attr('data-template', 'core_calendar/threemonth_month');
- placeHolder.attr('data-includenavigation', false);
- placeHolder.attr('data-mini', true);
- var placeHolderContainer = $('
');
- placeHolderContainer.hide();
- placeHolderContainer.append(placeHolder);
-
- var requestYear;
- var requestMonth;
- var oldMonth;
-
- if (newParent.is(previousMonth)) {
- // Fetch the new previous month.
- placeHolderContainer.insertBefore(previousMonth);
-
- requestYear = previousMonth.data('previousYear');
- requestMonth = previousMonth.data('previousMonth');
- oldMonth = nextMonth;
- } else if (newParent.is(nextMonth)) {
- // Fetch the new next month.
- placeHolderContainer.insertAfter(nextMonth);
- requestYear = nextMonth.data('nextYear');
- requestMonth = nextMonth.data('nextMonth');
- oldMonth = previousMonth;
- } else {
- return $.Deferred().resolve();
- }
-
- return CalendarViewManager.refreshMonthContent(
- placeHolder,
- requestYear,
- requestMonth,
- courseId,
- categoryId,
- placeHolder
- )
- .then(function() {
- var slideUpPromise = $.Deferred();
- var slideDownPromise = $.Deferred();
- oldMonth.slideUp('fast', function() {
- $(this).remove();
- slideUpPromise.resolve();
- });
- placeHolderContainer.slideDown('fast', function() {
- slideDownPromise.resolve();
- });
-
- return $.when(slideUpPromise, slideDownPromise);
- });
- };
-
- // Listen for a click on the day link in the three month block to load the day view.
- root.on('click', CalendarSelectors.links.miniDayLink, function(e) {
-
- var miniDayLink = $(e.target);
- var year = miniDayLink.data('year'),
- month = miniDayLink.data('month'),
- day = miniDayLink.text(),
- courseId = miniDayLink.data('courseid'),
- categoryId = miniDayLink.data('categoryid'),
- calendarRoot = $('body').find(CalendarSelectors.calendarMain);
- CalendarViewManager.refreshDayContent(calendarRoot, year, month, day, courseId, categoryId,
- calendarRoot.find('[id^="calendar-"][data-template^="core_calendar/"]'), 'core_calendar/calendar_day');
- e.preventDefault();
- CalendarViewManager.updateUrl('?view=day');
- });
- };
-
- return {
- init: function(root) {
- root = $(root);
-
- registerCalendarEventListeners(root);
- }
- };
-});
diff --git a/calendar/renderer.php b/calendar/renderer.php
index b6c867835574..5134fa007fa5 100644
--- a/calendar/renderer.php
+++ b/calendar/renderer.php
@@ -51,63 +51,10 @@ public function complete_layout() {
}
/**
- * Produces the content for the three months block (pretend block)
- *
- * This includes the previous month, the current month, and the next month
- *
* @deprecated since 4.0 MDL-72810.
- * @todo MDL-73117 This will be deleted in Moodle 4.4.
- *
- * @param calendar_information $calendar
- * @return string
*/
- public function fake_block_threemonths(calendar_information $calendar) {
- debugging('This method is no longer used as the three month calendar block has been removed', DEBUG_DEVELOPER);
-
- // Get the calendar type we are using.
- $calendartype = \core_calendar\type_factory::get_calendar_instance();
- $time = $calendartype->timestamp_to_date_array($calendar->time);
-
- $current = $calendar->time;
- $prevmonthyear = $calendartype->get_prev_month($time['year'], $time['mon']);
- $prev = $calendartype->convert_to_timestamp(
- $prevmonthyear[1],
- $prevmonthyear[0],
- 1
- );
- $nextmonthyear = $calendartype->get_next_month($time['year'], $time['mon']);
- $next = $calendartype->convert_to_timestamp(
- $nextmonthyear[1],
- $nextmonthyear[0],
- 1
- );
-
- $content = '';
-
- // Previous.
- $calendar->set_time($prev);
- list($previousmonth, ) = calendar_get_view($calendar, 'minithree', false, true);
-
- // Current month.
- $calendar->set_time($current);
- list($currentmonth, ) = calendar_get_view($calendar, 'minithree', false, true);
-
- // Next month.
- $calendar->set_time($next);
- list($nextmonth, ) = calendar_get_view($calendar, 'minithree', false, true);
-
- // Reset the time back.
- $calendar->set_time($current);
-
- $data = (object) [
- 'previousmonth' => $previousmonth,
- 'currentmonth' => $currentmonth,
- 'nextmonth' => $nextmonth,
- ];
-
- $template = 'core_calendar/calendar_threemonth';
- $content .= $this->render_from_template($template, $data);
- return $content;
+ public function fake_block_threemonths() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
}
/**
diff --git a/calendar/templates/calendar_threemonth.mustache b/calendar/templates/calendar_threemonth.mustache
deleted file mode 100644
index 5fc66f7eb47c..000000000000
--- a/calendar/templates/calendar_threemonth.mustache
+++ /dev/null
@@ -1,52 +0,0 @@
-{{!
- 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 .
-}}
-{{!
- @template core_calendar/calendar_threemonth
-
- @deprecated since 4.0 MDL-72810.
- @todo MDL-73117 This will be deleted in Moodle 4.4.
-
- Calendar view to show three months as a block.
-
- The purpose of this template is to render a set of three months of calendar_mini in a block.
-
- Classes required for JS:
- * none
-
- Data attributes required for JS:
- * none
-
- Example context (json):
- {
- }
-}}
-
-{{#js}}
-require(['jquery', 'core_calendar/calendar_threemonth'], function($, CalendarThreeMonth) {
- CalendarThreeMonth.init($("#calendar-multi-{{uniqid}}"));
-});
-{{/js}}
diff --git a/calendar/tests/behat/behat_calendar.php b/calendar/tests/behat/behat_calendar.php
index fc53c18233ca..3065ae8fd468 100644
--- a/calendar/tests/behat/behat_calendar.php
+++ b/calendar/tests/behat/behat_calendar.php
@@ -122,16 +122,6 @@ public function i_hover_over_today_in_mini_calendar_block(): void {
$this->i_hover_over_day_of_this_month_in_mini_calendar_block($todaysday);
}
- /**
- * Hover over today in the calendar.
- *
- * @Given /^I hover over today in the calendar$/
- */
- public function i_hover_over_today_in_the_calendar() {
- $todaysday = date('j');
- return $this->i_hover_over_day_of_this_month_in_calendar($todaysday);
- }
-
/**
* Navigate to a specific month in the calendar.
*
diff --git a/calendar/tests/behat/behat_calendar_deprecated.php b/calendar/tests/behat/behat_calendar_deprecated.php
new file mode 100644
index 000000000000..0fc1a08838b5
--- /dev/null
+++ b/calendar/tests/behat/behat_calendar_deprecated.php
@@ -0,0 +1,59 @@
+.
+
+// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
+
+require_once(__DIR__ . '/../../../lib/behat/behat_deprecated_base.php');
+
+/**
+ * Steps definitions that are now deprecated and will be removed in the next releases.
+ *
+ * This file only contains the steps that previously were in the behat_*.php files in the SAME DIRECTORY.
+ * When deprecating steps from other components or plugins, create a behat_COMPONENT_deprecated.php
+ * file in the same directory where the steps were defined.
+ *
+ * @package core_calendar
+ * @category test
+ * @copyright 2024 Mathew May
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_calendar_deprecated extends behat_deprecated_base {
+ /**
+ * Hover over today in the calendar.
+ *
+ * @Given /^I hover over today in the calendar$/
+ *
+ * @deprecated since 4.4 MDL-73117.
+ * @TODO MDL-79721: This will be deleted in Moodle 4.8.
+ */
+ public function i_hover_over_today_in_the_calendar() {
+ $this->deprecated_message('behat_calendar::i_hover_over_today_in_the_calendar');
+ $todaysday = date('j');
+
+ $summarytitle = userdate(time(), get_string('strftimemonthyear'));
+ // The current month table.
+ $currentmonth = "table[descendant::*[self::caption[contains(concat(' ', normalize-space(.), ' '), ' {$summarytitle} ')]]]";
+
+ // Strings for the class cell match.
+ $cellclasses = "contains(concat(' ', normalize-space(@class), ' '), ' day ')";
+ $daycontains = "text()[contains(concat(' ', normalize-space(.), ' '), ' {$todaysday} ')]";
+ $daycell = "td[{$cellclasses}]";
+ $dayofmonth = "a[{$daycontains}]";
+
+ $xpath = '//' . $currentmonth . '/descendant::' . $daycell . '/' . $dayofmonth;
+ $this->execute("behat_general::i_hover", [$xpath, "xpath_element"]);
+ }
+}
diff --git a/calendar/tests/calendar_event_exporter_test.php b/calendar/tests/calendar_event_exporter_test.php
index 055309216466..e092c4689b30 100644
--- a/calendar/tests/calendar_event_exporter_test.php
+++ b/calendar/tests/calendar_event_exporter_test.php
@@ -80,7 +80,6 @@ public function test_get_timestamp_min_limit($starttime, $min, $expected) {
->getMock();
$reflector = new \ReflectionClass($class);
$method = $reflector->getMethod('get_timestamp_min_limit');
- $method->setAccessible(true);
$result = $method->invoke($mock, $starttime, $min);
$this->assertEquals($expected, $result['mindaytimestamp']);
@@ -137,7 +136,6 @@ public function test_get_timestamp_max_limit($starttime, $max, $expected) {
->getMock();
$reflector = new \ReflectionClass($class);
$method = $reflector->getMethod('get_timestamp_max_limit');
- $method->setAccessible(true);
$result = $method->invoke($mock, $starttime, $max);
$this->assertEquals($expected, $result['maxdaytimestamp']);
diff --git a/calendar/tests/rrule_manager_test.php b/calendar/tests/rrule_manager_test.php
index ed9a3c119943..12b625a27a83 100644
--- a/calendar/tests/rrule_manager_test.php
+++ b/calendar/tests/rrule_manager_test.php
@@ -124,7 +124,6 @@ public function test_parse_rrule() {
$reflectionclass = new \ReflectionClass($mang);
foreach ($props as $prop => $expectedval) {
$rcprop = $reflectionclass->getProperty($prop);
- $rcprop->setAccessible(true);
$this->assertEquals($expectedval, $rcprop->getValue($mang));
}
}
diff --git a/calendar/upgrade.txt b/calendar/upgrade.txt
index 89855aa40937..28f627b4144e 100644
--- a/calendar/upgrade.txt
+++ b/calendar/upgrade.txt
@@ -5,6 +5,15 @@ information provided here is intended especially for developers.
* The following previously deprecated methods have been removed and can no longer be used:
- `calendar_process_subscription_row`
- `calendar_import_icalendar_events`
+ - `fake_block_threemonths`
+ - `i_click_day_of_this_month_in_calendar`
+ - `i_hover_over_today_in_the_calendar`
+* The following previously deprecated files have been removed and can no longer be used:
+ - `calendar_threemonth.js`
+ - `calendar_threemonth.mustache`
+ - `threemonth_month.mustache`
+* The following have been deprecated:
+ - Behat step definition `i_hover_over_today_in_the_calendar`
* The event_exporter_base class now returns a field called "branded" indicating whether the module is branded or not.
All the external functions using the exporter will now return the new field:
- core_calendar_get_action_events_by_course
diff --git a/communication/provider/matrix/tests/local/command_test.php b/communication/provider/matrix/tests/local/command_test.php
index c255f26ed639..8e540b784101 100644
--- a/communication/provider/matrix/tests/local/command_test.php
+++ b/communication/provider/matrix/tests/local/command_test.php
@@ -281,7 +281,6 @@ public function test_query_parameters(
);
$execute = new ReflectionMethod($instance, 'execute');
- $execute->setAccessible(true);
$execute->invoke($instance, $command);
}
diff --git a/communication/provider/matrix/tests/matrix_client_test.php b/communication/provider/matrix/tests/matrix_client_test.php
index 00680e242adc..a3e8c8950868 100644
--- a/communication/provider/matrix/tests/matrix_client_test.php
+++ b/communication/provider/matrix/tests/matrix_client_test.php
@@ -447,7 +447,6 @@ public function test_command_is_executed(): void {
$rc = new \ReflectionClass($instance);
$rcm = $rc->getMethod('execute');
- $rcm->setAccessible(true);
$result = $rcm->invoke($instance, $command);
$this->assertEquals(200, $result->getStatusCode());
diff --git a/completion/completion_completion.php b/completion/completion_completion.php
index 54adf228420d..47bd4c003f9f 100644
--- a/completion/completion_completion.php
+++ b/completion/completion_completion.php
@@ -179,8 +179,10 @@ public function mark_complete($timecomplete = null) {
// Notify user.
$course = get_course($data->course);
$messagesubject = get_string('coursecompleted', 'completion');
+ $options = new stdClass();
+ $options->context = context_course::instance($course->id);
$a = [
- 'coursename' => get_course_display_name_for_list($course),
+ 'coursename' => format_string(get_course_display_name_for_list($course), true, $options),
'courselink' => (string) new moodle_url('/course/view.php', array('id' => $course->id)),
];
$messagebody = get_string('coursecompletedmessage', 'completion', $a);
diff --git a/contentbank/tests/contentbank_test.php b/contentbank/tests/contentbank_test.php
index 88a08ed07a9a..6291c2ae70e5 100644
--- a/contentbank/tests/contentbank_test.php
+++ b/contentbank/tests/contentbank_test.php
@@ -568,7 +568,6 @@ public function test_get_contenttypes_with_capability_feature(array $contenttype
// Replace protected singletoninstance reference (core_plugin_manager property) with mock object.
$ref = new \ReflectionProperty(\core_plugin_manager::class, 'singletoninstance');
- $ref->setAccessible(true);
$ref->setValue(null, $pluginmanager);
// Return values of get_plugins_of_type method.
@@ -592,7 +591,6 @@ public function test_get_contenttypes_with_capability_feature(array $contenttype
// Get access to private property enabledcontenttypes.
$rc = new \ReflectionClass(\core_contentbank\contentbank::class);
$rcp = $rc->getProperty('enabledcontenttypes');
- $rcp->setAccessible(true);
foreach ($contenttypesenabled as $contenttypename) {
$plugins["\\contenttype_$contenttypename\\contenttype"] = $contenttypename;
diff --git a/course/format/tests/local/baseactions_test.php b/course/format/tests/local/baseactions_test.php
index 65bc80d9732f..19d05e14332d 100644
--- a/course/format/tests/local/baseactions_test.php
+++ b/course/format/tests/local/baseactions_test.php
@@ -45,7 +45,6 @@ public static function setUpBeforeClass(): void {
private function get_base_reflection_method(baseactions $baseinstance, string $methodname): ReflectionMethod {
$reflectionclass = new \reflectionclass($baseinstance);
$method = $reflectionclass->getMethod($methodname);
- $method->setAccessible(true);
return $method;
}
diff --git a/course/tests/category_hooks_test.php b/course/tests/category_hooks_test.php
index 21a73bd91639..b68de7a7eebe 100644
--- a/course/tests/category_hooks_test.php
+++ b/course/tests/category_hooks_test.php
@@ -72,7 +72,6 @@ public function get_mock_category(\core_course_category $category, string $callb
// This is used to overcome private constructor.
$reflected = new \ReflectionClass(\core_course_category::class);
$constructor = $reflected->getConstructor();
- $constructor->setAccessible(true);
$constructor->invoke($mockcategory, $category->get_db_record());
return $mockcategory;
diff --git a/course/tests/course_image_cache_test.php b/course/tests/course_image_cache_test.php
index c3fffd79c21c..59b697a5b97a 100644
--- a/course/tests/course_image_cache_test.php
+++ b/course/tests/course_image_cache_test.php
@@ -98,7 +98,6 @@ public function test_getting_data_if_course_is_not_exist() {
public function test_get_image_url_from_overview_files_return_null_if_no_summary_files_in_the_course() {
$method = new ReflectionMethod(course_image::class, 'get_image_url_from_overview_files');
$cache = course_image::get_instance_for_cache(new cache_definition());
- $method->setAccessible(true);
// Create course without files.
$course = $this->getDataGenerator()->create_course();
@@ -111,7 +110,6 @@ public function test_get_image_url_from_overview_files_return_null_if_no_summary
public function test_get_image_url_from_overview_files_returns_null_if_no_summary_images_in_the_course() {
$method = new ReflectionMethod(course_image::class, 'get_image_url_from_overview_files');
$cache = course_image::get_instance_for_cache(new cache_definition());
- $method->setAccessible(true);
// Create course without image files.
$draftid2 = $this->fill_draft_area(['filename2.zip' => 'Test file contents2']);
@@ -125,7 +123,6 @@ public function test_get_image_url_from_overview_files_returns_null_if_no_summar
public function test_get_image_url_from_overview_files_returns_url_if_there_is_a_summary_image() {
$method = new ReflectionMethod(course_image::class, 'get_image_url_from_overview_files');
$cache = course_image::get_instance_for_cache(new cache_definition());
- $method->setAccessible(true);
// Create course without one image.
$draftid1 = $this->fill_draft_area(['filename1.jpg' => file_get_contents(__DIR__ . '/fixtures/image.jpg')]);
@@ -140,7 +137,6 @@ public function test_get_image_url_from_overview_files_returns_url_if_there_is_a
public function test_get_image_url_from_overview_files_returns_url_of_the_first_image_if_there_are_many_summary_images() {
$method = new ReflectionMethod(course_image::class, 'get_image_url_from_overview_files');
$cache = course_image::get_instance_for_cache(new cache_definition());
- $method->setAccessible(true);
// Create course with two image files.
$draftid1 = $this->fill_draft_area([
@@ -159,7 +155,6 @@ public function test_get_image_url_from_overview_files_returns_url_of_the_first_
public function test_get_image_url_from_overview_files_returns_url_of_the_first_image_if_there_are_many_summary_files() {
$method = new ReflectionMethod(course_image::class, 'get_image_url_from_overview_files');
$cache = course_image::get_instance_for_cache(new cache_definition());
- $method->setAccessible(true);
// Create course with two image files and one zip file.
$draftid1 = $this->fill_draft_area([
diff --git a/course/tests/targets_test.php b/course/tests/targets_test.php
index 9e2e72b9823c..6dc0ad89a5dd 100644
--- a/course/tests/targets_test.php
+++ b/course/tests/targets_test.php
@@ -413,7 +413,6 @@ public function test_core_target_course_completion_samples($coursestart, $course
$class = new \ReflectionClass('\core\analytics\analyser\student_enrolments');
$method = $class->getMethod('get_all_samples');
- $method->setAccessible(true);
list($sampleids, $samplesdata) = $method->invoke($analyser, $analysable);
$target->add_sample_data($samplesdata);
@@ -448,7 +447,6 @@ public function test_core_target_course_completion_active_during_analysis_time($
$class = new \ReflectionClass('\core\analytics\analyser\student_enrolments');
$method = $class->getMethod('get_all_samples');
- $method->setAccessible(true);
list($sampleids, $samplesdata) = $method->invoke($analyser, $analysable);
$target->add_sample_data($samplesdata);
@@ -456,7 +454,6 @@ public function test_core_target_course_completion_active_during_analysis_time($
$reftarget = new \ReflectionObject($target);
$refmethod = $reftarget->getMethod('calculate_sample');
- $refmethod->setAccessible(true);
if ($nullcalculation) {
$this->assertNull($refmethod->invoke($target, $sampleid, $analysable, $starttime, $endtime));
@@ -532,7 +529,6 @@ public function test_core_target_course_competencies_calculate() {
$class = new \ReflectionClass('\core\analytics\analyser\student_enrolments');
$method = $class->getMethod('get_all_samples');
- $method->setAccessible(true);
list($sampleids, $samplesdata) = $method->invoke($analyser, $analysable);
$target->add_sample_data($samplesdata);
@@ -540,7 +536,6 @@ public function test_core_target_course_competencies_calculate() {
$class = new \ReflectionClass('\core_course\analytics\target\course_competencies');
$method = $class->getMethod('calculate_sample');
- $method->setAccessible(true);
// Method calculate_sample() returns 1 when the user has not achieved all the competencies assigned to the course.
$this->assertEquals(1, $method->invoke($target, $sampleid, $analysable));
@@ -630,14 +625,12 @@ public function test_core_target_course_gradetopass_calculate() {
$class = new \ReflectionClass('\core\analytics\analyser\student_enrolments');
$method = $class->getMethod('get_all_samples');
- $method->setAccessible(true);
list($sampleids, $samplesdata) = $method->invoke($analyser, $analysable);
$target->add_sample_data($samplesdata);
$class = new \ReflectionClass('\core_course\analytics\target\course_gradetopass');
$method = $class->getMethod('calculate_sample');
- $method->setAccessible(true);
// Verify all the expectations are fulfilled.
foreach ($sampleids as $sampleid => $key) {
diff --git a/customfield/tests/generator/lib.php b/customfield/tests/generator/lib.php
index eae8490154f0..6da6bf30f828 100644
--- a/customfield/tests/generator/lib.php
+++ b/customfield/tests/generator/lib.php
@@ -156,7 +156,6 @@ public function add_instance_data(field_controller $field, int $instanceid, $val
$rc = new ReflectionClass(get_class($data));
$rcm = $rc->getMethod('get_form_element_name');
- $rcm->setAccessible(true);
$formelementname = $rcm->invokeArgs($data, []);
$record = (object)[$formelementname => $value];
$data->instance_form_save($record);
diff --git a/enrol/ldap/tests/ldap_test.php b/enrol/ldap/tests/ldap_test.php
index c918b19f0293..7f93d763593f 100644
--- a/enrol/ldap/tests/ldap_test.php
+++ b/enrol/ldap/tests/ldap_test.php
@@ -513,7 +513,6 @@ public function test_objectclass_fetch($usertype, $expected) {
// Use reflection to sneak a look at the plugin.
$rc = new \ReflectionClass('enrol_ldap_plugin');
$rcp = $rc->getProperty('userobjectclass');
- $rcp->setAccessible(true);
// Fetch the current userobjectclass value.
$value = $rcp->getValue($instance);
diff --git a/enrol/lti/tests/helper_test.php b/enrol/lti/tests/helper_test.php
index 90fc6c09e14f..a3553183415c 100644
--- a/enrol/lti/tests/helper_test.php
+++ b/enrol/lti/tests/helper_test.php
@@ -477,7 +477,6 @@ public function set_xpath_provider() {
public function test_set_xpath($parameters, $expected) {
$helper = new \ReflectionClass('enrol_lti\\helper');
$function = $helper->getMethod('set_xpath');
- $function->setAccessible(true);
$document = new \DOMDocument();
$document->load(realpath(__DIR__ . '/fixtures/input.xml'));
@@ -502,7 +501,6 @@ public function test_set_xpath_incorrect_xpath() {
];
$helper = new \ReflectionClass('enrol_lti\\helper');
$function = $helper->getMethod('set_xpath');
- $function->setAccessible(true);
$document = new \DOMDocument();
$document->load(realpath(__DIR__ . '/fixtures/input.xml'));
diff --git a/files/tests/converter_test.php b/files/tests/converter_test.php
index d54d4b171aeb..ae766c8856cd 100644
--- a/files/tests/converter_test.php
+++ b/files/tests/converter_test.php
@@ -223,7 +223,6 @@ public function test_get_document_converter_classes_no_plugins() {
$converter->method('get_enabled_plugins')->willReturn([]);
$method = new ReflectionMethod(\core_files\converter::class, 'get_document_converter_classes');
- $method->setAccessible(true);
$result = $method->invokeArgs($converter, ['docx', 'pdf']);
$this->assertEmpty($result);
}
@@ -238,7 +237,6 @@ public function test_get_document_converter_classes_plugin_class_not_found() {
]);
$method = new ReflectionMethod(\core_files\converter::class, 'get_document_converter_classes');
- $method->setAccessible(true);
$result = $method->invokeArgs($converter, ['docx', 'pdf']);
$this->assertEmpty($result);
}
@@ -257,7 +255,6 @@ public function test_get_document_converter_classes_plugin_class_requirements_no
]);
$method = new ReflectionMethod(\core_files\converter::class, 'get_document_converter_classes');
- $method->setAccessible(true);
$result = $method->invokeArgs($converter, ['docx', 'pdf']);
$this->assertEmpty($result);
}
@@ -276,7 +273,6 @@ public function test_get_document_converter_classes_plugin_class_met_not_support
]);
$method = new ReflectionMethod(\core_files\converter::class, 'get_document_converter_classes');
- $method->setAccessible(true);
$result = $method->invokeArgs($converter, ['docx', 'pdf']);
$this->assertEmpty($result);
}
@@ -296,7 +292,6 @@ public function test_get_document_converter_classes_plugin_class_met_and_support
]);
$method = new ReflectionMethod(\core_files\converter::class, 'get_document_converter_classes');
- $method->setAccessible(true);
$result = $method->invokeArgs($converter, ['docx', 'pdf']);
$this->assertCount(1, $result);
$this->assertNotFalse(array_search($classname, $result));
@@ -681,7 +676,6 @@ public function test_start_conversion_two_supported() {
*/
public function test_get_next_converter_no_converters() {
$rcm = new \ReflectionMethod(converter::class, 'get_next_converter');
- $rcm->setAccessible(true);
$converter = new \core_files\converter();
$result = $rcm->invoke($converter, [], null);
@@ -694,7 +688,6 @@ public function test_get_next_converter_no_converters() {
*/
public function test_get_next_converter_only_converters() {
$rcm = new \ReflectionMethod(converter::class, 'get_next_converter');
- $rcm->setAccessible(true);
$converter = new converter();
$result = $rcm->invoke($converter, ['example'], 'example');
@@ -707,7 +700,6 @@ public function test_get_next_converter_only_converters() {
*/
public function test_get_next_converter_last_converters() {
$rcm = new \ReflectionMethod(converter::class, 'get_next_converter');
- $rcm->setAccessible(true);
$converter = new converter();
$result = $rcm->invoke($converter, ['foo', 'example'], 'example');
@@ -720,7 +712,6 @@ public function test_get_next_converter_last_converters() {
*/
public function test_get_next_converter_middle_converters() {
$rcm = new \ReflectionMethod(converter::class, 'get_next_converter');
- $rcm->setAccessible(true);
$converter = new converter();
$result = $rcm->invoke($converter, ['foo', 'bar', 'baz', 'example'], 'bar');
@@ -733,7 +724,6 @@ public function test_get_next_converter_middle_converters() {
*/
public function test_get_next_converter_first() {
$rcm = new \ReflectionMethod(converter::class, 'get_next_converter');
- $rcm->setAccessible(true);
$converter = new converter();
$result = $rcm->invoke($converter, ['foo', 'bar', 'baz', 'example']);
diff --git a/grade/report/user/tests/lib_test.php b/grade/report/user/tests/lib_test.php
index c27caa4c02f7..59bb6dc5fe6c 100644
--- a/grade/report/user/tests/lib_test.php
+++ b/grade/report/user/tests/lib_test.php
@@ -69,7 +69,6 @@ public function test_gradereport_user_myprofile_navigation() {
gradereport_user_myprofile_navigation($this->tree, $this->user, $iscurrentuser, $this->course);
$reflector = new \ReflectionObject($this->tree);
$nodes = $reflector->getProperty('nodes');
- $nodes->setAccessible(true);
$this->assertArrayHasKey('grade', $nodes->getValue($this->tree));
}
@@ -84,7 +83,6 @@ public function test_gradereport_user_myprofile_navigation_without_permission()
gradereport_user_myprofile_navigation($this->tree, $this->user, $iscurrentuser, $this->course);
$reflector = new \ReflectionObject($this->tree);
$nodes = $reflector->getProperty('nodes');
- $nodes->setAccessible(true);
$this->assertArrayNotHasKey('grade', $nodes->getValue($this->tree));
}
}
diff --git a/h5p/tests/editor_test.php b/h5p/tests/editor_test.php
index 74fe952b91f8..d2f1fc763813 100644
--- a/h5p/tests/editor_test.php
+++ b/h5p/tests/editor_test.php
@@ -113,7 +113,6 @@ public function test_set_content() {
// Call the method. We need the id of the new H5P content.
$rc = new \ReflectionClass(player::class);
$rcp = $rc->getProperty('h5pid');
- $rcp->setAccessible(true);
$h5pid = $rcp->getValue($h5pplayer);
$editor = new editor();
@@ -122,7 +121,6 @@ public function test_set_content() {
// Check we get the H5P content.
$rc = new \ReflectionClass(editor::class);
$rcp = $rc->getProperty('oldcontent');
- $rcp->setAccessible(true);
$oldcontent = $rcp->getValue($editor);
$core = (new factory)->get_core();
@@ -130,7 +128,6 @@ public function test_set_content() {
// Check we get the file of the H5P content.
$rcp = $rc->getProperty('oldfile');
- $rcp->setAccessible(true);
$oldfile = $rcp->getValue($editor);
$this->assertSame($file->get_contenthash(), $oldfile->get_contenthash());
@@ -154,7 +151,6 @@ public function test_set_library() {
// Check that the library has the right value.
$rc = new \ReflectionClass(editor::class);
$rcp = $rc->getProperty('library');
- $rcp->setAccessible(true);
$actual = $rcp->getValue($editor);
$this->assertSame($library, $actual);
@@ -171,7 +167,6 @@ public function test_set_library() {
];
$rcp = $rc->getProperty('filearea');
- $rcp->setAccessible(true);
$actual = $rcp->getValue($editor);
$this->assertEquals($expected, $actual);
@@ -198,8 +193,6 @@ public function test_add_editor_to_form() {
$rc = new \ReflectionClass(page_requirements_manager::class);
$rcp = $rc->getProperty('cssurls');
$rcp2 = $rc->getProperty('jsincludes');
- $rcp->setAccessible(true);
- $rcp2->setAccessible(true);
$actualcss = array_keys($rcp->getValue($PAGE->requires));
$actualjs = array_keys($rcp2->getValue($PAGE->requires)['head']);
$cachebuster = helper::get_cache_buster();
diff --git a/h5p/tests/file_storage_test.php b/h5p/tests/file_storage_test.php
index cbf0ee5a13eb..a1f9b5c290a5 100644
--- a/h5p/tests/file_storage_test.php
+++ b/h5p/tests/file_storage_test.php
@@ -69,11 +69,9 @@ protected function setUp(): void {
// Get value of protected properties.
$h5p_fs_rc = new \ReflectionClass(file_storage::class);
$h5p_file_storage_context = $h5p_fs_rc->getProperty('context');
- $h5p_file_storage_context->setAccessible(true);
$this->h5p_fs_context = $h5p_file_storage_context->getValue($this->h5p_file_storage);
$h5p_file_storage_fs = $h5p_fs_rc->getProperty('fs');
- $h5p_file_storage_fs->setAccessible(true);
$this->h5p_fs_fs = $h5p_file_storage_fs->getValue($this->h5p_file_storage);
}
@@ -625,7 +623,6 @@ public function test_get_file(): void {
// Set get_file method accessibility.
$method = new ReflectionMethod(file_storage::class, 'get_file');
- $method->setAccessible(true);
$contentfile = $method->invoke(new file_storage(), file_storage::CONTENT_FILEAREA, $h5pcontentid, $file);
@@ -668,7 +665,6 @@ public function test_move_file(): void {
// Set get_file method accessibility.
$method = new ReflectionMethod(file_storage::class, 'move_file');
- $method->setAccessible(true);
$method->invoke(new file_storage(), $file, $h5pcontentid);
diff --git a/h5p/tests/generator/lib.php b/h5p/tests/generator/lib.php
index 3bfefc0df85f..79edfec2e12e 100644
--- a/h5p/tests/generator/lib.php
+++ b/h5p/tests/generator/lib.php
@@ -554,7 +554,6 @@ public function create_export_file(string $filename, int $contextid,
// Call the method. We need the id of the new H5P content.
$rc = new \ReflectionClass(player::class);
$rcp = $rc->getProperty('h5pid');
- $rcp->setAccessible(true);
$h5pid = $rcp->getValue($h5pplayer);
// Get the info export file.
diff --git a/lang/en/admin.php b/lang/en/admin.php
index 9f7ea6d93f49..624f5604f053 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -1314,6 +1314,7 @@
$string['sixtyfourbitswarning'] = 'It has been detected that your site is not using a 64-bit PHP version. It is recommended that you upgrade your site to ensure future compatibility.';
$string['slasharguments'] = 'Use slash arguments';
$string['slashargumentswarning'] = 'It is recommended that the use of slash arguments is enabled. In future it will be required. For more details, see the documentation Using slash arguments.';
+$string['smallscreensonly'] = 'Small screens only';
$string['smtp'] = 'SMTP';
$string['smtpauthtype'] = 'SMTP Auth Type';
$string['smtpdetail'] = 'Simple Mail Transfer Protocol (SMTP) settings for sending email.';
diff --git a/lang/en/auth.php b/lang/en/auth.php
index c73816c063c1..2a42ae444a10 100644
--- a/lang/en/auth.php
+++ b/lang/en/auth.php
@@ -41,6 +41,8 @@
$string['auth_changingemailaddress'] = 'You have requested a change of email address, from {$a->oldemail} to {$a->newemail}. For security reasons, we are sending you an email message at the new address to confirm that it belongs to you. Your email address will be updated as soon as you open the URL sent to you in that message.';
$string['authinstructions'] = 'Leave this blank for the default login instructions to be displayed on the login page. If you want to provide custom login instructions, enter them here.';
$string['auth_invalidnewemailkey'] = 'Error: if you are trying to confirm a change of email address, you may have made a mistake in copying the URL we sent you by email. Please copy the address and try again.';
+$string['auth_loginpasswordtoggle'] = 'Password visibility toggle';
+$string['auth_loginpasswordtoggle_desc'] = 'Add an icon to the password field on the login screen that allows users to show or hide their entered password.';
$string['auth_loginrecaptcha'] = 'Enable reCAPTCHA for login';
$string['auth_loginrecaptcha_desc'] = 'Add a visual/audio confirmation form element to the login page. This reduces the risk of unwarranted login attempts. See Google reCAPTCHA for more details. ';
$string['auth_multiplehosts'] = 'Multiple hosts OR addresses can be specified (eg host1.com;host2.com;host3.com) or (eg xxx.xxx.xxx.xxx;xxx.xxx.xxx.xxx)';
diff --git a/lang/en/courseformat.php b/lang/en/courseformat.php
index c6d44e39964d..b6135aaeb065 100644
--- a/lang/en/courseformat.php
+++ b/lang/en/courseformat.php
@@ -47,6 +47,7 @@
$string['cm_show_feedback'] = '{$a->name} is now shown.';
$string['cm_show_feedback_batch'] = 'The selected {$a->count} activities are now shown.';
$string['cm_stealth_feedback'] = '{$a->name} is now available but not shown on the course page.';
+$string['cm_stealth_feedback_batch'] = 'The selected {$a->count} activities are now available but not shown on the course page.';
$string['cm_visiblegroups_feedback'] = '{$a->name} group mode changed to Visible groups.';
$string['cmavailability'] = 'Activity availability';
$string['cmdelete_info'] = 'This will delete {$a->name} and any user data it contains.';
diff --git a/lang/en/form.php b/lang/en/form.php
index 440997cb63ee..0ddade386d02 100644
--- a/lang/en/form.php
+++ b/lang/en/form.php
@@ -87,5 +87,6 @@
$string['time'] = 'Time';
$string['timeunit'] = 'Time unit';
$string['timing'] = 'Timing';
+$string['togglesensitive'] = 'Toggle sensitive';
$string['unmaskpassword'] = 'Unmask';
$string['year'] = 'Year';
diff --git a/lib/amd/build/togglesensitive.min.js b/lib/amd/build/togglesensitive.min.js
new file mode 100644
index 000000000000..7a14a4543d42
--- /dev/null
+++ b/lib/amd/build/togglesensitive.min.js
@@ -0,0 +1,10 @@
+define("core/togglesensitive",["exports","core/pagehelpers","core/templates","core/pending","core/prefetch","core/notification","core_form/events"],(function(_exports,_pagehelpers,_templates,_pending,_prefetch,_notification,_events){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
+/**
+ * JS module for toggling the sensitive input visibility (e.g. passwords, keys).
+ *
+ * @module core/togglesensitive
+ * @copyright 2023 David Woloszyn
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_templates=_interopRequireDefault(_templates),_pending=_interopRequireDefault(_pending),_prefetch=_interopRequireDefault(_prefetch),_notification=_interopRequireDefault(_notification);const SELECTORS_BUTTON=".toggle-sensitive-btn",PIX_EYE="t/hide",PIX_EYE_SLASH="t/show";let sensitiveElementId,smallScreensOnly;_exports.init=function(elementId){let isSmallScreensOnly=arguments.length>1&&void 0!==arguments[1]&&arguments[1];const sensitiveInput=document.getElementById(elementId);null!==sensitiveInput&&(sensitiveElementId=elementId,smallScreensOnly=isSmallScreensOnly,_prefetch.default.prefetchTemplate("core/form_input_toggle_sensitive"),renderSensitiveToggle(sensitiveInput),registerListenerEvents())};const renderSensitiveToggle=sensitiveInput=>{_templates.default.render("core/form_input_toggle_sensitive",{smallscreensonly:smallScreensOnly,sensitiveinput:sensitiveInput.outerHTML}).then((html=>{sensitiveInput.outerHTML=html,(0,_events.notifyFieldStructureChanged)(sensitiveInput.id)})).catch(_notification.default.exception)},registerListenerEvents=()=>{document.addEventListener("click",handleButtonInteraction),smallScreensOnly&&window.addEventListener("resize",handleScreenResizing)},handleButtonInteraction=event=>{const toggleButton=event.target.closest(SELECTORS_BUTTON);if(toggleButton){const sensitiveInput=document.getElementById(sensitiveElementId);sensitiveInput&&toggleSensitiveVisibility(sensitiveInput,toggleButton)}},handleScreenResizing=()=>{if(!(0,_pagehelpers.isExtraSmall)()){const sensitiveInput=document.getElementById(sensitiveElementId);if(sensitiveInput){const toggleButton=sensitiveInput.parentNode.querySelector(SELECTORS_BUTTON);toggleButton&&toggleSensitiveVisibility(sensitiveInput,toggleButton,!0)}}},toggleSensitiveVisibility=function(sensitiveInput,toggleButton){let force=arguments.length>2&&void 0!==arguments[2]&&arguments[2];const pendingPromise=new _pending.default("core/togglesensitive:toggle");let type,icon;!0===force?(type="password",icon=PIX_EYE):(type="password"===sensitiveInput.getAttribute("type")?"text":"password",icon="password"===sensitiveInput.getAttribute("type")?PIX_EYE_SLASH:PIX_EYE),sensitiveInput.setAttribute("type",type),_templates.default.renderPix(icon,"core").then((icon=>{toggleButton.innerHTML=icon,pendingPromise.resolve()})).catch(_notification.default.exception)}}));
+
+//# sourceMappingURL=togglesensitive.min.js.map
\ No newline at end of file
diff --git a/lib/amd/build/togglesensitive.min.js.map b/lib/amd/build/togglesensitive.min.js.map
new file mode 100644
index 000000000000..dfedebd5e21c
--- /dev/null
+++ b/lib/amd/build/togglesensitive.min.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"togglesensitive.min.js","sources":["../src/togglesensitive.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * JS module for toggling the sensitive input visibility (e.g. passwords, keys).\n *\n * @module core/togglesensitive\n * @copyright 2023 David Woloszyn \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {isExtraSmall} from 'core/pagehelpers';\nimport Templates from 'core/templates';\nimport Pending from 'core/pending';\nimport Prefetch from 'core/prefetch';\nimport Notification from 'core/notification';\nimport {notifyFieldStructureChanged} from 'core_form/events';\n\nconst SELECTORS = {\n BUTTON: '.toggle-sensitive-btn',\n ICON: '.toggle-sensitive-btn .icon',\n};\n\nconst PIX = {\n EYE: 't/hide',\n EYE_SLASH: 't/show',\n};\n\nlet sensitiveElementId;\nlet smallScreensOnly;\n\n/**\n * Entrypoint of the js.\n *\n * @method init\n * @param {String} elementId Form button element.\n * @param {boolean} isSmallScreensOnly Is this for small screens only?\n */\nexport const init = (elementId, isSmallScreensOnly = false) => {\n const sensitiveInput = document.getElementById(elementId);\n if (sensitiveInput === null) {\n // Exit early if invalid element id passed.\n return;\n }\n sensitiveElementId = elementId;\n smallScreensOnly = isSmallScreensOnly;\n Prefetch.prefetchTemplate('core/form_input_toggle_sensitive');\n // Render the sensitive input with a toggle button.\n renderSensitiveToggle(sensitiveInput);\n // Register event listeners.\n registerListenerEvents();\n};\n\n/**\n * Render the new input html with toggle button and update the incoming html.\n *\n * @method renderSensitiveToggle\n * @param {HTMLElement} sensitiveInput HTML element for the sensitive input.\n */\nconst renderSensitiveToggle = (sensitiveInput) => {\n Templates.render(\n 'core/form_input_toggle_sensitive',\n {\n smallscreensonly: smallScreensOnly,\n sensitiveinput: sensitiveInput.outerHTML,\n }\n ).then((html) => {\n sensitiveInput.outerHTML = html;\n // Dispatch the event indicating the sensitive input has changed.\n notifyFieldStructureChanged(sensitiveInput.id);\n return;\n }).catch(Notification.exception);\n};\n\n/**\n * Register event listeners.\n *\n * @method registerListenerEvents\n */\nconst registerListenerEvents = () => {\n // Toggle the sensitive input visibility when interacting with the toggle button.\n document.addEventListener('click', handleButtonInteraction);\n // For small screens only, hide all sensitive inputs when the screen is enlarged.\n if (smallScreensOnly) {\n window.addEventListener('resize', handleScreenResizing);\n }\n};\n\n/**\n * Handle events trigger by interacting with the toggle button.\n *\n * @method handleButtonInteraction\n * @param {Event} event The button event.\n */\nconst handleButtonInteraction = (event) => {\n const toggleButton = event.target.closest(SELECTORS.BUTTON);\n if (toggleButton) {\n const sensitiveInput = document.getElementById(sensitiveElementId);\n if (sensitiveInput) {\n toggleSensitiveVisibility(sensitiveInput, toggleButton);\n }\n }\n};\n\n/**\n * Handle events trigger by resizing the screen.\n *\n * @method handleScreenResizing\n */\nconst handleScreenResizing = () => {\n if (!isExtraSmall()) {\n const sensitiveInput = document.getElementById(sensitiveElementId);\n if (sensitiveInput) {\n const toggleButton = sensitiveInput.parentNode.querySelector(SELECTORS.BUTTON);\n if (toggleButton) {\n toggleSensitiveVisibility(sensitiveInput, toggleButton, true);\n }\n }\n }\n};\n\n/**\n * Toggle the sensitive input visibility and its associated icon.\n *\n * @method toggleSensitiveVisibility\n * @param {HTMLInputElement} sensitiveInput The sensitive input element.\n * @param {HTMLElement} toggleButton The toggle button.\n * @param {boolean} force Force the input back to password type.\n */\nconst toggleSensitiveVisibility = (sensitiveInput, toggleButton, force = false) => {\n const pendingPromise = new Pending('core/togglesensitive:toggle');\n let type;\n let icon;\n if (force === true) {\n type = 'password';\n icon = PIX.EYE;\n } else {\n type = sensitiveInput.getAttribute('type') === 'password' ? 'text' : 'password';\n icon = sensitiveInput.getAttribute('type') === 'password' ? PIX.EYE_SLASH : PIX.EYE;\n }\n sensitiveInput.setAttribute('type', type);\n Templates.renderPix(icon, 'core').then((icon) => {\n toggleButton.innerHTML = icon;\n pendingPromise.resolve();\n return;\n }).catch(Notification.exception);\n};\n"],"names":["SELECTORS","PIX","sensitiveElementId","smallScreensOnly","elementId","isSmallScreensOnly","sensitiveInput","document","getElementById","prefetchTemplate","renderSensitiveToggle","registerListenerEvents","render","smallscreensonly","sensitiveinput","outerHTML","then","html","id","catch","Notification","exception","addEventListener","handleButtonInteraction","window","handleScreenResizing","event","toggleButton","target","closest","toggleSensitiveVisibility","parentNode","querySelector","force","pendingPromise","Pending","type","icon","getAttribute","setAttribute","renderPix","innerHTML","resolve"],"mappings":";;;;;;;gRA8BMA,iBACM,wBAINC,QACG,SADHA,cAES,aAGXC,mBACAC,+BASgB,SAACC,eAAWC,iFACtBC,eAAiBC,SAASC,eAAeJ,WACxB,OAAnBE,iBAIJJ,mBAAqBE,UACrBD,iBAAmBE,qCACVI,iBAAiB,oCAE1BC,sBAAsBJ,gBAEtBK,iCASED,sBAAyBJ,oCACjBM,OACN,mCACA,CACIC,iBAAkBV,iBAClBW,eAAgBR,eAAeS,YAErCC,MAAMC,OACJX,eAAeS,UAAYE,6CAECX,eAAeY,OAE5CC,MAAMC,sBAAaC,YAQpBV,uBAAyB,KAE3BJ,SAASe,iBAAiB,QAASC,yBAE/BpB,kBACAqB,OAAOF,iBAAiB,SAAUG,uBAUpCF,wBAA2BG,cACvBC,aAAeD,MAAME,OAAOC,QAAQ7B,qBACtC2B,aAAc,OACRrB,eAAiBC,SAASC,eAAeN,oBAC3CI,gBACAwB,0BAA0BxB,eAAgBqB,gBAUhDF,qBAAuB,UACpB,+BAAgB,OACXnB,eAAiBC,SAASC,eAAeN,uBAC3CI,eAAgB,OACVqB,aAAerB,eAAeyB,WAAWC,cAAchC,kBACzD2B,cACAG,0BAA0BxB,eAAgBqB,cAAc,MAclEG,0BAA4B,SAACxB,eAAgBqB,kBAAcM,oEACvDC,eAAiB,IAAIC,iBAAQ,mCAC/BC,KACAC,MACU,IAAVJ,OACAG,KAAO,WACPC,KAAOpC,UAEPmC,KAA+C,aAAxC9B,eAAegC,aAAa,QAAyB,OAAS,WACrED,KAA+C,aAAxC/B,eAAegC,aAAa,QAAyBrC,cAAgBA,SAEhFK,eAAeiC,aAAa,OAAQH,yBAC1BI,UAAUH,KAAM,QAAQrB,MAAMqB,OACpCV,aAAac,UAAYJ,KACzBH,eAAeQ,aAEhBvB,MAAMC,sBAAaC"}
\ No newline at end of file
diff --git a/lib/amd/src/togglesensitive.js b/lib/amd/src/togglesensitive.js
new file mode 100644
index 000000000000..19d2bf03783e
--- /dev/null
+++ b/lib/amd/src/togglesensitive.js
@@ -0,0 +1,159 @@
+// 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 .
+
+/**
+ * JS module for toggling the sensitive input visibility (e.g. passwords, keys).
+ *
+ * @module core/togglesensitive
+ * @copyright 2023 David Woloszyn
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+import {isExtraSmall} from 'core/pagehelpers';
+import Templates from 'core/templates';
+import Pending from 'core/pending';
+import Prefetch from 'core/prefetch';
+import Notification from 'core/notification';
+import {notifyFieldStructureChanged} from 'core_form/events';
+
+const SELECTORS = {
+ BUTTON: '.toggle-sensitive-btn',
+ ICON: '.toggle-sensitive-btn .icon',
+};
+
+const PIX = {
+ EYE: 't/hide',
+ EYE_SLASH: 't/show',
+};
+
+let sensitiveElementId;
+let smallScreensOnly;
+
+/**
+ * Entrypoint of the js.
+ *
+ * @method init
+ * @param {String} elementId Form button element.
+ * @param {boolean} isSmallScreensOnly Is this for small screens only?
+ */
+export const init = (elementId, isSmallScreensOnly = false) => {
+ const sensitiveInput = document.getElementById(elementId);
+ if (sensitiveInput === null) {
+ // Exit early if invalid element id passed.
+ return;
+ }
+ sensitiveElementId = elementId;
+ smallScreensOnly = isSmallScreensOnly;
+ Prefetch.prefetchTemplate('core/form_input_toggle_sensitive');
+ // Render the sensitive input with a toggle button.
+ renderSensitiveToggle(sensitiveInput);
+ // Register event listeners.
+ registerListenerEvents();
+};
+
+/**
+ * Render the new input html with toggle button and update the incoming html.
+ *
+ * @method renderSensitiveToggle
+ * @param {HTMLElement} sensitiveInput HTML element for the sensitive input.
+ */
+const renderSensitiveToggle = (sensitiveInput) => {
+ Templates.render(
+ 'core/form_input_toggle_sensitive',
+ {
+ smallscreensonly: smallScreensOnly,
+ sensitiveinput: sensitiveInput.outerHTML,
+ }
+ ).then((html) => {
+ sensitiveInput.outerHTML = html;
+ // Dispatch the event indicating the sensitive input has changed.
+ notifyFieldStructureChanged(sensitiveInput.id);
+ return;
+ }).catch(Notification.exception);
+};
+
+/**
+ * Register event listeners.
+ *
+ * @method registerListenerEvents
+ */
+const registerListenerEvents = () => {
+ // Toggle the sensitive input visibility when interacting with the toggle button.
+ document.addEventListener('click', handleButtonInteraction);
+ // For small screens only, hide all sensitive inputs when the screen is enlarged.
+ if (smallScreensOnly) {
+ window.addEventListener('resize', handleScreenResizing);
+ }
+};
+
+/**
+ * Handle events trigger by interacting with the toggle button.
+ *
+ * @method handleButtonInteraction
+ * @param {Event} event The button event.
+ */
+const handleButtonInteraction = (event) => {
+ const toggleButton = event.target.closest(SELECTORS.BUTTON);
+ if (toggleButton) {
+ const sensitiveInput = document.getElementById(sensitiveElementId);
+ if (sensitiveInput) {
+ toggleSensitiveVisibility(sensitiveInput, toggleButton);
+ }
+ }
+};
+
+/**
+ * Handle events trigger by resizing the screen.
+ *
+ * @method handleScreenResizing
+ */
+const handleScreenResizing = () => {
+ if (!isExtraSmall()) {
+ const sensitiveInput = document.getElementById(sensitiveElementId);
+ if (sensitiveInput) {
+ const toggleButton = sensitiveInput.parentNode.querySelector(SELECTORS.BUTTON);
+ if (toggleButton) {
+ toggleSensitiveVisibility(sensitiveInput, toggleButton, true);
+ }
+ }
+ }
+};
+
+/**
+ * Toggle the sensitive input visibility and its associated icon.
+ *
+ * @method toggleSensitiveVisibility
+ * @param {HTMLInputElement} sensitiveInput The sensitive input element.
+ * @param {HTMLElement} toggleButton The toggle button.
+ * @param {boolean} force Force the input back to password type.
+ */
+const toggleSensitiveVisibility = (sensitiveInput, toggleButton, force = false) => {
+ const pendingPromise = new Pending('core/togglesensitive:toggle');
+ let type;
+ let icon;
+ if (force === true) {
+ type = 'password';
+ icon = PIX.EYE;
+ } else {
+ type = sensitiveInput.getAttribute('type') === 'password' ? 'text' : 'password';
+ icon = sensitiveInput.getAttribute('type') === 'password' ? PIX.EYE_SLASH : PIX.EYE;
+ }
+ sensitiveInput.setAttribute('type', type);
+ Templates.renderPix(icon, 'core').then((icon) => {
+ toggleButton.innerHTML = icon;
+ pendingPromise.resolve();
+ return;
+ }).catch(Notification.exception);
+};
diff --git a/lib/behat/classes/named_selector.php b/lib/behat/classes/named_selector.php
index e683ffcf2913..b390b7590942 100644
--- a/lib/behat/classes/named_selector.php
+++ b/lib/behat/classes/named_selector.php
@@ -58,7 +58,6 @@ public function register_component_selector(string $component, behat_component_n
// This is due to an API limitation in Mink.
$rc = new \ReflectionClass(\Behat\Mink\Selector\NamedSelector::class);
$r = $rc->getProperty('replacements');
- $r->setAccessible(true);
$replacements = $r->getValue($this);
$selectorxpath = strtr($selector->get_combined_xpath(), $replacements);
@@ -77,7 +76,6 @@ public function register_replacement(string $component, behat_component_named_re
// This is due to an API limitation in Mink.
$rc = new \ReflectionClass(\Behat\Mink\Selector\NamedSelector::class);
$r = $rc->getProperty('replacements');
- $r->setAccessible(true);
$existing = $r->getValue($this);
$from = $replacement->get_from($component);
diff --git a/lib/classes/deprecated.php b/lib/classes/attribute/deprecated.php
similarity index 79%
rename from lib/classes/deprecated.php
rename to lib/classes/attribute/deprecated.php
index deb278abe94b..c68317bdf397 100644
--- a/lib/classes/deprecated.php
+++ b/lib/classes/attribute/deprecated.php
@@ -14,9 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-namespace core;
-
-use Attribute;
+namespace core\attribute;
/**
* Attribute to describe a deprecated item.
@@ -25,7 +23,7 @@
* @copyright 2023 Andrew Lyons
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-#[Attribute]
+#[\Attribute]
class deprecated {
/**
* A deprecated item.
@@ -34,20 +32,25 @@ class deprecated {
*
* Note: The mere presence of the attribute does not do anything. It must be checked by some part of the code.
*
- * @param mixed $descriptor A brief descriptor of the thing that was deprecated.
+ * @param null|string $replacement Any replacement for the deprecated thing
* @param null|string $since When it was deprecated
* @param null|string $reason Why it was deprecated
- * @param null|string $replacement Any replacement for the deprecated thing
* @param null|string $mdl Link to the Moodle Tracker issue for more information
+ * @param bool $final Whether this is a final deprecation
+ * @param bool $emit Whether to emit a deprecation warning
*/
public function __construct(
- public readonly mixed $descriptor,
+ public readonly ?string $replacement,
public readonly ?string $since = null,
public readonly ?string $reason = null,
- public readonly ?string $replacement = null,
public readonly ?string $mdl = null,
public readonly bool $final = false,
public readonly bool $emit = true,
) {
+ if ($replacement === null && $reason === null && $mdl === null) {
+ throw new \coding_exception(
+ 'A deprecated item which is not deprecated must provide a reason, or an issue number.',
+ );
+ }
}
}
diff --git a/lib/classes/attribute/deprecated_with_reference.php b/lib/classes/attribute/deprecated_with_reference.php
new file mode 100644
index 000000000000..751cd8f111ec
--- /dev/null
+++ b/lib/classes/attribute/deprecated_with_reference.php
@@ -0,0 +1,58 @@
+.
+
+namespace core\attribute;
+
+/**
+ * Attribute to describe a deprecated item which contains a reference to the owning feature.
+ *
+ * @package core
+ * @copyright 2023 Andrew Lyons
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class deprecated_with_reference extends deprecated {
+ /**
+ * A deprecated item which also includes a reference to the owning feature.
+ *
+ * This attribute is not expected to be used more generally. It is an internal feature.
+ *
+ * @param string $owner The code which owns the usage
+ * @param null|string $replacement Any replacement for the deprecated thing
+ * @param null|string $since When it was deprecated
+ * @param null|string $reason Why it was deprecated
+ * @param null|string $mdl Link to the Moodle Tracker issue for more information
+ * @param bool $final Whether this is a final deprecation
+ * @param bool $emit Whether to emit a deprecation warning
+ */
+ public function __construct(
+ public readonly string $owner,
+ ?string $replacement,
+ ?string $since,
+ ?string $reason,
+ ?string $mdl,
+ bool $final,
+ bool $emit,
+ ) {
+ parent::__construct(
+ replacement: $replacement,
+ since: $since,
+ reason: $reason,
+ mdl: $mdl,
+ final: $final,
+ emit: $emit,
+ );
+ }
+}
diff --git a/lib/classes/deprecation.php b/lib/classes/deprecation.php
index b71fd502d9b6..e11b12058ac3 100644
--- a/lib/classes/deprecation.php
+++ b/lib/classes/deprecation.php
@@ -16,6 +16,9 @@
namespace core;
+use core\attribute\deprecated;
+use core\attribute\deprecated_with_reference;
+
/**
* Deprecation utility.
*
@@ -42,17 +45,14 @@ public static function from(array|string|object $reference): ?deprecated {
return self::from(explode('::', $reference));
}
- if (class_exists($reference)) {
+ if (class_exists($reference) || interface_exists($reference) || trait_exists($reference)) {
// The reference looks to be a class name.
return self::from([$reference]);
}
if (function_exists($reference)) {
// The reference looks to be a global function.
- $ref = new \ReflectionFunction($reference);
- if ($attributes = $ref->getAttributes(deprecated::class)) {
- return $attributes[0]->newInstance();
- }
+ return self::get_attribute(new \ReflectionFunction($reference), $reference);
}
return null;
@@ -75,14 +75,45 @@ public static function from(array|string|object $reference): ?deprecated {
return self::from_reflected_object($rc, $reference[1] ?? null);
}
- if (is_string($reference[0]) && class_exists($reference[0])) {
- $rc = new \ReflectionClass($reference[0]);
- return self::from_reflected_object($rc, $reference[1] ?? null);
+ if (is_string($reference[0])) {
+ if (class_exists($reference[0]) || interface_exists($reference[0]) || trait_exists($reference[0])) {
+ $rc = new \ReflectionClass($reference[0]);
+ return self::from_reflected_object($rc, $reference[1] ?? null);
+ }
}
// The reference is an array, but it's not an object or a class that currently exists.
return null;
}
+
+ // The reference is none of the above.
+ return null;
+ }
+
+ /**
+ * Get a deprecation attribute from a reflector.
+ *
+ * @param \Reflector $ref The reflector
+ * @param string $owner A descriptor of the owner of the thing that is deprecated
+ * @return null|deprecated_with_reference
+ */
+ protected static function get_attribute(
+ \Reflector $ref,
+ string $owner,
+ ): ?deprecated_with_reference {
+ if ($attributes = $ref->getAttributes(deprecated::class)) {
+ $attribute = $attributes[0]->newInstance();
+ return new deprecated_with_reference(
+ owner: $owner,
+ replacement: $attribute->replacement,
+ since: $attribute->since,
+ reason: $attribute->reason,
+ mdl: $attribute->mdl,
+ final: $attribute->final,
+ emit: $attribute->emit,
+ );
+ }
+ return null;
}
/**
@@ -107,47 +138,59 @@ public static function emit_deprecation_if_present(array|string|object $referenc
}
/**
- * Fetch a deprecation attribute from a reflected object.
+ * Fetch a referenced deprecation attribute from a reflected object.
*
* @param \ReflectionClass $rc The reflected object
* @param null|string $name The name of the thing to check for deprecation
- * @return null|deprecated
+ * @return null|deprecated_with_reference
*/
protected static function from_reflected_object(
\ReflectionClass $rc,
?string $name,
- ): ?deprecated {
- if ($name === null) {
- // No name specified. This may be a deprecated class.
- if ($attributes = $rc->getAttributes(deprecated::class)) {
- return $attributes[0]->newInstance();
+ ): ?deprecated_with_reference {
+ // Check if the class itself is deprecated first.
+ $classattribute = self::get_attribute($rc, $rc->name);
+ if ($classattribute || $name === null) {
+ return $classattribute;
+ }
+
+ // Check for any deprecated interfaces.
+ foreach ($rc->getInterfaces() as $interface) {
+ if ($attribute = self::get_attribute($interface, $interface->name)) {
+ return $attribute;
+ }
+ }
+
+ // And any deprecated traits.
+ foreach ($rc->getTraits() as $trait) {
+ if ($attribute = self::get_attribute($trait, $trait->name)) {
+ return $attribute;
}
- return null;
}
if ($rc->hasConstant($name)) {
// This class has a constant with the specified name.
// Note: This also applies to enums.
- $ref = $rc->getReflectionConstant($name);
- if ($attributes = $ref->getAttributes(deprecated::class)) {
- return $attributes[0]->newInstance();
- }
+ return self::get_attribute(
+ $rc->getReflectionConstant($name),
+ "{$rc->name}::{$name}",
+ );
}
if ($rc->hasMethod($name)) {
// This class has a method with the specified name.
- $ref = $rc->getMethod($name);
- if ($attributes = $ref->getAttributes(deprecated::class)) {
- return $attributes[0]->newInstance();
- }
+ return self::get_attribute(
+ $rc->getMethod($name),
+ "{$rc->name}::{$name}",
+ );
}
if ($rc->hasProperty($name)) {
// This class has a property with the specified name.
- $ref = $rc->getProperty($name);
- if ($attributes = $ref->getAttributes(deprecated::class)) {
- return $attributes[0]->newInstance();
- }
+ return self::get_attribute(
+ $rc->getProperty($name),
+ "{$rc->name}::{$name}",
+ );
}
return null;
@@ -157,10 +200,19 @@ protected static function from_reflected_object(
* Get a string describing the deprecation.
*
* @param deprecated $attribute
+ * @param string $owner
* @return string
*/
- public static function get_deprecation_string(deprecated $attribute): string {
- $output = "Deprecation: {$attribute->descriptor} has been deprecated";
+ public static function get_deprecation_string(
+ deprecated $attribute,
+ ): string {
+ $output = "Deprecation:";
+
+ if ($attribute instanceof deprecated_with_reference) {
+ $output .= " {$attribute->owner}";
+ }
+ $output .= " has been deprecated";
+
if ($attribute->since) {
$output .= " since {$attribute->since}";
}
@@ -187,7 +239,9 @@ public static function get_deprecation_string(deprecated $attribute): string {
*
* @param deprecated $attribute
*/
- public static function emit_deprecation_notice(deprecated $attribute): void {
+ protected static function emit_deprecation_notice(
+ deprecated $attribute,
+ ): void {
if (!$attribute->emit) {
return;
}
diff --git a/lib/classes/hook/output/standard_head_html_prepend.php b/lib/classes/hook/output/before_standard_head_html_generation.php
similarity index 82%
rename from lib/classes/hook/output/standard_head_html_prepend.php
rename to lib/classes/hook/output/before_standard_head_html_generation.php
index 5a4ac7d0c567..4a2e99ac9b40 100644
--- a/lib/classes/hook/output/standard_head_html_prepend.php
+++ b/lib/classes/hook/output/before_standard_head_html_generation.php
@@ -26,19 +26,25 @@
#[\core\attribute\tags('output')]
#[\core\attribute\label('Allows plugins to add any elements to the page <head> html tag.')]
#[\core\attribute\hook\replaces_callbacks('before_standard_html_head')]
-class standard_head_html_prepend {
- /** @var string $output Stores results from callbacks */
- private $output = '';
+final class before_standard_head_html_generation {
+ public function __construct(
+ /** @var \renderer_base The core_renderer instance used for the generation */
+ public readonly \renderer_base $renderer,
+ private string $output = '',
+ ) {
+ }
/**
* Plugins implementing callback can add any HTML to the page.
*
* Must be a string containing valid html head content
*
- * @param string $output
+ * @param null|string $output
*/
- public function add_html(string $output): void {
- $this->output .= $output;
+ public function add_html(?string $output): void {
+ if ($output) {
+ $this->output .= $output;
+ }
}
/**
diff --git a/lib/classes/param.php b/lib/classes/param.php
index 359ffc37b293..9c817ff4f5b2 100644
--- a/lib/classes/param.php
+++ b/lib/classes/param.php
@@ -18,6 +18,7 @@
use coding_exception;
use core_text;
+use core\attribute\deprecated;
use core\ip_utils;
use invalid_parameter_exception;
use moodle_exception;
@@ -222,9 +223,9 @@ enum param: string {
* @deprecated since 2.0
*/
#[deprecated(
- 'param::CLEAN',
+ replacement: 'a more specific type of parameter',
since: '2.0',
- reason: 'Please use a more specific type of parameter',
+ reason: 'The CLEAN param type is too generic to perform satisfactory validation',
emit: false,
)]
case CLEAN = 'clean';
@@ -234,7 +235,7 @@ enum param: string {
* @deprecated since 2.0
*/
#[deprecated(
- 'param::INTEGER',
+ replacement: 'param::INT',
since: '2.0',
reason: 'Alias for INT',
final: true,
@@ -246,7 +247,7 @@ enum param: string {
* @deprecated since 2.0
*/
#[deprecated(
- 'param::NUMBER',
+ replacement: 'param::FLOAT',
since: '2.0',
reason: 'Alias for FLOAT',
final: true,
@@ -259,7 +260,7 @@ enum param: string {
* @deprecated since 2.0
*/
#[deprecated(
- 'param::ACTION',
+ replacement: 'param::ALPHANUMEXT',
since: '2.0',
reason: 'Alias for PARAM_ALPHANUMEXT',
final: true,
@@ -272,7 +273,7 @@ enum param: string {
* @deprecated since 2.0
*/
#[deprecated(
- 'param::FORMAT',
+ replacement: 'param::ALPHANUMEXT',
since: '2.0',
reason: 'Alias for PARAM_ALPHANUMEXT',
final: true,
@@ -284,7 +285,7 @@ enum param: string {
* @deprecated since 2.0
*/
#[deprecated(
- 'param::MULTILANG',
+ replacement: 'param::TEXT',
since: '2.0',
reason: 'Alias for PARAM_TEXT',
final: true,
@@ -303,7 +304,7 @@ enum param: string {
* @deprecated since 2.0
*/
#[deprecated(
- 'param::CLEANFILE',
+ replacement: 'param::FILE',
since: '2.0',
reason: 'Alias for PARAM_FILE',
)]
diff --git a/lib/classes/scss.php b/lib/classes/scss.php
index 31d73536eb1b..301a7d65cddc 100644
--- a/lib/classes/scss.php
+++ b/lib/classes/scss.php
@@ -164,7 +164,6 @@ protected function compileChild($child, \ScssPhp\ScssPhp\Formatter\OutputBlock $
// We need to find the import path relative to the directory of the currently processed file.
$currentdirectory = new ReflectionProperty(\ScssPhp\ScssPhp\Compiler::class, 'currentDirectory');
- $currentdirectory->setAccessible(true);
if ($path = $this->findImport($path, $currentdirectory->getValue($this))) {
if ($this->is_valid_file($path)) {
diff --git a/lib/db/services.php b/lib/db/services.php
index 672509c38b34..1886f7de5976 100644
--- a/lib/db/services.php
+++ b/lib/db/services.php
@@ -1706,13 +1706,6 @@
'capabilities' => 'moodle/question:flag',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
- 'core_question_submit_tags_form' => array(
- 'classname' => 'core_question_external',
- 'methodname' => 'submit_tags_form',
- 'description' => 'Update the question tags.',
- 'type' => 'write',
- 'ajax' => true,
- ),
'core_question_get_random_question_summaries' => array(
'classname' => 'core_question_external',
'methodname' => 'get_random_question_summaries',
diff --git a/lib/ddl/tests/ddl_test.php b/lib/ddl/tests/ddl_test.php
index 3dd3d07f22ac..85456aec28ef 100644
--- a/lib/ddl/tests/ddl_test.php
+++ b/lib/ddl/tests/ddl_test.php
@@ -1885,7 +1885,6 @@ public function test_leftover_temp_tables_cache() {
$rc = new \ReflectionClass('moodle_database');
$rcm = $rc->getMethod('get_temp_tables_cache');
- $rcm->setAccessible(true);
$metacachetemp = $rcm->invokeArgs($DB, []);
// Data of test_table0 should be removed from the cache.
@@ -1896,7 +1895,6 @@ public function test_leftover_temp_tables_cache() {
$rc = new \ReflectionClass('moodle_database');
$rcm = $rc->getMethod('get_metacache');
- $rcm->setAccessible(true);
$metacache = $rcm->invokeArgs($DB, []);
// Data of test_table2 should be intact.
diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php
index 1f29fd436699..409a16a41878 100644
--- a/lib/deprecatedlib.php
+++ b/lib/deprecatedlib.php
@@ -3125,3 +3125,94 @@ function random_bytes_emulate($length) {
);
return random_bytes($length);
}
+
+/**
+ * @deprecated since Moodle 4.0
+ */
+function question_preview_url() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
+
+/**
+ * @deprecated since Moodle 4.0
+ */
+function question_preview_popup_params() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
+
+/**
+ * @deprecated since Moodle 4.0
+ */
+function question_hash() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
+
+/**
+ * @deprecated since Moodle 4.0 MDL-71573
+ */
+function question_make_export_url() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
+
+/**
+ * @deprecated since Moodle 4.0
+ */
+function question_get_export_single_question_url() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
+
+/**
+ * @deprecated since Moodle 4.0 MDL-71585
+ */
+function question_remove_stale_questions_from_category() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
+
+/**
+ * @deprecated since Moodle 4.0 MDL-71585
+ */
+function flatten_category_tree() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
+
+/**
+ * @deprecated since Moodle 4.0 MDL-71585
+ */
+function add_indented_names() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
+
+/**
+ * @deprecated since Moodle 4.0 MDL-71585
+ */
+function question_category_select_menu() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
+
+/**
+ * @deprecated since Moodle 4.0 MDL-71585
+ */
+function get_categories_for_contexts() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
+
+/**
+ * @deprecated since Moodle 4.0 MDL-71585
+ */
+function question_category_options() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
+
+/**
+ * @deprecated since Moodle 4.0 MDL-71585
+ */
+function question_add_context_in_key() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
+
+/**
+ * @deprecated since Moodle 4.0 MDL-71585
+ */
+function question_fix_top_names() {
+ throw new coding_exception(__FUNCTION__ . '() has been removed.');
+}
diff --git a/lib/dml/tests/dml_mysqli_read_slave_test.php b/lib/dml/tests/dml_mysqli_read_slave_test.php
index 7c797ebff4f3..681fca72d114 100644
--- a/lib/dml/tests/dml_mysqli_read_slave_test.php
+++ b/lib/dml/tests/dml_mysqli_read_slave_test.php
@@ -117,7 +117,6 @@ public function test_aux_readonly(): void {
$rc = new \ReflectionClass(\mysqli_native_moodle_database::class);
$rcm = $rc->getMethod('insert_chunk_size');
- $rcm->setAccessible(true);
$rcm->invoke($db2);
$this->assertGreaterThan($reads, $reads = $db2->perf_get_reads());
$this->assertGreaterThan($readsprimary, $readsprimary = $reads - $db2->perf_get_reads_slave());
diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php
index 46fa06f032c9..653f158c3295 100644
--- a/lib/dml/tests/dml_test.php
+++ b/lib/dml/tests/dml_test.php
@@ -500,7 +500,7 @@ public function test_add_sql_debugging() {
$out = $fixture->four($sql);
$expected = <<invoke()
+-- line 64 of /lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php: call to ReflectionMethod->invoke()
EOD;
$this->assertEquals($this->unix_to_os_dirsep($expected), $out);
@@ -508,8 +508,8 @@ public function test_add_sql_debugging() {
$out = $fixture->four($sql);
$expected = <<invoke()
--- line 74 of /lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php: call to test_dml_sql_debugging_fixture->one()
+-- line 64 of /lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php: call to ReflectionMethod->invoke()
+-- line 73 of /lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php: call to test_dml_sql_debugging_fixture->one()
EOD;
$this->assertEquals($this->unix_to_os_dirsep($expected), $out);
@@ -517,10 +517,10 @@ public function test_add_sql_debugging() {
$out = $fixture->four($sql);
$expected = <<invoke()
--- line 74 of /lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php: call to test_dml_sql_debugging_fixture->one()
--- line 83 of /lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php: call to test_dml_sql_debugging_fixture->two()
--- line 92 of /lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php: call to test_dml_sql_debugging_fixture->three()
+-- line 64 of /lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php: call to ReflectionMethod->invoke()
+-- line 73 of /lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php: call to test_dml_sql_debugging_fixture->one()
+-- line 82 of /lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php: call to test_dml_sql_debugging_fixture->two()
+-- line 91 of /lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php: call to test_dml_sql_debugging_fixture->three()
-- line 517 of /lib/dml/tests/dml_test.php: call to test_dml_sql_debugging_fixture->four()
EOD;
$this->assertEquals($this->unix_to_os_dirsep($expected), $out);
@@ -6371,7 +6371,6 @@ public function test_get_server_info_dbfamily_mysql() {
$this->assertTrue(empty($cfg->dboptions['versionfromdb']));
$rc = new \ReflectionClass(\mysqli_native_moodle_database::class);
$rcm = $rc->getMethod('should_db_version_be_read_from_db');
- $rcm->setAccessible(true);
$this->assertFalse($rcm->invokeArgs($DB, []));
['description' => $description, 'version' => $version] = $DB->get_server_info();
diff --git a/lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php b/lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php
index 2aba9dead4c7..c29268c0e093 100644
--- a/lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php
+++ b/lib/dml/tests/fixtures/test_dml_sql_debugging_fixture.php
@@ -61,7 +61,6 @@ public function get_mock() {
*/
public function one(string $sql) {
$method = new \ReflectionMethod($this->db, 'add_sql_debugging');
- $method->setAccessible(true);
return $method->invoke($this->db, $sql);
}
diff --git a/lib/dml/tests/fixtures/test_moodle_read_slave_trait.php b/lib/dml/tests/fixtures/test_moodle_read_slave_trait.php
index 07d21d8ae885..6826c3d93625 100644
--- a/lib/dml/tests/fixtures/test_moodle_read_slave_trait.php
+++ b/lib/dml/tests/fixtures/test_moodle_read_slave_trait.php
@@ -53,7 +53,6 @@ public function __construct($external = false) {
$this->prefix = 'test_'; // Default, not to leave empty.
$rcp = new ReflectionProperty(parent::class, 'wantreadslave');
- $rcp->setAccessible(true);
$rcp->setValue($this, true);
$this->dbhwrite = $rw;
diff --git a/lib/dml/tests/mysqli_native_moodle_database_test.php b/lib/dml/tests/mysqli_native_moodle_database_test.php
index d40c5646d27e..dd17338224ab 100644
--- a/lib/dml/tests/mysqli_native_moodle_database_test.php
+++ b/lib/dml/tests/mysqli_native_moodle_database_test.php
@@ -70,7 +70,6 @@ public function new_connection(?bool $compress = false, ?string $ssl = null): my
$reflector = new ReflectionClass($db2);
$rp = $reflector->getProperty('mysqli');
- $rp->setAccessible(true);
return $rp->getValue($db2);
}
diff --git a/lib/dml/tests/pgsql_native_moodle_database_test.php b/lib/dml/tests/pgsql_native_moodle_database_test.php
index 5e3986035b6b..3e0a32e55464 100644
--- a/lib/dml/tests/pgsql_native_moodle_database_test.php
+++ b/lib/dml/tests/pgsql_native_moodle_database_test.php
@@ -89,7 +89,6 @@ private function get_current_index(): int {
global $DB;
$reflector = new ReflectionClass($DB);
$property = $reflector->getProperty('inorequaluniqueindex');
- $property->setAccessible(true);
return (int) $property->getValue($DB);
}
@@ -390,7 +389,6 @@ public function new_connection($ssl) {
$reflector = new ReflectionClass($db2);
$rp = $reflector->getProperty('pgsql');
- $rp->setAccessible(true);
return $rp->getValue($db2);
}
diff --git a/lib/dml/tests/sqlsrv_native_moodle_database_test.php b/lib/dml/tests/sqlsrv_native_moodle_database_test.php
index 9e0f34b9f7ea..0d4800a6e470 100644
--- a/lib/dml/tests/sqlsrv_native_moodle_database_test.php
+++ b/lib/dml/tests/sqlsrv_native_moodle_database_test.php
@@ -125,10 +125,8 @@ public function test_add_no_lock_to_temp_tables($input, $expected) {
$reflector = new \ReflectionObject($sqlsrv);
$method = $reflector->getMethod('add_no_lock_to_temp_tables');
- $method->setAccessible(true);
$temptablesproperty = $reflector->getProperty('temptables');
- $temptablesproperty->setAccessible(true);
$temptables = new temptables_tester();
$temptablesproperty->setValue($sqlsrv, $temptables);
@@ -252,7 +250,6 @@ public function test_has_query_order_by(string $sql, string $expectedmainquery,
// The has_query_order_by static method is protected. Use Reflection to call the method.
$method = new \ReflectionMethod('sqlsrv_native_moodle_database', 'has_query_order_by');
- $method->setAccessible(true);
$result = $method->invoke(null, $sql);
$this->assertSame($expectedresult, $result);
}
diff --git a/lib/editor/atto/plugins/html/thirdpartylibs.xml b/lib/editor/atto/plugins/html/thirdpartylibs.xml
index 6baba0ca1fb1..ceb826cbf70f 100644
--- a/lib/editor/atto/plugins/html/thirdpartylibs.xml
+++ b/lib/editor/atto/plugins/html/thirdpartylibs.xml
@@ -12,7 +12,7 @@
yui/src/beautifyjsbeautifyBeautify HTML code in Atto.
- 1.14.7
+ 1.15.1MIThttps://github.com/beautify-web/js-beautify
diff --git a/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-debug.js b/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-debug.js
index 6ebc08992d70..4bd9ce1b0259 100644
--- a/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-debug.js
+++ b/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-debug.js
@@ -77,7 +77,7 @@ Y.namespace('M.atto_html').beautify = exports;
} }
space_after_anon_function (default false) - should the space before an anonymous function's parens be added, "function()" vs "function ()",
- NOTE: This option is overriden by jslint_happy (i.e. if jslint_happy is true, space_after_anon_function is true by design)
+ NOTE: This option is overridden by jslint_happy (i.e. if jslint_happy is true, space_after_anon_function is true by design)
brace_style (default "collapse") - "collapse" | "expand" | "end-expand" | "none" | any of the former + ",preserve-inline"
put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line, or attempt to keep them where they are.
@@ -928,7 +928,7 @@ Beautifier.prototype.handle_start_block = function(current_token) {
}
}
if (this._flags.last_token.type !== TOKEN.OPERATOR && this._flags.last_token.type !== TOKEN.START_EXPR) {
- if (this._flags.last_token.type === TOKEN.START_BLOCK && !this._flags.inline_frame) {
+ if (in_array(this._flags.last_token.type, [TOKEN.START_BLOCK, TOKEN.SEMICOLON]) && !this._flags.inline_frame) {
this.print_newline();
} else {
this._output.space_before_token = true;
@@ -1054,7 +1054,9 @@ Beautifier.prototype.handle_word = function(current_token) {
}
if (this._flags.last_token.type === TOKEN.COMMA || this._flags.last_token.type === TOKEN.START_EXPR || this._flags.last_token.type === TOKEN.EQUALS || this._flags.last_token.type === TOKEN.OPERATOR) {
- if (!this.start_of_object_property()) {
+ if (!this.start_of_object_property() && !(
+ // start of object property is different for numeric values with +/- prefix operators
+ in_array(this._flags.last_token.text, ['+', '-']) && this._last_last_text === ':' && this._flags.parent.mode === MODE.ObjectLiteral)) {
this.allow_wrap_or_preserved_newline(current_token);
}
}
@@ -1335,6 +1337,12 @@ Beautifier.prototype.handle_operator = function(current_token) {
return;
}
+ if (in_array(current_token.text, ['-', '+']) && this.start_of_object_property()) {
+ // numeric value with +/- symbol in front as a property
+ this.print_token(current_token);
+ return;
+ }
+
// Allow line wrapping between operators when operator_position is
// set to before or preserve
if (this._flags.last_token.type === TOKEN.OPERATOR && in_array(this._options.operator_position, OPERATOR_POSITION_BEFORE_OR_PRESERVE)) {
@@ -2161,12 +2169,13 @@ var nonASCIIidentifierChars = "\\u0300-\\u036f\\u0483-\\u0487\\u0591-\\u05bd\\u0
//var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
//var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
-var identifierStart = "(?:\\\\u[0-9a-fA-F]{4}|[" + baseASCIIidentifierStartChars + nonASCIIidentifierStartChars + "])";
-var identifierChars = "(?:\\\\u[0-9a-fA-F]{4}|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])*";
+var unicodeEscapeOrCodePoint = "\\\\u[0-9a-fA-F]{4}|\\\\u\\{[0-9a-fA-F]+\\}";
+var identifierStart = "(?:" + unicodeEscapeOrCodePoint + "|[" + baseASCIIidentifierStartChars + nonASCIIidentifierStartChars + "])";
+var identifierChars = "(?:" + unicodeEscapeOrCodePoint + "|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])*";
exports.identifier = new RegExp(identifierStart + identifierChars, 'g');
exports.identifierStart = new RegExp(identifierStart);
-exports.identifierMatch = new RegExp("(?:\\\\u[0-9a-fA-F]{4}|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])+");
+exports.identifierMatch = new RegExp("(?:" + unicodeEscapeOrCodePoint + "|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])+");
var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/; // jshint ignore:line
@@ -2355,10 +2364,10 @@ function Options(options, merge_child_field) {
this.indent_empty_lines = this._get_boolean('indent_empty_lines');
- // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty']
- // For now, 'auto' = all off for javascript, all on for html (and inline javascript).
+ // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular']
+ // For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css).
// other values ignored
- this.templating = this._get_selection_list('templating', ['auto', 'none', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
+ this.templating = this._get_selection_list('templating', ['auto', 'none', 'angular', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
}
Options.prototype._get_array = function(name, default_value) {
@@ -2654,6 +2663,7 @@ Tokenizer.prototype._get_next_token = function(previous_token, open_token) { //
token = token || this._read_non_javascript(c);
token = token || this._read_string(c);
+ token = token || this._read_pair(c, this._input.peek(1)); // Issue #2062 hack for record type '#{'
token = token || this._read_word(previous_token);
token = token || this._read_singles(c);
token = token || this._read_comment(c);
@@ -2712,6 +2722,19 @@ Tokenizer.prototype._read_singles = function(c) {
return token;
};
+Tokenizer.prototype._read_pair = function(c, d) {
+ var token = null;
+ if (c === '#' && d === '{') {
+ token = this._create_token(TOKEN.START_BLOCK, c + d);
+ }
+
+ if (token) {
+ this._input.next();
+ this._input.next();
+ }
+ return token;
+};
+
Tokenizer.prototype._read_punctuation = function() {
var resulting_string = this.__patterns.punct.read();
@@ -2957,6 +2980,9 @@ function unescape_string(s) {
matched = input_scan.match(/x([0-9A-Fa-f]{2})/g);
} else if (input_scan.peek() === 'u') {
matched = input_scan.match(/u([0-9A-Fa-f]{4})/g);
+ if (!matched) {
+ matched = input_scan.match(/u\{([0-9A-Fa-f]+)\}/g);
+ }
} else {
out += '\\';
if (input_scan.hasNext()) {
@@ -2980,7 +3006,9 @@ function unescape_string(s) {
} else if (escaped >= 0x00 && escaped < 0x20) {
// leave 0x00...0x1f escaped
out += '\\' + matched[0];
- continue;
+ } else if (escaped > 0x10FFFF) {
+ // If the escape sequence is out of bounds, keep the original sequence and continue conversion
+ out += '\\' + matched[0];
} else if (escaped === 0x22 || escaped === 0x27 || escaped === 0x5c) {
// single-quote, apostrophe, backslash - escape these
out += '\\' + String.fromCharCode(escaped);
@@ -3803,7 +3831,8 @@ var template_names = {
erb: false,
handlebars: false,
php: false,
- smarty: false
+ smarty: false,
+ angular: false
};
// This lets templates appear anywhere we would do a readUntil
@@ -4609,10 +4638,10 @@ function Options(options, merge_child_field) {
this.indent_empty_lines = this._get_boolean('indent_empty_lines');
- // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty']
- // For now, 'auto' = all off for javascript, all on for html (and inline javascript).
+ // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular']
+ // For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css).
// other values ignored
- this.templating = this._get_selection_list('templating', ['auto', 'none', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
+ this.templating = this._get_selection_list('templating', ['auto', 'none', 'angular', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
}
Options.prototype._get_array = function(name, default_value) {
@@ -5115,18 +5144,18 @@ function Beautifier(source_text, options) {
// https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
this.NESTED_AT_RULE = {
- "@page": true,
- "@font-face": true,
- "@keyframes": true,
+ "page": true,
+ "font-face": true,
+ "keyframes": true,
// also in CONDITIONAL_GROUP_RULE below
- "@media": true,
- "@supports": true,
- "@document": true
+ "media": true,
+ "supports": true,
+ "document": true
};
this.CONDITIONAL_GROUP_RULE = {
- "@media": true,
- "@supports": true,
- "@document": true
+ "media": true,
+ "supports": true,
+ "document": true
};
this.NON_SEMICOLON_NEWLINE_PROPERTY = [
"grid-template-areas",
@@ -5254,8 +5283,7 @@ Beautifier.prototype.beautify = function() {
// label { content: blue }
var insidePropertyValue = false;
var enteringConditionalGroup = false;
- var insideAtExtend = false;
- var insideAtImport = false;
+ var insideNonNestedAtRule = false;
var insideScssMap = false;
var topCharacter = this._ch;
var insideNonSemiColonValues = false;
@@ -5310,10 +5338,30 @@ Beautifier.prototype.beautify = function() {
// Ensures any new lines following the comment are preserved
this.eatWhitespace(true);
- } else if (this._ch === '@' || this._ch === '$') {
+ } else if (this._ch === '$') {
+ this.preserveSingleSpace(isAfterSpace);
+
+ this.print_string(this._ch);
+
+ // strip trailing space, if present, for hash property checks
+ var variable = this._input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g);
+
+ if (variable.match(/[ :]$/)) {
+ // we have a variable or pseudo-class, add it and insert one space before continuing
+ variable = this.eatString(": ").replace(/\s+$/, '');
+ this.print_string(variable);
+ this._output.space_before_token = true;
+ }
+
+ // might be sass variable
+ if (parenLevel === 0 && variable.indexOf(':') !== -1) {
+ insidePropertyValue = true;
+ this.indent();
+ }
+ } else if (this._ch === '@') {
this.preserveSingleSpace(isAfterSpace);
- // deal with less propery mixins @{...}
+ // deal with less property mixins @{...}
if (this._input.peek() === '{') {
this.print_string(this._ch + this.eatString('}'));
} else {
@@ -5324,29 +5372,26 @@ Beautifier.prototype.beautify = function() {
if (variableOrRule.match(/[ :]$/)) {
// we have a variable or pseudo-class, add it and insert one space before continuing
- variableOrRule = this.eatString(": ").replace(/\s$/, '');
+ variableOrRule = this.eatString(": ").replace(/\s+$/, '');
this.print_string(variableOrRule);
this._output.space_before_token = true;
}
- variableOrRule = variableOrRule.replace(/\s$/, '');
-
- if (variableOrRule === 'extend') {
- insideAtExtend = true;
- } else if (variableOrRule === 'import') {
- insideAtImport = true;
- }
+ // might be less variable
+ if (parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
+ insidePropertyValue = true;
+ this.indent();
- // might be a nesting at-rule
- if (variableOrRule in this.NESTED_AT_RULE) {
+ // might be a nesting at-rule
+ } else if (variableOrRule in this.NESTED_AT_RULE) {
this._nestedLevel += 1;
if (variableOrRule in this.CONDITIONAL_GROUP_RULE) {
enteringConditionalGroup = true;
}
- // might be less variable
- } else if (!insideRule && parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
- insidePropertyValue = true;
- this.indent();
+
+ // might be a non-nested at-rule
+ } else if (parenLevel === 0 && !insidePropertyValue) {
+ insideNonNestedAtRule = true;
}
}
} else if (this._ch === '#' && this._input.peek() === '{') {
@@ -5358,6 +5403,9 @@ Beautifier.prototype.beautify = function() {
this.outdent();
}
+ // non nested at rule becomes nested
+ insideNonNestedAtRule = false;
+
// when entering conditional groups, only rulesets are allowed
if (enteringConditionalGroup) {
enteringConditionalGroup = false;
@@ -5398,8 +5446,7 @@ Beautifier.prototype.beautify = function() {
if (previous_ch === '{') {
this._output.trim(true);
}
- insideAtImport = false;
- insideAtExtend = false;
+
if (insidePropertyValue) {
this.outdent();
insidePropertyValue = false;
@@ -5433,9 +5480,10 @@ Beautifier.prototype.beautify = function() {
}
}
- if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideAtExtend && parenLevel === 0) {
+ if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideNonNestedAtRule && parenLevel === 0) {
// 'property: value' delimiter
// which could be in a conditional group query
+
this.print_string(':');
if (!insidePropertyValue) {
insidePropertyValue = true;
@@ -5472,8 +5520,7 @@ Beautifier.prototype.beautify = function() {
this.outdent();
insidePropertyValue = false;
}
- insideAtExtend = false;
- insideAtImport = false;
+ insideNonNestedAtRule = false;
this.print_string(this._ch);
this.eatWhitespace(true);
@@ -5538,7 +5585,7 @@ Beautifier.prototype.beautify = function() {
} else if (this._ch === ',') {
this.print_string(this._ch);
this.eatWhitespace(true);
- if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideAtImport && !insideAtExtend) {
+ if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideNonNestedAtRule) {
this._output.add_new_line();
} else {
this._output.space_before_token = true;
@@ -6353,10 +6400,10 @@ function Options(options, merge_child_field) {
this.indent_empty_lines = this._get_boolean('indent_empty_lines');
- // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty']
- // For now, 'auto' = all off for javascript, all on for html (and inline javascript).
+ // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular']
+ // For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css).
// other values ignored
- this.templating = this._get_selection_list('templating', ['auto', 'none', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
+ this.templating = this._get_selection_list('templating', ['auto', 'none', 'angular', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
}
Options.prototype._get_array = function(name, default_value) {
@@ -7229,7 +7276,8 @@ var template_names = {
erb: false,
handlebars: false,
php: false,
- smarty: false
+ smarty: false,
+ angular: false
};
// This lets templates appear anywhere we would do a readUntil
@@ -7572,6 +7620,13 @@ Printer.prototype.indent = function() {
this.indent_level++;
};
+Printer.prototype.deindent = function() {
+ if (this.indent_level > 0) {
+ this.indent_level--;
+ this._output.set_indent(this.indent_level, this.alignment_size);
+ }
+};
+
Printer.prototype.get_full_indent = function(level) {
level = this.indent_level + (level || 0);
if (level < 1) {
@@ -7757,15 +7812,19 @@ Beautifier.prototype.beautify = function() {
while (raw_token.type !== TOKEN.EOF) {
if (raw_token.type === TOKEN.TAG_OPEN || raw_token.type === TOKEN.COMMENT) {
- parser_token = this._handle_tag_open(printer, raw_token, last_tag_token, last_token);
+ parser_token = this._handle_tag_open(printer, raw_token, last_tag_token, last_token, tokens);
last_tag_token = parser_token;
} else if ((raw_token.type === TOKEN.ATTRIBUTE || raw_token.type === TOKEN.EQUALS || raw_token.type === TOKEN.VALUE) ||
(raw_token.type === TOKEN.TEXT && !last_tag_token.tag_complete)) {
- parser_token = this._handle_inside_tag(printer, raw_token, last_tag_token, tokens);
+ parser_token = this._handle_inside_tag(printer, raw_token, last_tag_token, last_token);
} else if (raw_token.type === TOKEN.TAG_CLOSE) {
parser_token = this._handle_tag_close(printer, raw_token, last_tag_token);
} else if (raw_token.type === TOKEN.TEXT) {
parser_token = this._handle_text(printer, raw_token, last_tag_token);
+ } else if (raw_token.type === TOKEN.CONTROL_FLOW_OPEN) {
+ parser_token = this._handle_control_flow_open(printer, raw_token);
+ } else if (raw_token.type === TOKEN.CONTROL_FLOW_CLOSE) {
+ parser_token = this._handle_control_flow_close(printer, raw_token);
} else {
// This should never happen, but if it does. Print the raw token
printer.add_raw_token(raw_token);
@@ -7780,6 +7839,38 @@ Beautifier.prototype.beautify = function() {
return sweet_code;
};
+Beautifier.prototype._handle_control_flow_open = function(printer, raw_token) {
+ var parser_token = {
+ text: raw_token.text,
+ type: raw_token.type
+ };
+ printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true);
+ if (raw_token.newlines) {
+ printer.print_preserved_newlines(raw_token);
+ } else {
+ printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true);
+ }
+ printer.print_token(raw_token);
+ printer.indent();
+ return parser_token;
+};
+
+Beautifier.prototype._handle_control_flow_close = function(printer, raw_token) {
+ var parser_token = {
+ text: raw_token.text,
+ type: raw_token.type
+ };
+
+ printer.deindent();
+ if (raw_token.newlines) {
+ printer.print_preserved_newlines(raw_token);
+ } else {
+ printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true);
+ }
+ printer.print_token(raw_token);
+ return parser_token;
+};
+
Beautifier.prototype._handle_tag_close = function(printer, raw_token, last_tag_token) {
var parser_token = {
text: raw_token.text,
@@ -7818,7 +7909,7 @@ Beautifier.prototype._handle_tag_close = function(printer, raw_token, last_tag_t
return parser_token;
};
-Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_token, tokens) {
+Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_token, last_token) {
var wrapped = last_tag_token.has_wrapped_attrs;
var parser_token = {
text: raw_token.text,
@@ -7839,7 +7930,6 @@ Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_
} else {
if (raw_token.type === TOKEN.ATTRIBUTE) {
printer.set_space_before_token(true);
- last_tag_token.attr_count += 1;
} else if (raw_token.type === TOKEN.EQUALS) { //no space before =
printer.set_space_before_token(false);
} else if (raw_token.type === TOKEN.VALUE && raw_token.previous.type === TOKEN.EQUALS) { //no space before value
@@ -7852,29 +7942,15 @@ Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_
wrapped = wrapped || raw_token.newlines !== 0;
}
-
- if (this._is_wrap_attributes_force) {
- var force_attr_wrap = last_tag_token.attr_count > 1;
- if (this._is_wrap_attributes_force_expand_multiline && last_tag_token.attr_count === 1) {
- var is_only_attribute = true;
- var peek_index = 0;
- var peek_token;
- do {
- peek_token = tokens.peek(peek_index);
- if (peek_token.type === TOKEN.ATTRIBUTE) {
- is_only_attribute = false;
- break;
- }
- peek_index += 1;
- } while (peek_index < 4 && peek_token.type !== TOKEN.EOF && peek_token.type !== TOKEN.TAG_CLOSE);
-
- force_attr_wrap = !is_only_attribute;
- }
-
- if (force_attr_wrap) {
- printer.print_newline(false);
- wrapped = true;
- }
+ // Wrap for 'force' options, and if the number of attributes is at least that specified in 'wrap_attributes_min_attrs':
+ // 1. always wrap the second and beyond attributes
+ // 2. wrap the first attribute only if 'force-expand-multiline' is specified
+ if (this._is_wrap_attributes_force &&
+ last_tag_token.attr_count >= this._options.wrap_attributes_min_attrs &&
+ (last_token.type !== TOKEN.TAG_OPEN || // ie. second attribute and beyond
+ this._is_wrap_attributes_force_expand_multiline)) {
+ printer.print_newline(false);
+ wrapped = true;
}
}
printer.print_token(raw_token);
@@ -8003,12 +8079,12 @@ Beautifier.prototype._print_custom_beatifier_text = function(printer, raw_token,
}
};
-Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_token, last_token) {
+Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_token, last_token, tokens) {
var parser_token = this._get_tag_open_token(raw_token);
if ((last_tag_token.is_unformatted || last_tag_token.is_content_unformatted) &&
!last_tag_token.is_empty_element &&
- raw_token.type === TOKEN.TAG_OPEN && raw_token.text.indexOf('') === 0) {
+ raw_token.type === TOKEN.TAG_OPEN && !parser_token.is_start_tag) {
// End element tags for unformatted or content_unformatted elements
// are printed raw to keep any newlines inside them exactly the same.
printer.add_raw_token(raw_token);
@@ -8022,6 +8098,19 @@ Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_to
printer.print_token(raw_token);
}
+ // count the number of attributes
+ if (parser_token.is_start_tag && this._is_wrap_attributes_force) {
+ var peek_index = 0;
+ var peek_token;
+ do {
+ peek_token = tokens.peek(peek_index);
+ if (peek_token.type === TOKEN.ATTRIBUTE) {
+ parser_token.attr_count += 1;
+ }
+ peek_index += 1;
+ } while (peek_token.type !== TOKEN.EOF && peek_token.type !== TOKEN.TAG_CLOSE);
+ }
+
//indent attributes an auto, forced, aligned or forced-align line-wrap
if (this._is_wrap_attributes_force_aligned || this._is_wrap_attributes_aligned_multiple || this._is_wrap_attributes_preserve_aligned) {
parser_token.alignment_size = raw_token.text.length + 1;
@@ -8119,7 +8208,7 @@ Beautifier.prototype._get_tag_open_token = function(raw_token) { //function to g
parser_token.is_unformatted = !parser_token.tag_complete && in_array(parser_token.tag_check, this._options.unformatted);
parser_token.is_content_unformatted = !parser_token.is_empty_element && in_array(parser_token.tag_check, this._options.content_unformatted);
- parser_token.is_inline_element = in_array(parser_token.tag_name, this._options.inline) || parser_token.tag_name.includes("-") || parser_token.tag_start_char === '{';
+ parser_token.is_inline_element = in_array(parser_token.tag_name, this._options.inline) || (this._options.inline_custom_elements && parser_token.tag_name.includes("-")) || parser_token.tag_start_char === '{';
return parser_token;
};
@@ -8226,7 +8315,7 @@ Beautifier.prototype._calcluate_parent_multiline = function(printer, parser_toke
};
//To be used for
tag special case:
-var p_closers = ['address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'];
+var p_closers = ['address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'menu', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'];
var p_parent_excludes = ['a', 'audio', 'del', 'ins', 'map', 'noscript', 'video'];
Beautifier.prototype._do_optional_end_element = function(parser_token) {
@@ -8249,7 +8338,7 @@ Beautifier.prototype._do_optional_end_element = function(parser_token) {
} else if (parser_token.tag_name === 'li') {
// An li element’s end tag may be omitted if the li element is immediately followed by another li element or if there is no more content in the parent element.
- result = result || this._tag_stack.try_pop('li', ['ol', 'ul']);
+ result = result || this._tag_stack.try_pop('li', ['ol', 'ul', 'menu']);
} else if (parser_token.tag_name === 'dd' || parser_token.tag_name === 'dt') {
// A dd element’s end tag may be omitted if the dd element is immediately followed by another dd element or a dt element, or if there is no more content in the parent element.
@@ -8388,6 +8477,7 @@ function Options(options) {
this.indent_handlebars = this._get_boolean('indent_handlebars', true);
this.wrap_attributes = this._get_selection('wrap_attributes',
['auto', 'force', 'force-aligned', 'force-expand-multiline', 'aligned-multiple', 'preserve', 'preserve-aligned']);
+ this.wrap_attributes_min_attrs = this._get_number('wrap_attributes_min_attrs', 2);
this.wrap_attributes_indent_size = this._get_number('wrap_attributes_indent_size', this.indent_size);
this.extra_liners = this._get_array('extra_liners', ['head', 'body', '/html']);
@@ -8405,6 +8495,7 @@ function Options(options) {
// obsolete inline tags
'acronym', 'big', 'strike', 'tt'
]);
+ this.inline_custom_elements = this._get_boolean('inline_custom_elements', true);
this.void_elements = this._get_array('void_elements', [
// HTLM void elements - aka self-closing tags - aka singletons
// https://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
@@ -8479,6 +8570,8 @@ var Pattern = (__webpack_require__(12).Pattern);
var TOKEN = {
TAG_OPEN: 'TK_TAG_OPEN',
TAG_CLOSE: 'TK_TAG_CLOSE',
+ CONTROL_FLOW_OPEN: 'TK_CONTROL_FLOW_OPEN',
+ CONTROL_FLOW_CLOSE: 'TK_CONTROL_FLOW_CLOSE',
ATTRIBUTE: 'TK_ATTRIBUTE',
EQUALS: 'TK_EQUALS',
VALUE: 'TK_VALUE',
@@ -8503,11 +8596,13 @@ var Tokenizer = function(input_string, options) {
this.__patterns = {
word: templatable_reader.until(/[\n\r\t <]/),
+ word_control_flow_close_excluded: templatable_reader.until(/[\n\r\t <}]/),
single_quote: templatable_reader.until_after(/'/),
double_quote: templatable_reader.until_after(/"/),
attribute: templatable_reader.until(/[\n\r\t =>]|\/>/),
element_name: templatable_reader.until(/[\n\r\t >\/]/),
+ angular_control_flow_start: pattern_reader.matching(/\@[a-zA-Z]+[^({]*[({]/),
handlebars_comment: pattern_reader.starting_with(/{{!--/).until_after(/--}}/),
handlebars: pattern_reader.starting_with(/{{/).until_after(/}}/),
handlebars_open: pattern_reader.until(/[\n\r\t }]/),
@@ -8521,6 +8616,7 @@ var Tokenizer = function(input_string, options) {
if (this._options.indent_handlebars) {
this.__patterns.word = this.__patterns.word.exclude('handlebars');
+ this.__patterns.word_control_flow_close_excluded = this.__patterns.word_control_flow_close_excluded.exclude('handlebars');
}
this._unformatted_content_delimiter = null;
@@ -8539,14 +8635,16 @@ Tokenizer.prototype._is_comment = function(current_token) { // jshint unused:fal
};
Tokenizer.prototype._is_opening = function(current_token) {
- return current_token.type === TOKEN.TAG_OPEN;
+ return current_token.type === TOKEN.TAG_OPEN || current_token.type === TOKEN.CONTROL_FLOW_OPEN;
};
Tokenizer.prototype._is_closing = function(current_token, open_token) {
- return current_token.type === TOKEN.TAG_CLOSE &&
+ return (current_token.type === TOKEN.TAG_CLOSE &&
(open_token && (
((current_token.text === '>' || current_token.text === '/>') && open_token.text[0] === '<') ||
- (current_token.text === '}}' && open_token.text[0] === '{' && open_token.text[1] === '{')));
+ (current_token.text === '}}' && open_token.text[0] === '{' && open_token.text[1] === '{')))
+ ) || (current_token.type === TOKEN.CONTROL_FLOW_CLOSE &&
+ (current_token.text === '}' && open_token.text.endsWith('{')));
};
Tokenizer.prototype._reset = function() {
@@ -8565,8 +8663,9 @@ Tokenizer.prototype._get_next_token = function(previous_token, open_token) { //
token = token || this._read_open_handlebars(c, open_token);
token = token || this._read_attribute(c, previous_token, open_token);
token = token || this._read_close(c, open_token);
+ token = token || this._read_control_flows(c, open_token);
token = token || this._read_raw_content(c, previous_token, open_token);
- token = token || this._read_content_word(c);
+ token = token || this._read_content_word(c, open_token);
token = token || this._read_comment_or_cdata(c);
token = token || this._read_processing(c);
token = token || this._read_open(c, open_token);
@@ -8631,7 +8730,7 @@ Tokenizer.prototype._read_processing = function(c) { // jshint unused:false
Tokenizer.prototype._read_open = function(c, open_token) {
var resulting_string = null;
var token = null;
- if (!open_token) {
+ if (!open_token || open_token.type === TOKEN.CONTROL_FLOW_OPEN) {
if (c === '<') {
resulting_string = this._input.next();
@@ -8648,7 +8747,7 @@ Tokenizer.prototype._read_open = function(c, open_token) {
Tokenizer.prototype._read_open_handlebars = function(c, open_token) {
var resulting_string = null;
var token = null;
- if (!open_token) {
+ if (!open_token || open_token.type === TOKEN.CONTROL_FLOW_OPEN) {
if (this._options.indent_handlebars && c === '{' && this._input.peek(1) === '{') {
if (this._input.peek(2) === '!') {
resulting_string = this.__patterns.handlebars_comment.read();
@@ -8663,11 +8762,48 @@ Tokenizer.prototype._read_open_handlebars = function(c, open_token) {
return token;
};
+Tokenizer.prototype._read_control_flows = function(c, open_token) {
+ var resulting_string = '';
+ var token = null;
+ // Only check for control flows if angular templating is set AND indenting is set
+ if (!this._options.templating.includes('angular') || !this._options.indent_handlebars) {
+ return token;
+ }
+
+ if (c === '@') {
+ resulting_string = this.__patterns.angular_control_flow_start.read();
+ if (resulting_string === '') {
+ return token;
+ }
+
+ var opening_parentheses_count = resulting_string.endsWith('(') ? 1 : 0;
+ var closing_parentheses_count = 0;
+ // The opening brace of the control flow is where the number of opening and closing parentheses equal
+ // e.g. @if({value: true} !== null) {
+ while (!(resulting_string.endsWith('{') && opening_parentheses_count === closing_parentheses_count)) {
+ var next_char = this._input.next();
+ if (next_char === null) {
+ break;
+ } else if (next_char === '(') {
+ opening_parentheses_count++;
+ } else if (next_char === ')') {
+ closing_parentheses_count++;
+ }
+ resulting_string += next_char;
+ }
+ token = this._create_token(TOKEN.CONTROL_FLOW_OPEN, resulting_string);
+ } else if (c === '}' && open_token && open_token.type === TOKEN.CONTROL_FLOW_OPEN) {
+ resulting_string = this._input.next();
+ token = this._create_token(TOKEN.CONTROL_FLOW_CLOSE, resulting_string);
+ }
+ return token;
+};
+
Tokenizer.prototype._read_close = function(c, open_token) {
var resulting_string = null;
var token = null;
- if (open_token) {
+ if (open_token && open_token.type === TOKEN.TAG_OPEN) {
if (open_token.text[0] === '<' && (c === '>' || (c === '/' && this._input.peek(1) === '>'))) {
resulting_string = this._input.next();
if (c === '/') { // for close tag "/>"
@@ -8754,7 +8890,7 @@ Tokenizer.prototype._read_raw_content = function(c, previous_token, open_token)
return null;
};
-Tokenizer.prototype._read_content_word = function(c) {
+Tokenizer.prototype._read_content_word = function(c, open_token) {
var resulting_string = '';
if (this._options.unformatted_content_delimiter) {
if (c === this._options.unformatted_content_delimiter[0]) {
@@ -8763,7 +8899,7 @@ Tokenizer.prototype._read_content_word = function(c) {
}
if (!resulting_string) {
- resulting_string = this.__patterns.word.read();
+ resulting_string = (open_token && open_token.type === TOKEN.CONTROL_FLOW_OPEN) ? this.__patterns.word_control_flow_close_excluded.read() : this.__patterns.word.read();
}
if (resulting_string) {
return this._create_token(TOKEN.TEXT, resulting_string);
diff --git a/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-min.js b/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-min.js
index c16731212cc9..9f2d6e07a8b6 100644
--- a/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-min.js
+++ b/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify-min.js
@@ -1,24 +1,25 @@
-YUI.add("moodle-atto_html-beautify",function(t,e){var s,a,u,n,i,_,r={};t.namespace("M.atto_html").beautify=r,function(){"use strict";var t,n=[function(t,e,n){var i=n(1).Beautifier,_=n(5).Options;t.exports=function(t,e){return new i(t,e).beautify()},t.exports.defaultOptions=function(){return new _}},function(n,_,t){var d,f,g,o,h,s,a,r,b,m,y,w=t(2).Output,k=t(3).Token,x=t(4),v=t(5).Options,E=t(7).Tokenizer,O=t(7).line_starters,T=t(7).positionable_operators,p=t(7).TOKEN;function l(t,e){return-1!==e.indexOf(t)}function i(t,e){return t&&t.type===p.RESERVED&&t.text===e}function c(t,e){return t&&t.type===p.RESERVED&&l(t.text,e)}function R(t,e){e.multiline_frame||e.mode===r||e.mode===b||t.remove_indent(e.start_line_index)}function u(t){return t===a}function A(t){return l(t,[m,r,b])}function e(t,e){e=e||{},this._source_text=t||"",this._output=null,this._tokens=null,this._last_last_text=null,this._flags=null,this._previous_flags=null,this._flag_store=null,this._options=new v(e)}d=["case","return","do","if","throw","else","await","break","continue","async"],f=function(t){for(var e={},n=0;nn&&(n=t.line_indent_level)),{mode:e,parent:t,last_token:t?t.last_token:new k(p.START_BLOCK,""),last_word:t?t.last_word:"",declaration_statement:!1,declaration_assignment:!1,multiline_frame:!1,inline_frame:!1,if_block:!1,else_block:!1,class_start_block:!1,do_block:!1,do_while:!1,import_block:!1,in_case_statement:!1,in_case:!1,case_body:!1,case_block:!1,indentation_level:n,alignment:0,line_indent_level:t?t.line_indent_level:n,start_line_index:this._output.get_line_number(),ternary_depth:0}},e.prototype._reset=function(t){var e=t.match(/^[\t ]*/)[0];return this._last_last_text="",this._output=new w(this._options,e),this._output.raw=this._options.test_output_raw,this._flag_store=[],this.set_mode(o),e=new E(t,this._options),this._tokens=e.tokenize(),t},e.prototype.beautify=function(){var t,e,n;if(this._options.disabled)return this._source_text;for(t=this._reset(this._source_text),e=this._options.eol,"auto"===this._options.eol&&(e="\n",t&&x.lineBreak.test(t||"")&&(e=t.match(x.lineBreak)[0])),n=this._tokens.next();n;)this.handle_token(n),this._last_last_text=this._flags.last_token.text,this._flags.last_token=n,n=this._tokens.next();return this._output.get_code(e)},e.prototype.handle_token=function(t,e){t.type===p.START_EXPR?this.handle_start_expr(t):t.type===p.END_EXPR?this.handle_end_expr(t):t.type===p.START_BLOCK?this.handle_start_block(t):t.type===p.END_BLOCK?this.handle_end_block(t):t.type===p.WORD||t.type===p.RESERVED?this.handle_word(t):t.type===p.SEMICOLON?this.handle_semicolon(t):t.type===p.STRING?this.handle_string(t):t.type===p.EQUALS?this.handle_equals(t):t.type===p.OPERATOR?this.handle_operator(t):t.type===p.COMMA?this.handle_comma(t):t.type===p.BLOCK_COMMENT?this.handle_block_comment(t,e):t.type===p.COMMENT?this.handle_comment(t,e):t.type===p.DOT?this.handle_dot(t):t.type===p.EOF?this.handle_eof(t):(t.type,p.UNKNOWN,this.handle_unknown(t,e))},e.prototype.handle_whitespace_and_comments=function(t,e){var n,i,_,s=t.newlines,a=this._options.keep_array_indentation&&u(this._flags.mode);if(t.comments_before)for(n=t.comments_before.next();n;)this.handle_whitespace_and_comments(n,e),this.handle_token(n,e),n=t.comments_before.next();if(a)for(i=0;ithis._options.max_preserve_newlines&&(s=this._options.max_preserve_newlines),this._options.preserve_newlines&&1this._flags.parent.indentation_level)&&(--this._flags.indentation_level,this._output.set_indent(this._flags.indentation_level,this._flags.alignment))},e.prototype.set_mode=function(t){this._flags?(this._flag_store.push(this._flags),this._previous_flags=this._flags):this._previous_flags=this.create_flags(null,t),this._flags=this.create_flags(this._previous_flags,t),this._output.set_indent(this._flags.indentation_level,this._flags.alignment)},e.prototype.restore_mode=function(){0"!==this._flags.last_token.text)&&(l(this._flags.last_token.type,[p.EQUALS,p.START_EXPR,p.COMMA,p.OPERATOR])||c(this._flags.last_token,["return","throw","import","default"]))?this.set_mode(s):this.set_mode(o),this._flags.last_token&&c(this._flags.last_token.previous,["class","extends"])&&(this._flags.class_start_block=!0),n=(e=!n.comments_before&&"}"===n.text)&&"function"===this._flags.last_word&&this._flags.last_token.type===p.END_EXPR,this._options.brace_preserve_inline){i=0,this._flags.inline_frame=!(_=null);do{if((_=this._tokens.peek((i+=1)-1)).newlines){this._flags.inline_frame=!1;break}}while(_.type!==p.EOF&&(_.type!==p.END_BLOCK||_.opened!==t))}("expand"===this._options.brace_style||"none"===this._options.brace_style&&t.newlines)&&!this._flags.inline_frame?this._flags.last_token.type!==p.OPERATOR&&(n||this._flags.last_token.type===p.EQUALS||c(this._flags.last_token,d)&&"else"!==this._flags.last_token.text)?this._output.space_before_token=!0:this.print_newline(!1,!0):(!u(this._previous_flags.mode)||this._flags.last_token.type!==p.START_EXPR&&this._flags.last_token.type!==p.COMMA||(this._flags.last_token.type!==p.COMMA&&!this._options.space_in_paren||(this._output.space_before_token=!0),(this._flags.last_token.type===p.COMMA||this._flags.last_token.type===p.START_EXPR&&this._flags.inline_frame)&&(this.allow_wrap_or_preserved_newline(t),this._previous_flags.multiline_frame=this._previous_flags.multiline_frame||this._flags.multiline_frame,this._flags.multiline_frame=!1)),this._flags.last_token.type!==p.OPERATOR&&this._flags.last_token.type!==p.START_EXPR&&(this._flags.last_token.type!==p.START_BLOCK||this._flags.inline_frame?this._output.space_before_token=!0:this.print_newline())),this.print_token(t),this.indent(),e||this._options.brace_preserve_inline&&this._flags.inline_frame||this.print_newline()},e.prototype.handle_end_block=function(t){for(this.handle_whitespace_and_comments(t);this._flags.mode===h;)this.restore_mode();var e=this._flags.last_token.type===p.START_BLOCK;this._flags.inline_frame&&!e?this._output.space_before_token=!0:"expand"===this._options.brace_style?e||this.print_newline():e||(u(this._flags.mode)&&this._options.keep_array_indentation?(this._options.keep_array_indentation=!1,this.print_newline(),this._options.keep_array_indentation=!0):this.print_newline()),this.restore_mode(),this.print_token(t)},e.prototype.handle_word=function(t){var e;if(t.type===p.RESERVED&&(l(t.text,["set","get"])&&this._flags.mode!==s||"import"===t.text&&l(this._tokens.peek().text,["(","."])||l(t.text,["as","from"])&&!this._flags.import_block||this._flags.mode===s&&":"===this._tokens.peek().text)&&(t.type=p.WORD),this.start_of_statement(t)?c(this._flags.last_token,["var","let","const"])&&t.type===p.WORD&&(this._flags.declaration_statement=!0):!t.newlines||A(this._flags.mode)||this._flags.last_token.type===p.OPERATOR&&"--"!==this._flags.last_token.text&&"++"!==this._flags.last_token.text||this._flags.last_token.type===p.EQUALS||!this._options.preserve_newlines&&c(this._flags.last_token,["var","let","const","set","get"])?this.handle_whitespace_and_comments(t):(this.handle_whitespace_and_comments(t),this.print_newline()),this._flags.do_block&&!this._flags.do_while){if(i(t,"while"))return this._output.space_before_token=!0,this.print_token(t),this._output.space_before_token=!0,void(this._flags.do_while=!0);this.print_newline(),this._flags.do_block=!1}if(this._flags.if_block)if(!this._flags.else_block&&i(t,"else"))this._flags.else_block=!0;else{for(;this._flags.mode===h;)this.restore_mode();this._flags.if_block=!1,this._flags.else_block=!1}return this._flags.in_case_statement&&c(t,["case","default"])?(this.print_newline(),this._flags.case_block||!this._flags.case_body&&!this._options.jslint_happy||this.deindent(),this._flags.case_body=!1,this.print_token(t),void(this._flags.in_case=!0)):(this._flags.last_token.type!==p.COMMA&&this._flags.last_token.type!==p.START_EXPR&&this._flags.last_token.type!==p.EQUALS&&this._flags.last_token.type!==p.OPERATOR||this.start_of_object_property()||this.allow_wrap_or_preserved_newline(t),i(t,"function")?((l(this._flags.last_token.text,["}",";"])||this._output.just_added_newline()&&!l(this._flags.last_token.text,["(","[","{",":","=",","])&&this._flags.last_token.type!==p.OPERATOR)&&(this._output.just_added_blankline()||t.comments_before||(this.print_newline(),this.print_newline(!0))),this._flags.last_token.type===p.RESERVED||this._flags.last_token.type===p.WORD?c(this._flags.last_token,["get","set","new","export"])||c(this._flags.last_token,y)||i(this._flags.last_token,"default")&&"export"===this._last_last_text||"declare"===this._flags.last_token.text?this._output.space_before_token=!0:this.print_newline():this._flags.last_token.type===p.OPERATOR||"="===this._flags.last_token.text?this._output.space_before_token=!0:!this._flags.multiline_frame&&(A(this._flags.mode)||u(this._flags.mode))||this.print_newline(),this.print_token(t),void(this._flags.last_word=t.text)):(e="NONE",this._flags.last_token.type===p.END_BLOCK?this._previous_flags.inline_frame?e="SPACE":!c(t,["else","catch","finally","from"])||"expand"===this._options.brace_style||"end-expand"===this._options.brace_style||"none"===this._options.brace_style&&t.newlines?e="NEWLINE":(e="SPACE",this._output.space_before_token=!0):this._flags.last_token.type===p.SEMICOLON&&this._flags.mode===o?e="NEWLINE":this._flags.last_token.type===p.SEMICOLON&&A(this._flags.mode)?e="SPACE":this._flags.last_token.type===p.STRING?e="NEWLINE":this._flags.last_token.type===p.RESERVED||this._flags.last_token.type===p.WORD||"*"===this._flags.last_token.text&&(l(this._last_last_text,["function","yield"])||this._flags.mode===s&&l(this._last_last_text,["{",","])
-)?e="SPACE":this._flags.last_token.type===p.START_BLOCK?e=this._flags.inline_frame?"SPACE":"NEWLINE":this._flags.last_token.type===p.END_EXPR&&(this._output.space_before_token=!0,e="NEWLINE"),c(t,O)&&")"!==this._flags.last_token.text&&(e=this._flags.inline_frame||"else"===this._flags.last_token.text||"export"===this._flags.last_token.text?"SPACE":"NEWLINE"),c(t,["else","catch","finally"])?(this._flags.last_token.type!==p.END_BLOCK||this._previous_flags.mode!==o||"expand"===this._options.brace_style||"end-expand"===this._options.brace_style||"none"===this._options.brace_style&&t.newlines)&&!this._flags.inline_frame?this.print_newline():(this._output.trim(!0),"}"!==this._output.current_line.last()&&this.print_newline(),this._output.space_before_token=!0):"NEWLINE"===e?c(this._flags.last_token,d)||"declare"===this._flags.last_token.text&&c(t,["var","let","const"])?this._output.space_before_token=!0:this._flags.last_token.type!==p.END_EXPR?this._flags.last_token.type===p.START_EXPR&&c(t,["var","let","const"])||":"===this._flags.last_token.text||(i(t,"if")&&i(t.previous,"else")?this._output.space_before_token=!0:this.print_newline()):c(t,O)&&")"!==this._flags.last_token.text&&this.print_newline():this._flags.multiline_frame&&u(this._flags.mode)&&","===this._flags.last_token.text&&"}"===this._last_last_text?this.print_newline():"SPACE"===e&&(this._output.space_before_token=!0),!t.previous||t.previous.type!==p.WORD&&t.previous.type!==p.RESERVED||(this._output.space_before_token=!0),this.print_token(t),this._flags.last_word=t.text,void(t.type===p.RESERVED&&("do"===t.text?this._flags.do_block=!0:"if"===t.text?this._flags.if_block=!0:"import"===t.text?this._flags.import_block=!0:this._flags.import_block&&i(t,"from")&&(this._flags.import_block=!1)))))},e.prototype.handle_semicolon=function(t){this.start_of_statement(t)?this._output.space_before_token=!1:this.handle_whitespace_and_comments(t);for(var e=this._tokens.peek();!(this._flags.mode!==h||this._flags.if_block&&i(e,"else")||this._flags.do_block);)this.restore_mode();this._flags.import_block&&(this._flags.import_block=!1),this.print_token(t)},e.prototype.handle_string=function(t){t.text.startsWith("`")&&0===t.newlines&&""===t.whitespace_before&&(")"===t.previous.text||this._flags.last_token.type===p.WORD)||(this.start_of_statement(t)?this._output.space_before_token=!0:(this.handle_whitespace_and_comments(t),this._flags.last_token.type===p.RESERVED||this._flags.last_token.type===p.WORD||this._flags.inline_frame?this._output.space_before_token=!0:this._flags.last_token.type===p.COMMA||this._flags.last_token.type===p.START_EXPR||this._flags.last_token.type===p.EQUALS||this._flags.last_token.type===p.OPERATOR?this.start_of_object_property()||this.allow_wrap_or_preserved_newline(t):!t.text.startsWith("`")||this._flags.last_token.type!==p.END_EXPR||"]"!==t.previous.text&&")"!==t.previous.text||0!==t.newlines?this.print_newline():this._output.space_before_token=!0)),this.print_token(t)},e.prototype.handle_equals=function(t){this.start_of_statement(t)||this.handle_whitespace_and_comments(t),this._flags.declaration_statement&&(this._flags.declaration_assignment=!0),this._output.space_before_token=!0,this.print_token(t),this._output.space_before_token=!0},e.prototype.handle_comma=function(t){this.handle_whitespace_and_comments(t,!0),this.print_token(t),this._output.space_before_token=!0,this._flags.declaration_statement?(A(this._flags.parent.mode)&&(this._flags.declaration_assignment=!1),this._flags.declaration_assignment?(this._flags.declaration_assignment=!1,this.print_newline(!1,!0)):this._options.comma_first&&this.allow_wrap_or_preserved_newline(t)):this._flags.mode===s||this._flags.mode===h&&this._flags.parent.mode===s?(this._flags.mode===h&&this.restore_mode(),this._flags.inline_frame||this.print_newline()):this._options.comma_first&&this.allow_wrap_or_preserved_newline(t)},e.prototype.handle_operator=function(t){var e,n,i,_,s,a,u="*"===t.text&&(c(this._flags.last_token,["function","yield"])||l(this._flags.last_token.type,[p.START_BLOCK,p.COMMA,p.END_BLOCK,p.SEMICOLON])),r=l(t.text,["-","+"])&&(l(this._flags.last_token.type,[p.START_BLOCK,p.START_EXPR,p.EQUALS,p.OPERATOR])||l(this._flags.last_token.text,O)||","===this._flags.last_token.text);if(this.start_of_statement(t)||this.handle_whitespace_and_comments(t,!u),"*"!==t.text||this._flags.last_token.type!==p.DOT)if("::"!==t.text){if(this._flags.last_token.type===p.OPERATOR&&l(this._options.operator_position,g)&&this.allow_wrap_or_preserved_newline(t),":"===t.text&&this._flags.in_case)return this.print_token(t),this._flags.in_case=!1,this._flags.case_body=!0,void(this._tokens.peek().type!==p.START_BLOCK?(this.indent(),this.print_newline(),this._flags.case_block=!1):(this._flags.case_block=!0,this._output.space_before_token=!0));if(a=!(n=e=!0),":"===t.text?0===this._flags.ternary_depth?e=!1:(--this._flags.ternary_depth,a=!0):"?"===t.text&&(this._flags.ternary_depth+=1),!r&&!u&&this._options.preserve_newlines&&l(t.text,T))switch(_=(i=":"===t.text)&&a,s=i&&!a,this._options.operator_position){case f.before_newline:return this._output.space_before_token=!s,this.print_token(t),i&&!_||this.allow_wrap_or_preserved_newline(t),void(this._output.space_before_token=!0);case f.after_newline:return this._output.space_before_token=!0,!i||_?this._tokens.peek().newlines?this.print_newline(!1,!0):this.allow_wrap_or_preserved_newline(t):this._output.space_before_token=!1,this.print_token(t),void(this._output.space_before_token=!0);case f.preserve_newline:return s||this.allow_wrap_or_preserved_newline(t),e=!(this._output.just_added_newline()||s),this._output.space_before_token=e,this.print_token(t),void(this._output.space_before_token=!0)}u?(this.allow_wrap_or_preserved_newline(t),e=!1,n=(a=this._tokens.peek())&&l(a.type,[p.WORD,p.RESERVED])):"..."===t.text?(this.allow_wrap_or_preserved_newline(t),e=this._flags.last_token.type===p.START_BLOCK,n=!1):(l(t.text,["--","++","!","~"])||r)&&(
-this._flags.last_token.type!==p.COMMA&&this._flags.last_token.type!==p.START_EXPR||this.allow_wrap_or_preserved_newline(t),n=e=!1,!t.newlines||"--"!==t.text&&"++"!==t.text&&"~"!==t.text||((u=c(this._flags.last_token,d)&&t.newlines)&&(this._previous_flags.if_block||this._previous_flags.else_block)&&this.restore_mode(),this.print_newline(u,!0)),";"===this._flags.last_token.text&&A(this._flags.mode)&&(e=!0),this._flags.last_token.type===p.RESERVED?e=!0:this._flags.last_token.type===p.END_EXPR?e=!("]"===this._flags.last_token.text&&("--"===t.text||"++"===t.text)):this._flags.last_token.type===p.OPERATOR&&(e=l(t.text,["--","-","++","+"])&&l(this._flags.last_token.text,["--","-","++","+"]),l(t.text,["+","-"])&&l(this._flags.last_token.text,["--","++"])&&(n=!0)),(this._flags.mode!==o||this._flags.inline_frame)&&this._flags.mode!==h||"{"!==this._flags.last_token.text&&";"!==this._flags.last_token.text||this.print_newline()),this._output.space_before_token=this._output.space_before_token||e,this.print_token(t),this._output.space_before_token=n}else this.print_token(t);else this.print_token(t)},e.prototype.handle_block_comment=function(t,e){return this._output.raw?(this._output.add_raw_token(t),void(t.directives&&"end"===t.directives.preserve&&(this._output.raw=this._options.test_output_raw))):t.directives?(this.print_newline(!1,e),this.print_token(t),"start"===t.directives.preserve&&(this._output.raw=!0),void this.print_newline(!1,!0)):void(x.newline.test(t.text)||t.newlines?this.print_block_commment(t,e):(this._output.space_before_token=!0,this.print_token(t),this._output.space_before_token=!0))},e.prototype.print_block_commment=function(t,e){var n,i,_,s=function(t){for(var e=[],n=(t=t.replace(x.allLineBreaks,"\n")).indexOf("\n");-1!==n;)e.push(t.substring(0,n)),n=(t=t.substring(n+1)).indexOf("\n");return t.length&&e.push(t),e}(t.text),a=t.whitespace_before,u=a.length;if(this.print_newline(!1,e),this.print_token_line_indentation(t),this._output.add_token(s[0]),this.print_newline(!1,e),1this.__parent.wrap_line_length&&this.__wrap_point_character_count>this.__parent.next_line.__character_count},_.prototype._allow_wrap=function(){var t;return!!this._should_wrap()&&(this.__parent.add_new_line(),(t=this.__parent.current_line).set_indent(this.__wrap_point_indent_count,this.__wrap_point_alignment_count),t.__items=this.__items.slice(this.__wrap_point_index),this.__items=this.__items.slice(0,this.__wrap_point_index),t.__character_count+=this.__character_count-this.__wrap_point_character_count,
-this.__character_count=this.__wrap_point_character_count," "===t.__items[0]&&(t.__items.splice(0,1),--t.__character_count),!0)},_.prototype.is_empty=function(){return 0===this.__items.length},_.prototype.last=function(){return this.is_empty()?null:this.__items[this.__items.length-1]},_.prototype.push=function(t){this.__items.push(t);var e=t.lastIndexOf("\n");-1!==e?this.__character_count=t.length-e:this.__character_count+=t.length},_.prototype.pop=function(){var t=null;return this.is_empty()||(t=this.__items.pop(),this.__character_count-=t.length),t},_.prototype._remove_indent=function(){0=this.__cache.length;)this.__add_column()},n.prototype.__add_column=function(){var t,e=this.__cache.length,n="";this.__indent_size&&e>=this.__indent_size&&(e-=(t=Math.floor(e/this.__indent_size))*this.__indent_size,n=new Array(t+1).join(this.__indent_string)),e&&(n+=new Array(e+1).join(" ")),this.__cache.push(n)},e.prototype.__add_outputline=function(){this.previous_line=this.current_line,this.current_line=this.next_line.clone_empty(),this.__lines.push(this.current_line)},e.prototype.get_line_number=function(){return this.__lines.length},e.prototype.get_indent_string=function(t,e){return this.__indent_cache.get_indent_string(t,e)},e.prototype.get_indent_size=function(t,e){return this.__indent_cache.get_indent_size(t,e)},e.prototype.is_empty=function(){return!this.previous_line&&this.current_line.is_empty()},e.prototype.add_new_line=function(t){return!(this.is_empty()||!t&&this.just_added_newline())&&(this.raw||this.__add_outputline(),!0)},e.prototype.get_code=function(t){var e;return this.trim(!0),(e=this.current_line.pop())&&("\n"===e[e.length-1]&&(e=e.replace(/\n+$/g,"")),this.current_line.push(e)),this._end_with_newline&&this.__add_outputline(),e=this.__lines.join("\n"),e="\n"!==t?e.replace(/[\n]/g,t):e},e.prototype.set_wrap_point=function(){this.current_line._set_wrap_point()},e.prototype.set_indent=function(t,e){return this.next_line.set_indent(t=t||0,e=e||0),1n&&(n=t.line_indent_level)),{mode:e,parent:t,last_token:t?t.last_token:new k(p.START_BLOCK,""),last_word:t?t.last_word:"",declaration_statement:!1,declaration_assignment:!1,multiline_frame:!1,inline_frame:!1,if_block:!1,else_block:!1,class_start_block:!1,do_block:!1,do_while:!1,import_block:!1,in_case_statement:!1,in_case:!1,case_body:!1,case_block:!1,indentation_level:n,alignment:0,line_indent_level:t?t.line_indent_level:n,start_line_index:this._output.get_line_number(),ternary_depth:0}},e.prototype._reset=function(t){var e=t.match(/^[\t ]*/)[0];return this._last_last_text="",this._output=new w(this._options,e),this._output.raw=this._options.test_output_raw,this._flag_store=[],this.set_mode(o),e=new E(t,this._options),this._tokens=e.tokenize(),t},e.prototype.beautify=function(){var t,e,n;if(this._options.disabled)return this._source_text;for(t=this._reset(this._source_text),e=this._options.eol,"auto"===this._options.eol&&(e="\n",t&&x.lineBreak.test(t||"")&&(e=t.match(x.lineBreak)[0])),n=this._tokens.next();n;)this.handle_token(n),this._last_last_text=this._flags.last_token.text,this._flags.last_token=n,n=this._tokens.next();return this._output.get_code(e)},e.prototype.handle_token=function(t,e){t.type===p.START_EXPR?this.handle_start_expr(t):t.type===p.END_EXPR?this.handle_end_expr(t):t.type===p.START_BLOCK?this.handle_start_block(t):t.type===p.END_BLOCK?this.handle_end_block(t):t.type===p.WORD||t.type===p.RESERVED?this.handle_word(t):t.type===p.SEMICOLON?this.handle_semicolon(t):t.type===p.STRING?this.handle_string(t):t.type===p.EQUALS?this.handle_equals(t):t.type===p.OPERATOR?this.handle_operator(t):t.type===p.COMMA?this.handle_comma(t):t.type===p.BLOCK_COMMENT?this.handle_block_comment(t,e):t.type===p.COMMENT?this.handle_comment(t,e):t.type===p.DOT?this.handle_dot(t):t.type===p.EOF?this.handle_eof(t):(t.type,p.UNKNOWN,this.handle_unknown(t,e))},e.prototype.handle_whitespace_and_comments=function(t,e){var n,i,_,s=t.newlines,a=this._options.keep_array_indentation&&r(this._flags.mode);if(t.comments_before)for(n=t.comments_before.next();n;)this.handle_whitespace_and_comments(n,e),this.handle_token(n,e),n=t.comments_before.next();if(a)for(i=0;ithis._options.max_preserve_newlines&&(s=this._options.max_preserve_newlines),this._options.preserve_newlines&&1this._flags.parent.indentation_level)&&(--this._flags.indentation_level,this._output.set_indent(this._flags.indentation_level,this._flags.alignment))},e.prototype.set_mode=function(t){this._flags?(this._flag_store.push(this._flags),this._previous_flags=this._flags):this._previous_flags=this.create_flags(null,t),this._flags=this.create_flags(this._previous_flags,t),this._output.set_indent(this._flags.indentation_level,this._flags.alignment)},e.prototype.restore_mode=function(){0"!==this._flags.last_token.text)&&(l(this._flags.last_token.type,[p.EQUALS,p.START_EXPR,p.COMMA,p.OPERATOR])||c(this._flags.last_token,["return","throw","import","default"]))?this.set_mode(s):this.set_mode(o),this._flags.last_token&&c(this._flags.last_token.previous,["class","extends"])&&(this._flags.class_start_block=!0),n=(e=!n.comments_before&&"}"===n.text)&&"function"===this._flags.last_word&&this._flags.last_token.type===p.END_EXPR,this._options.brace_preserve_inline){i=0,this._flags.inline_frame=!(_=null);do{if((_=this._tokens.peek((i+=1)-1)).newlines){this._flags.inline_frame=!1;break}}while(_.type!==p.EOF&&(_.type!==p.END_BLOCK||_.opened!==t))}("expand"===this._options.brace_style||"none"===this._options.brace_style&&t.newlines)&&!this._flags.inline_frame?this._flags.last_token.type!==p.OPERATOR&&(n||this._flags.last_token.type===p.EQUALS||c(this._flags.last_token,d)&&"else"!==this._flags.last_token.text)?this._output.space_before_token=!0:this.print_newline(!1,!0):(!r(this._previous_flags.mode)||this._flags.last_token.type!==p.START_EXPR&&this._flags.last_token.type!==p.COMMA||(this._flags.last_token.type!==p.COMMA&&!this._options.space_in_paren||(this._output.space_before_token=!0),(this._flags.last_token.type===p.COMMA||this._flags.last_token.type===p.START_EXPR&&this._flags.inline_frame)&&(this.allow_wrap_or_preserved_newline(t),this._previous_flags.multiline_frame=this._previous_flags.multiline_frame||this._flags.multiline_frame,this._flags.multiline_frame=!1)),this._flags.last_token.type!==p.OPERATOR&&this._flags.last_token.type!==p.START_EXPR&&(l(this._flags.last_token.type,[p.START_BLOCK,p.SEMICOLON])&&!this._flags.inline_frame?this.print_newline():this._output.space_before_token=!0)),this.print_token(t),this.indent(),e||this._options.brace_preserve_inline&&this._flags.inline_frame||this.print_newline()},e.prototype.handle_end_block=function(t){for(this.handle_whitespace_and_comments(t);this._flags.mode===h;)this.restore_mode();var e=this._flags.last_token.type===p.START_BLOCK;this._flags.inline_frame&&!e?this._output.space_before_token=!0:"expand"===this._options.brace_style?e||this.print_newline():e||(r(this._flags.mode)&&this._options.keep_array_indentation?(this._options.keep_array_indentation=!1,this.print_newline(),this._options.keep_array_indentation=!0):this.print_newline()),this.restore_mode(),this.print_token(t)},e.prototype.handle_word=function(t){var e;if(t.type===p.RESERVED&&(l(t.text,["set","get"])&&this._flags.mode!==s||"import"===t.text&&l(this._tokens.peek().text,["(","."])||l(t.text,["as","from"])&&!this._flags.import_block||this._flags.mode===s&&":"===this._tokens.peek().text)&&(t.type=p.WORD),this.start_of_statement(t)?c(this._flags.last_token,["var","let","const"])&&t.type===p.WORD&&(this._flags.declaration_statement=!0):!t.newlines||A(this._flags.mode)||this._flags.last_token.type===p.OPERATOR&&"--"!==this._flags.last_token.text&&"++"!==this._flags.last_token.text||this._flags.last_token.type===p.EQUALS||!this._options.preserve_newlines&&c(this._flags.last_token,["var","let","const","set","get"])?this.handle_whitespace_and_comments(t):(this.handle_whitespace_and_comments(t),this.print_newline()),this._flags.do_block&&!this._flags.do_while){if(i(t,"while"))return this._output.space_before_token=!0,this.print_token(t),this._output.space_before_token=!0,void(this._flags.do_while=!0);this.print_newline(),this._flags.do_block=!1}if(this._flags.if_block)if(!this._flags.else_block&&i(t,"else"))this._flags.else_block=!0;else{for(;this._flags.mode===h;)this.restore_mode();this._flags.if_block=!1,this._flags.else_block=!1}return this._flags.in_case_statement&&c(t,["case","default"])?(this.print_newline(),this._flags.case_block||!this._flags.case_body&&!this._options.jslint_happy||this.deindent(),this._flags.case_body=!1,this.print_token(t),void(this._flags.in_case=!0)):(this._flags.last_token.type!==p.COMMA&&this._flags.last_token.type!==p.START_EXPR&&this._flags.last_token.type!==p.EQUALS&&this._flags.last_token.type!==p.OPERATOR||this.start_of_object_property()||l(this._flags.last_token.text,["+","-"])&&":"===this._last_last_text&&this._flags.parent.mode===s||this.allow_wrap_or_preserved_newline(t),i(t,"function")?((l(this._flags.last_token.text,["}",";"])||this._output.just_added_newline()&&!l(this._flags.last_token.text,["(","[","{",":","=",","])&&this._flags.last_token.type!==p.OPERATOR)&&(this._output.just_added_blankline()||t.comments_before||(this.print_newline(),this.print_newline(!0))),this._flags.last_token.type===p.RESERVED||this._flags.last_token.type===p.WORD?c(this._flags.last_token,["get","set","new","export"])||c(this._flags.last_token,y)||i(this._flags.last_token,"default")&&"export"===this._last_last_text||"declare"===this._flags.last_token.text?this._output.space_before_token=!0:this.print_newline():this._flags.last_token.type===p.OPERATOR||"="===this._flags.last_token.text?this._output.space_before_token=!0:!this._flags.multiline_frame&&(A(this._flags.mode)||r(this._flags.mode))||this.print_newline(),this.print_token(t),void(this._flags.last_word=t.text)):(e="NONE",this._flags.last_token.type===p.END_BLOCK?this._previous_flags.inline_frame?e="SPACE":!c(t,["else","catch","finally","from"])||"expand"===this._options.brace_style||"end-expand"===this._options.brace_style||"none"===this._options.brace_style&&t.newlines?e="NEWLINE":(e="SPACE",this._output.space_before_token=!0):this._flags.last_token.type===p.SEMICOLON&&this._flags.mode===o?e="NEWLINE":this._flags.last_token.type===p.SEMICOLON&&A(this._flags.mode)?e="SPACE":this._flags.last_token.type===p.STRING?e="NEWLINE":this._flags.last_token.type===p.RESERVED||this._flags.last_token.type===p.WORD||"*"===this._flags.last_token.text&&(l(
+this._last_last_text,["function","yield"])||this._flags.mode===s&&l(this._last_last_text,["{",","]))?e="SPACE":this._flags.last_token.type===p.START_BLOCK?e=this._flags.inline_frame?"SPACE":"NEWLINE":this._flags.last_token.type===p.END_EXPR&&(this._output.space_before_token=!0,e="NEWLINE"),c(t,O)&&")"!==this._flags.last_token.text&&(e=this._flags.inline_frame||"else"===this._flags.last_token.text||"export"===this._flags.last_token.text?"SPACE":"NEWLINE"),c(t,["else","catch","finally"])?(this._flags.last_token.type!==p.END_BLOCK||this._previous_flags.mode!==o||"expand"===this._options.brace_style||"end-expand"===this._options.brace_style||"none"===this._options.brace_style&&t.newlines)&&!this._flags.inline_frame?this.print_newline():(this._output.trim(!0),"}"!==this._output.current_line.last()&&this.print_newline(),this._output.space_before_token=!0):"NEWLINE"===e?c(this._flags.last_token,d)||"declare"===this._flags.last_token.text&&c(t,["var","let","const"])?this._output.space_before_token=!0:this._flags.last_token.type!==p.END_EXPR?this._flags.last_token.type===p.START_EXPR&&c(t,["var","let","const"])||":"===this._flags.last_token.text||(i(t,"if")&&i(t.previous,"else")?this._output.space_before_token=!0:this.print_newline()):c(t,O)&&")"!==this._flags.last_token.text&&this.print_newline():this._flags.multiline_frame&&r(this._flags.mode)&&","===this._flags.last_token.text&&"}"===this._last_last_text?this.print_newline():"SPACE"===e&&(this._output.space_before_token=!0),!t.previous||t.previous.type!==p.WORD&&t.previous.type!==p.RESERVED||(this._output.space_before_token=!0),this.print_token(t),this._flags.last_word=t.text,void(t.type===p.RESERVED&&("do"===t.text?this._flags.do_block=!0:"if"===t.text?this._flags.if_block=!0:"import"===t.text?this._flags.import_block=!0:this._flags.import_block&&i(t,"from")&&(this._flags.import_block=!1)))))},e.prototype.handle_semicolon=function(t){this.start_of_statement(t)?this._output.space_before_token=!1:this.handle_whitespace_and_comments(t);for(var e=this._tokens.peek();!(this._flags.mode!==h||this._flags.if_block&&i(e,"else")||this._flags.do_block);)this.restore_mode();this._flags.import_block&&(this._flags.import_block=!1),this.print_token(t)},e.prototype.handle_string=function(t){t.text.startsWith("`")&&0===t.newlines&&""===t.whitespace_before&&(")"===t.previous.text||this._flags.last_token.type===p.WORD)||(this.start_of_statement(t)?this._output.space_before_token=!0:(this.handle_whitespace_and_comments(t),this._flags.last_token.type===p.RESERVED||this._flags.last_token.type===p.WORD||this._flags.inline_frame?this._output.space_before_token=!0:this._flags.last_token.type===p.COMMA||this._flags.last_token.type===p.START_EXPR||this._flags.last_token.type===p.EQUALS||this._flags.last_token.type===p.OPERATOR?this.start_of_object_property()||this.allow_wrap_or_preserved_newline(t):!t.text.startsWith("`")||this._flags.last_token.type!==p.END_EXPR||"]"!==t.previous.text&&")"!==t.previous.text||0!==t.newlines?this.print_newline():this._output.space_before_token=!0)),this.print_token(t)},e.prototype.handle_equals=function(t){this.start_of_statement(t)||this.handle_whitespace_and_comments(t),this._flags.declaration_statement&&(this._flags.declaration_assignment=!0),this._output.space_before_token=!0,this.print_token(t),this._output.space_before_token=!0},e.prototype.handle_comma=function(t){this.handle_whitespace_and_comments(t,!0),this.print_token(t),this._output.space_before_token=!0,this._flags.declaration_statement?(A(this._flags.parent.mode)&&(this._flags.declaration_assignment=!1),this._flags.declaration_assignment?(this._flags.declaration_assignment=!1,this.print_newline(!1,!0)):this._options.comma_first&&this.allow_wrap_or_preserved_newline(t)):this._flags.mode===s||this._flags.mode===h&&this._flags.parent.mode===s?(this._flags.mode===h&&this.restore_mode(),this._flags.inline_frame||this.print_newline()):this._options.comma_first&&this.allow_wrap_or_preserved_newline(t)},e.prototype.handle_operator=function(t){var e,n,i,_,s,a,r="*"===t.text&&(c(this._flags.last_token,["function","yield"])||l(this._flags.last_token.type,[p.START_BLOCK,p.COMMA,p.END_BLOCK,p.SEMICOLON])),u=l(t.text,["-","+"])&&(l(this._flags.last_token.type,[p.START_BLOCK,p.START_EXPR,p.EQUALS,p.OPERATOR])||l(this._flags.last_token.text,O)||","===this._flags.last_token.text);if(this.start_of_statement(t)||this.handle_whitespace_and_comments(t,!r),"*"!==t.text||this._flags.last_token.type!==p.DOT)if("::"!==t.text)if(l(t.text,["-","+"])&&this.start_of_object_property())this.print_token(t);else{if(this._flags.last_token.type===p.OPERATOR&&l(this._options.operator_position,g)&&this.allow_wrap_or_preserved_newline(t),":"===t.text&&this._flags.in_case)return this.print_token(t),this._flags.in_case=!1,this._flags.case_body=!0,void(this._tokens.peek().type!==p.START_BLOCK?(this.indent(),this.print_newline(),this._flags.case_block=!1):(this._flags.case_block=!0,this._output.space_before_token=!0));if(a=!(n=e=!0),":"===t.text?0===this._flags.ternary_depth?e=!1:(--this._flags.ternary_depth,a=!0):"?"===t.text&&(this._flags.ternary_depth+=1),!u&&!r&&this._options.preserve_newlines&&l(t.text,T))switch(_=(i=":"===t.text)&&a,s=i&&!a,this._options.operator_position){case f.before_newline:return this._output.space_before_token=!s,this.print_token(t),i&&!_||this.allow_wrap_or_preserved_newline(t),void(this._output.space_before_token=!0);case f.after_newline:return this._output.space_before_token=!0,!i||_?this._tokens.peek().newlines?this.print_newline(!1,!0):this.allow_wrap_or_preserved_newline(t):this._output.space_before_token=!1,this.print_token(t),void(this._output.space_before_token=!0);case f.preserve_newline:return s||this.allow_wrap_or_preserved_newline(t),e=!(this._output.just_added_newline()||s),this._output.space_before_token=e,this.print_token(t),void(this._output.space_before_token=!0)}r?(this.allow_wrap_or_preserved_newline(t),e=!1,n=(a=this._tokens.peek())&&l(a.type,[p.WORD,p.RESERVED])
+):"..."===t.text?(this.allow_wrap_or_preserved_newline(t),e=this._flags.last_token.type===p.START_BLOCK,n=!1):(l(t.text,["--","++","!","~"])||u)&&(this._flags.last_token.type!==p.COMMA&&this._flags.last_token.type!==p.START_EXPR||this.allow_wrap_or_preserved_newline(t),n=e=!1,!t.newlines||"--"!==t.text&&"++"!==t.text&&"~"!==t.text||((r=c(this._flags.last_token,d)&&t.newlines)&&(this._previous_flags.if_block||this._previous_flags.else_block)&&this.restore_mode(),this.print_newline(r,!0)),";"===this._flags.last_token.text&&A(this._flags.mode)&&(e=!0),this._flags.last_token.type===p.RESERVED?e=!0:this._flags.last_token.type===p.END_EXPR?e=!("]"===this._flags.last_token.text&&("--"===t.text||"++"===t.text)):this._flags.last_token.type===p.OPERATOR&&(e=l(t.text,["--","-","++","+"])&&l(this._flags.last_token.text,["--","-","++","+"]),l(t.text,["+","-"])&&l(this._flags.last_token.text,["--","++"])&&(n=!0)),(this._flags.mode!==o||this._flags.inline_frame)&&this._flags.mode!==h||"{"!==this._flags.last_token.text&&";"!==this._flags.last_token.text||this.print_newline()),this._output.space_before_token=this._output.space_before_token||e,this.print_token(t),this._output.space_before_token=n}else this.print_token(t);else this.print_token(t)},e.prototype.handle_block_comment=function(t,e){return this._output.raw?(this._output.add_raw_token(t),void(t.directives&&"end"===t.directives.preserve&&(this._output.raw=this._options.test_output_raw))):t.directives?(this.print_newline(!1,e),this.print_token(t),"start"===t.directives.preserve&&(this._output.raw=!0),void this.print_newline(!1,!0)):void(x.newline.test(t.text)||t.newlines?this.print_block_commment(t,e):(this._output.space_before_token=!0,this.print_token(t),this._output.space_before_token=!0))},e.prototype.print_block_commment=function(t,e){var n,i,_,s=function(t){for(var e=[],n=(t=t.replace(x.allLineBreaks,"\n")).indexOf("\n");-1!==n;)e.push(t.substring(0,n)),n=(t=t.substring(n+1)).indexOf("\n");return t.length&&e.push(t),e}(t.text),a=t.whitespace_before,r=a.length;if(this.print_newline(!1,e),this.print_token_line_indentation(t),this._output.add_token(s[0]),this.print_newline(!1,e),1this.__parent.wrap_line_length&&this.__wrap_point_character_count>this.__parent.next_line.__character_count},_.prototype._allow_wrap=function(){var t;return!!this._should_wrap()&&(this.__parent.add_new_line(),(t=this.__parent.current_line).set_indent(this.__wrap_point_indent_count,this.__wrap_point_alignment_count),t.__items=this.__items.slice(
+this.__wrap_point_index),this.__items=this.__items.slice(0,this.__wrap_point_index),t.__character_count+=this.__character_count-this.__wrap_point_character_count,this.__character_count=this.__wrap_point_character_count," "===t.__items[0]&&(t.__items.splice(0,1),--t.__character_count),!0)},_.prototype.is_empty=function(){return 0===this.__items.length},_.prototype.last=function(){return this.is_empty()?null:this.__items[this.__items.length-1]},_.prototype.push=function(t){this.__items.push(t);var e=t.lastIndexOf("\n");-1!==e?this.__character_count=t.length-e:this.__character_count+=t.length},_.prototype.pop=function(){var t=null;return this.is_empty()||(t=this.__items.pop(),this.__character_count-=t.length),t},_.prototype._remove_indent=function(){0=this.__cache.length;)this.__add_column()},n.prototype.__add_column=function(){var t,e=this.__cache.length,n="";this.__indent_size&&e>=this.__indent_size&&(e-=(t=Math.floor(e/this.__indent_size))*this.__indent_size,n=new Array(t+1).join(this.__indent_string)),e&&(n+=new Array(e+1).join(" ")),this.__cache.push(n)},e.prototype.__add_outputline=function(){this.previous_line=this.current_line,this.current_line=this.next_line.clone_empty(),this.__lines.push(this.current_line)},e.prototype.get_line_number=function(){return this.__lines.length},e.prototype.get_indent_string=function(t,e){return this.__indent_cache.get_indent_string(t,e)},e.prototype.get_indent_size=function(t,e){return this.__indent_cache.get_indent_size(t,e)},e.prototype.is_empty=function(){return!this.previous_line&&this.current_line.is_empty()},e.prototype.add_new_line=function(t){return!(this.is_empty()||!t&&this.just_added_newline())&&(this.raw||this.__add_outputline(),!0)},e.prototype.get_code=function(t){var e;return this.trim(!0),(e=this.current_line.pop())&&("\n"===e[e.length-1]&&(e=e.replace(/\n+$/g,"")),this.current_line.push(e)),this._end_with_newline&&this.__add_outputline(),e=this.__lines.join("\n"),e="\n"!==t?e.replace(/[\n]/g,t):e},e.prototype.set_wrap_point=function(){this.current_line._set_wrap_point()},e.prototype.set_indent=function(t,e){return this.next_line.set_indent(t=t||0,e=e||0),1>> === !== &&= ??= ||= << && >= ** != == <= >> || ?? |> < / - + > : & % ? ^ | *".split(" "),s=(s="\\?\\.(?!\\d) "+(s=(s=">>>= ... >>= <<= === >>> !== **= &&= ??= ||= => ^= :: /= << <= == && -= >= >> != -- += ** || ?? ++ %= &= *= |= |> = ! ? > < : / ^ - + * & % ~ |").replace(/[-[\]{}()*+?.,\\^$|#]/g,"\\$&"))).replace(/ /g,"|"),c=new RegExp(s),s=(a="continue,try,throw,return,var,let,const,if,switch,case,default,for,while,break,function,import,export".split(",")).concat(["do","in","of","else","get","set","new","catch","finally","typeof","yield","async","await","from","as","class","extends"]),d=new RegExp("^(?:"+s.join("|")+")$"),((s=function(t,e){
-g.call(this,t,e),this._patterns.whitespace=this._patterns.whitespace.matching(/\u00A0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff/.source,/\u2028\u2029/.source),t=new b(this._input),e=new m(this._input).read_options(this._options),this.__patterns={template:e,identifier:e.starting_with(h.identifier).matching(h.identifierMatch),number:t.matching(n),punct:t.matching(c),comment:t.starting_with(/\/\//).until(/[\n\r\u2028\u2029]/),block_comment:t.starting_with(/\/\*/).until_after(/\*\//),html_comment_start:t.matching(//),include:t.starting_with(/#include/).until_after(h.lineBreak),shebang:t.starting_with(/#!/).until_after(h.lineBreak),xml:t.matching(/[\s\S]*?<(\/?)([-a-zA-Z:0-9_.]+|{[^}]+?}|!\[CDATA\[[^\]]*?\]\]|)(\s*{[^}]+?}|\s+[-a-zA-Z:0-9_.]+|\s+[-a-zA-Z:0-9_.]+\s*=\s*('[^']*'|"[^"]*"|{([^{}]|{[^}]+?})+?}))*\s*(\/?)\s*>/),single_quote:e.until(/['\\\n\r\u2028\u2029]/),double_quote:e.until(/["\\\n\r\u2028\u2029]/),template_text:e.until(/[`\\$]/),template_expression:e.until(/[`}\\]/)}}).prototype=new g)._is_comment=function(t){return t.type===o.COMMENT||t.type===o.BLOCK_COMMENT||t.type===o.UNKNOWN},s.prototype._is_opening=function(t){return t.type===o.START_BLOCK||t.type===o.START_EXPR},s.prototype._is_closing=function(t,e){return(t.type===o.END_BLOCK||t.type===o.END_EXPR)&&e&&("]"===t.text&&"["===e.text||")"===t.text&&"("===e.text||"}"===t.text&&"{"===e.text)},s.prototype._reset=function(){_=!1},s.prototype._get_next_token=function(t,e){var n;return this._readWhitespace(),null===(n=this._input.peek())?this._create_token(o.EOF,""):this._read_non_javascript(n)||this._read_string(n)||this._read_word(t)||this._read_singles(n)||this._read_comment(n)||this._read_regexp(n,t)||this._read_xml(n,t)||this._read_punctuation()||this._create_token(o.UNKNOWN,this._input.next())},s.prototype._read_word=function(t){var e=this.__patterns.identifier.read();return""!==e?(e=e.replace(h.allLineBreaks,"\n"),t.type!==o.DOT&&(t.type!==o.RESERVED||"set"!==t.text&&"get"!==t.text)&&d.test(e)?"in"!==e&&"of"!==e||t.type!==o.WORD&&t.type!==o.STRING?this._create_token(o.RESERVED,e):this._create_token(o.OPERATOR,e):this._create_token(o.WORD,e)):""!==(e=this.__patterns.number.read())?this._create_token(o.WORD,e):void 0},s.prototype._read_singles=function(t){var e=null;return"("===t||"["===t?e=this._create_token(o.START_EXPR,t):")"===t||"]"===t?e=this._create_token(o.END_EXPR,t):"{"===t?e=this._create_token(o.START_BLOCK,t):"}"===t?e=this._create_token(o.END_BLOCK,t):";"===t?e=this._create_token(o.SEMICOLON,t):"."===t&&l.test(this._input.peek(1))?e=this._create_token(o.DOT,t):","===t&&(e=this._create_token(o.COMMA,t)),e&&this._input.next(),e},s.prototype._read_punctuation=function(){var t=this.__patterns.punct.read();if(""!==t)return"="===t?this._create_token(o.EQUALS,t):"?."===t?this._create_token(o.DOT,t):this._create_token(o.OPERATOR,t)},s.prototype._read_non_javascript=function(t){var e,n="";if("#"===t){if(this._is_first_token()&&(n=this.__patterns.shebang.read()))return this._create_token(o.UNKNOWN,n.trim()+"\n");if(n=this.__patterns.include.read())return this._create_token(o.UNKNOWN,n.trim()+"\n");if(t=this._input.next(),e="#",this._input.hasNext()&&this._input.testChar(p)){for(;e+=t=this._input.next(),this._input.hasNext()&&"#"!==t&&"="!==t;);return"#"===t||("["===this._input.peek()&&"]"===this._input.peek(1)?(e+="[]",this._input.next(),this._input.next()):"{"===this._input.peek()&&"}"===this._input.peek(1)&&(e+="{}",this._input.next(),this._input.next())),this._create_token(o.WORD,e)}this._input.back()}else if("<"===t&&this._is_first_token()){if(n=this.__patterns.html_comment_start.read()){for(;this._input.hasNext()&&!this._input.testChar(h.newline);)n+=this._input.next();return _=!0,this._create_token(o.COMMENT,n)}}else if(_&&"-"===t&&(n=this.__patterns.html_comment_end.read()))return _=!1,this._create_token(o.COMMENT,n);return null},s.prototype._read_comment=function(t){var e,n=null;return"/"===t&&(t="","*"===this._input.peek(1)?(t=this.__patterns.block_comment.read(),(e=i.get_directives(t))&&"start"===e.ignore&&(t+=i.readIgnored(this._input)),t=t.replace(h.allLineBreaks,"\n"),(n=this._create_token(o.BLOCK_COMMENT,t)).directives=e):"/"===this._input.peek(1)&&(t=this.__patterns.comment.read(),n=this._create_token(o.COMMENT,t))),n},s.prototype._read_string=function(t){var e;return"`"===t||"'"===t||'"'===t?(e=this._input.next(),this.has_char_escapes=!1,e+="`"===t?this._read_string_recursive("`",!0,"${"):this._read_string_recursive(t),this.has_char_escapes&&this._options.unescape_strings&&(e=function(t){var e="",n=0,i=new f(t),_=null;for(;i.hasNext();)if((_=i.match(/([\s]|[^\\]|\\\\)+/g))&&(e+=_[0]),"\\"===i.peek()){if(i.next(),"x"===i.peek())_=i.match(/x([0-9A-Fa-f]{2})/g);else{if("u"!==i.peek()){e+="\\",i.hasNext()&&(e+=i.next());continue}_=i.match(/u([0-9A-Fa-f]{4})/g)}if(!_)return t;if(126<(n=parseInt(_[1],16))&&n<=255&&0===_[0].indexOf("x"))return t;e+=0<=n&&n<32?"\\"+_[0]:34===n||39===n||92===n?"\\"+String.fromCharCode(n):String.fromCharCode(n)}return e}(e)),this._input.peek()===t&&(e+=this._input.next()),e=e.replace(h.allLineBreaks,"\n"),this._create_token(o.STRING,e)):null},s.prototype._allow_regexp_or_xml=function(t){return t.type===o.RESERVED&&u(t.text,["return","case","throw","else","do","typeof","yield"])||t.type===o.END_EXPR&&")"===t.text&&t.opened.previous.type===o.RESERVED&&u(t.opened.previous.text,["if","while","for"])||u(t.type,[o.COMMENT,o.START_EXPR,o.START_BLOCK,o.START,o.END_BLOCK,o.OPERATOR,o.EQUALS,o.EOF,o.SEMICOLON,o.COMMA])},s.prototype._read_regexp=function(t,e){var n,i,_;if("/"===t&&this._allow_regexp_or_xml(e)){for(n=this._input.next(),_=i=!1;this._input.hasNext()&&(i||_||this._input.peek()!==t)&&!this._input.testChar(h.newline);)n+=this._input.peek(),i?i=!1:(i="\\"===this._input.peek(),"["===this._input.peek()?_=!0:"]"===this._input.peek()&&(_=!1)),this._input.next();return this._input.peek()===t&&(n=(n+=this._input.next())+this._input.read(
-h.identifier)),this._create_token(o.STRING,n)}return null},s.prototype._read_xml=function(t,e){var n,i,_,s,a,u,r;if(this._options.e4x&&"<"===t&&this._allow_regexp_or_xml(e)&&(n="",i=this.__patterns.xml.read_match())){for(s=0===(_=i[2].replace(/^{\s+/,"{").replace(/\s+}$/,"}")).indexOf("{"),a=0;i&&(u=!!i[1],r=i[2],!(!!i[i.length-1]||"![CDATA["===r.slice(0,8))&&(r===_||s&&r.replace(/^{\s+/,"{").replace(/\s+}$/,"}"))&&(u?--a:++a),n+=i[0],!(a<=0));)i=this.__patterns.xml.read_match();return i||(n+=this._input.match(/[\s\S]*/g)[0]),n=n.replace(h.allLineBreaks,"\n"),this._create_token(o.STRING,n)}return null},s.prototype._read_string_recursive=function(t,e,n){var i,_,s,a;for("'"===t?_=this.__patterns.single_quote:'"'===t?_=this.__patterns.double_quote:"`"===t?_=this.__patterns.template_text:"}"===t&&(_=this.__patterns.template_expression),s=_.read(),a="";this._input.hasNext();){if((a=this._input.next())===t||!e&&h.newline.test(a)){this._input.back();break}"\\"===a&&this._input.hasNext()?("x"===(i=this._input.peek())||"u"===i?this.has_char_escapes=!0:"\r"===i&&"\n"===this._input.peek(1)&&this._input.next(),a+=this._input.next()):n&&("${"===n&&"$"===a&&"{"===this._input.peek()&&(a+=this._input.next()),n===a&&(a+="`"===t?this._read_string_recursive("}",e,"`"):this._read_string_recursive("`",e,"${"),this._input.hasNext()&&(a+=this._input.next()))),s+=a+=_.read()}return s},t.exports.Tokenizer=s,t.exports.TOKEN=o,t.exports.positionable_operators=e.slice(),t.exports.line_starters=a.slice()},function(t){var i=RegExp.prototype.hasOwnProperty("sticky");function e(t){this.__input=t||"",this.__input_length=this.__input.length,this.__position=0}e.prototype.restart=function(){this.__position=0},e.prototype.back=function(){0=t.length&&this.__input.substring(e-t.length,e).toLowerCase()===t},t.exports.InputScanner=e},function(t,e,n){var i=n(8).InputScanner,s=n(3).Token,a=n(10).TokenStream,_=n(11).WhitespacePattern,u={START:"TK_START",RAW:"TK_RAW",EOF:"TK_EOF"},n=function(t,e){this._input=new i(t),this._options=e||{},this.__tokens=null,this._patterns={},this._patterns.whitespace=new _(this._input)};n.prototype.tokenize=function(){var t,e,n,i,_;for(this._input.restart(),this.__tokens=new a,this._reset(),e=new s(u.START,""),n=null,i=[],_=new a;e.type!==u.EOF;){for(t=this._get_next_token(e,n);this._is_comment(t);)_.add(t),t=this._get_next_token(e,n);_.isEmpty()||(t.comments_before=_,_=new a),t.parent=n,this._is_opening(t)?(i.push(n),n=t):n&&this._is_closing(t,n)&&((t.opened=n).closed=t,n=i.pop(),t.parent=n),(t.previous=e).next=t,this.__tokens.add(t),e=t}return this.__tokens},n.prototype._is_first_token=function(){return this.__tokens.isEmpty()},n.prototype._reset=function(){},n.prototype._get_next_token=function(t,e){this._readWhitespace();var n=this._input.read(/.+/g);return n?this._create_token(u.RAW,n):this._create_token(u.EOF,"")},n.prototype._is_comment=function(t){return!1},n.prototype._is_opening=function(t){return!1},n.prototype._is_closing=function(t,e){return!1},n.prototype._create_token=function(t,e){return new s(t,e,this._patterns.whitespace.newline_count,this._patterns.whitespace.whitespace_before_token)},n.prototype._readWhitespace=function(){return this._patterns.whitespace.read()},t.exports.Tokenizer=n,t.exports.TOKEN=u},function(t){function e(t){this.__tokens=[],this.__tokens_length=this.__tokens.length,this.__position=0,this.__parent_token=t}e.prototype.restart=function(){this.__position=0},e.prototype.isEmpty=function(){return 0===this.__tokens_length},e.prototype.hasNext=function(){return this.__position/),erb:e.starting_with(/<%[^%]/).until_after(/[^%]%>/),django:e.starting_with(/{%/).until_after(/%}/),django_value:e.starting_with(/{{/).until_after(/}}/),django_comment:e.starting_with(/{#/).until_after(/#}/),smarty:e.starting_with(/{(?=[^}{\s\n])/).until_after(/[^\s\n]}/),smarty_comment:e.starting_with(/{\*/).until_after(/\*}/),smarty_literal:e.starting_with(/{literal}/).until_after(/{\/literal}/)}}(s.prototype=new i)._create=function(){return new s(this._input,this)},s.prototype._update=function(){this.__set_templated_pattern()},s.prototype.disable=function(t){var e=this._create();return e._disabled[t]=!0,e._update(),e},s.prototype.read_options=function(t){var e,n=this._create();for(e in _)n._disabled[e]=-1===t.templating.indexOf(e);return n._update(),n},s.prototype.exclude=function(t){var e=this._create();return e._excluded[t]=!0,e._update(),e},s.prototype.read=function(){for(var t="",t=this._match_pattern?this._input.read(this._starting_pattern):this._input.read(this._starting_pattern,this.__template_pattern),e=this._read_template();e;)this._match_pattern?e+=this._input.read(this._match_pattern):e+=this._input.readUntil(this.__template_pattern),t+=e,e=this._read_template();return this._until_after&&(t+=this._input.readUntilAfter(this._until_pattern)),t},s.prototype.__set_templated_pattern=function(){var t=[];this._disabled.php||t.push(this.__patterns.php._starting_pattern.source),this._disabled.handlebars||t.push(this.__patterns.handlebars._starting_pattern.source),this._disabled.erb||t.push(this.__patterns.erb._starting_pattern.source),this._disabled.django||(t.push(this.__patterns.django._starting_pattern.source),t.push(this.__patterns.django_value._starting_pattern.source),t.push(this.__patterns.django_comment._starting_pattern.source)),this._disabled.smarty||t.push(this.__patterns.smarty._starting_pattern.source),this._until_pattern&&t.push(this._until_pattern.source),this.__template_pattern=this._input.get_regexp("(?:"+t.join("|")+")")},s.prototype._read_template=function(){var t,e="",n=this._input.peek();return"<"===n?(t=this._input.peek(1),this._disabled.php||this._excluded.php||"?"!==t||(e=e||this.__patterns.php.read()),this._disabled.erb||this._excluded.erb||"%"!==t||(e=e||this.__patterns.erb.read())):"{"===n&&(this._disabled.handlebars||this._excluded.handlebars||(e=(e=(e=e||this.__patterns.handlebars_comment.read())||this.__patterns.handlebars_unescaped.read())||this.__patterns.handlebars.read()),this._disabled.django||(this._excluded.django||this._excluded.handlebars||(e=e||this.__patterns.django_value.read()),
-this._excluded.django||(e=(e=e||this.__patterns.django_comment.read())||this.__patterns.django.read())),this._disabled.smarty||this._disabled.django&&this._disabled.handlebars&&(e=(e=(e=e||this.__patterns.smarty_comment.read())||this.__patterns.smarty_literal.read())||this.__patterns.smarty.read())),e},t.exports.TemplatablePattern=s}],i={};t=function _(t){var e=i[t];return e!==undefined||(e=i[t]={exports:{}},n[t](e,e.exports,_)),e.exports}(0),s=t}(),t=s,void 0!==r?r.js_beautify=t:"undefined"!=typeof window?window.js_beautify=t:"undefined"!=typeof global&&(global.js_beautify=t),function(){"use strict";var t,n=[,,function(t){function _(t){this.__parent=t,this.__character_count=0,this.__indent_count=-1,this.__alignment_count=0,this.__wrap_point_index=0,this.__wrap_point_character_count=0,this.__wrap_point_indent_count=-1,this.__wrap_point_alignment_count=0,this.__items=[]}function n(t,e){this.__cache=[""],this.__indent_size=t.indent_size,this.__indent_string=t.indent_char,t.indent_with_tabs||(this.__indent_string=new Array(t.indent_size+1).join(t.indent_char)),e=e||"",0this.__parent.wrap_line_length&&this.__wrap_point_character_count>this.__parent.next_line.__character_count},_.prototype._allow_wrap=function(){var t;return!!this._should_wrap()&&(this.__parent.add_new_line(),(t=this.__parent.current_line).set_indent(this.__wrap_point_indent_count,this.__wrap_point_alignment_count),t.__items=this.__items.slice(this.__wrap_point_index),this.__items=this.__items.slice(0,this.__wrap_point_index),t.__character_count+=this.__character_count-this.__wrap_point_character_count,this.__character_count=this.__wrap_point_character_count," "===t.__items[0]&&(t.__items.splice(0,1),--t.__character_count),!0)},_.prototype.is_empty=function(){return 0===this.__items.length},_.prototype.last=function(){return this.is_empty()?null:this.__items[this.__items.length-1]},_.prototype.push=function(t){this.__items.push(t);var e=t.lastIndexOf("\n");-1!==e?this.__character_count=t.length-e:this.__character_count+=t.length},_.prototype.pop=function(){var t=null;return this.is_empty()||(t=this.__items.pop(),this.__character_count-=t.length),t},_.prototype._remove_indent=function(){0=this.__cache.length;)this.__add_column()},n.prototype.__add_column=function(){var t,e=this.__cache.length,n="";this.__indent_size&&e>=this.__indent_size&&(e-=(t=Math.floor(e/this.__indent_size))*this.__indent_size,n=new Array(t+1).join(this.__indent_string)),e&&(n+=new Array(e+1).join(" ")),this.__cache.push(n)},e.prototype.__add_outputline=function(){this.previous_line=this.current_line,this.current_line=this.next_line.clone_empty(),this.__lines.push(this.current_line)},e.prototype.get_line_number=function(){return this.__lines.length},e.prototype.get_indent_string=function(t,e){return this.__indent_cache.get_indent_string(t,e)},e.prototype.get_indent_size=function(t,e){return this.__indent_cache.get_indent_size(t,e)},e.prototype.is_empty=function(){return!this.previous_line&&this.current_line.is_empty()},e.prototype.add_new_line=function(t){return!(this.is_empty()||!t&&this.just_added_newline())&&(this.raw||this.__add_outputline(),!0)},e.prototype.get_code=function(t){var e;return this.trim(!0),(e=this.current_line.pop())&&("\n"===e[e.length-1]&&(e=e.replace(/\n+$/g,"")),this.current_line.push(e)),this._end_with_newline&&this.__add_outputline(),e=this.__lines.join("\n"),e="\n"!==t?e.replace(/[\n]/g,t):e},e.prototype.set_wrap_point=function(){this.current_line._set_wrap_point()},e.prototype.set_indent=function(t,e){return this.next_line.set_indent(t=t||0,e=e||0),
-1=t.length&&this.__input.substring(e-t.length,e).toLowerCase()===t},t.exports.InputScanner=e},,,,,function(t){function e(t,e){t="string"==typeof t?t:t.source,e="string"==typeof e?e:e.source,this.__directives_block_pattern=new RegExp(t+/ beautify( \w+[:]\w+)+ /.source+e,"g"),this.__directive_pattern=/ (\w+)[:](\w+)/g,this.__directives_end_ignore_pattern=new RegExp(t+/\sbeautify\signore:end\s/.source+e,"g")}e.prototype.get_directives=function(t){var e,n;if(!t.match(this.__directives_block_pattern))return null;for(e={},this.__directive_pattern.lastIndex=0,n=this.__directive_pattern.exec(t);n;)e[n[1]]=n[2],n=this.__directive_pattern.exec(t);return e},e.prototype.readIgnored=function(t){return t.readUntilAfter(this.__directives_end_ignore_pattern)},t.exports.Directives=e},,function(t,e,n){var i=n(16).Beautifier,_=n(17).Options;t.exports=function(t,e){return new i(t,e).beautify()},t.exports.defaultOptions=function(){return new _}},function(t,_,e){var n=e(17).Options,b=e(2).Output,m=e(8).InputScanner,e=e(13).Directives,y=new e(/\/\*/,/\*\//),w=/\r\n|[\r\n]/,k=/\r\n|[\r\n]/g,x=/\s/,v=/(?:\s|\n)+/g,E=/\/\*(?:[\s\S]*?)((?:\*\/)|$)/g,O=/\/\/(?:[^\n\r\u2028\u2029]*)/g;function i(t,e){this._source_text=t||"",this._options=new n(e),this._ch=null,this._input=null,this.NESTED_AT_RULE={"@page":!0,"@font-face":!0,"@keyframes":!0,"@media":!0,"@supports":!0,"@document":!0},this.CONDITIONAL_GROUP_RULE={"@media":!0,"@supports":!0,"@document":!0},this.NON_SEMICOLON_NEWLINE_PROPERTY=["grid-template-areas","grid-template"]}i.prototype.eatString=function(t){var e="";for(this._ch=this._input.next();this._ch;){if(e+=this._ch,"\\"===this._ch)e+=this._input.next();else if(-1!==t.indexOf(this._ch)||"\n"===this._ch)break;this._ch=this._input.next()}return e},i.prototype.eatWhitespace=function(t){for(var e=x.test(this._input.peek()),n=0;x.test(this._input.peek());)this._ch=this._input.next(),t&&"\n"===this._ch&&(0===n||n=this._nestedLevel):this._indentLevel>=this._nestedLevel-1,this._options.newline_between_rules&&n&&this._output.previous_line&&"{"!==this._output.previous_line.item(-1)&&this._output.ensure_empty_line_above("/",","),this._output.space_before_token=!0,"expand"===this._options.brace_style?(this._output.add_new_line(),this.print_string(this._ch),this.indent(),this._output.set_indent(this._indentLevel)):("("===u?this._output.space_before_token=!1:","!==u&&this.indent(),this.print_string(this._ch)),this.eatWhitespace(!0),this._output.add_new_line();else if("}"===this._ch)this.outdent(),this._output.add_new_line(),"{"===u&&this._output.trim(!0),s=l=!1,i&&(this.outdent(),i=!1),this.print_string(this._ch),n=!1,this._nestedLevel&&this._nestedLevel--,this.eatWhitespace(!0),this._output.add_new_line(),this._options.newline_between_rules&&!this._output.just_added_blankline()&&"}"!==this._input.peek()&&this._output.add_new_line(!0),")"===this._input.peek()&&(this._output.trim(!0),"expand"===this._options.brace_style&&this._output.add_new_line(!0));else if(":"===this._ch){for(g=0;g"!==this._ch&&"+"!==this._ch&&"~"!==this._ch||i||0!==e?"]"===this._ch?this.print_string(this._ch):"["===this._ch?(this.preserveSingleSpace(a),this.print_string(this._ch)):"="===this._ch?(this.eatWhitespace(),this.print_string("="),x.test(this._ch)&&(this._ch="")):"!"!==this._ch||this._input.lookBack("\\")?(this.preserveSingleSpace('"'===u||"'"===u||a),this.print_string(this._ch),!this._output.just_added_newline()&&"\n"===this._input.peek()&&f&&this._output.add_new_line()):(this._output.space_before_token=!0,this.print_string(this._ch)):this._options.space_around_combinator?(this._output.space_before_token=!0,this.print_string(this._ch),this._output.space_before_token=!0):(this.print_string(this._ch),this.eatWhitespace(),this._ch&&x.test(this._ch)&&(this._ch=""))}return this._output.get_code(h)},t.exports.Beautifier=i},function(t,e,n){var i=n(6).Options;function _(t){var e,n;for(i.call(this,t,"css"),this.selector_separator_newline=this._get_boolean("selector_separator_newline",!0),this.newline_between_rules=this._get_boolean("newline_between_rules",!0),t=this._get_boolean("space_around_selector_separator"),this.space_around_combinator=this._get_boolean("space_around_combinator")||t,e=this._get_selection_list("brace_style",["collapse","expand","end-expand","none","preserve-inline"]),this.brace_style="collapse",n=0;nthis.__parent.wrap_line_length&&this.__wrap_point_character_count>this.__parent.next_line.__character_count},_.prototype._allow_wrap=function(){var t;return!!this._should_wrap()&&(this.__parent.add_new_line(),(t=this.__parent.current_line).set_indent(this.__wrap_point_indent_count,this.__wrap_point_alignment_count),t.__items=this.__items.slice(this.__wrap_point_index),this.__items=this.__items.slice(0,this.__wrap_point_index),t.__character_count+=this.__character_count-this.__wrap_point_character_count,this.__character_count=this.__wrap_point_character_count," "===t.__items[0]&&(t.__items.splice(0,1),--t.__character_count),!0)},_.prototype.is_empty=function(){return 0===this.__items.length},_.prototype.last=function(){return this.is_empty(
-)?null:this.__items[this.__items.length-1]},_.prototype.push=function(t){this.__items.push(t);var e=t.lastIndexOf("\n");-1!==e?this.__character_count=t.length-e:this.__character_count+=t.length},_.prototype.pop=function(){var t=null;return this.is_empty()||(t=this.__items.pop(),this.__character_count-=t.length),t},_.prototype._remove_indent=function(){0=this.__cache.length;)this.__add_column()},n.prototype.__add_column=function(){var t,e=this.__cache.length,n="";this.__indent_size&&e>=this.__indent_size&&(e-=(t=Math.floor(e/this.__indent_size))*this.__indent_size,n=new Array(t+1).join(this.__indent_string)),e&&(n+=new Array(e+1).join(" ")),this.__cache.push(n)},e.prototype.__add_outputline=function(){this.previous_line=this.current_line,this.current_line=this.next_line.clone_empty(),this.__lines.push(this.current_line)},e.prototype.get_line_number=function(){return this.__lines.length},e.prototype.get_indent_string=function(t,e){return this.__indent_cache.get_indent_string(t,e)},e.prototype.get_indent_size=function(t,e){return this.__indent_cache.get_indent_size(t,e)},e.prototype.is_empty=function(){return!this.previous_line&&this.current_line.is_empty()},e.prototype.add_new_line=function(t){return!(this.is_empty()||!t&&this.just_added_newline())&&(this.raw||this.__add_outputline(),!0)},e.prototype.get_code=function(t){var e;return this.trim(!0),(e=this.current_line.pop())&&("\n"===e[e.length-1]&&(e=e.replace(/\n+$/g,"")),this.current_line.push(e)),this._end_with_newline&&this.__add_outputline(),e=this.__lines.join("\n"),e="\n"!==t?e.replace(/[\n]/g,t):e},e.prototype.set_wrap_point=function(){this.current_line._set_wrap_point()},e.prototype.set_indent=function(t,e){return this.next_line.set_indent(t=t||0,e=e||0),1=t.length&&this.__input.substring(e-t.length,e).toLowerCase()===t},t.exports.InputScanner=e},function(t,e,n){var i=n(8).InputScanner,s=n(3).Token,a=n(10).TokenStream,_=n(11).WhitespacePattern,u={START:"TK_START",RAW:"TK_RAW",EOF:"TK_EOF"},n=function(t,e){this._input=new i(t),this._options=e||{},this.__tokens=null,this._patterns={},this._patterns.whitespace=new _(this._input)};n.prototype.tokenize=function(){var t,e,n,i,_;for(this._input.restart(),this.__tokens=new a,this._reset(),e=new s(u.START,""),n=null,i=[],_=new a;e.type!==u.EOF;){for(t=this._get_next_token(e,n);this._is_comment(t);)_.add(t),t=this._get_next_token(e,n);_.isEmpty()||(t.comments_before=_,_=new a),t.parent=n,this._is_opening(t)?(i.push(n),n=t):n&&this._is_closing(t,n)&&((t.opened=n).closed=t,n=i.pop(),t.parent=n),(t.previous=e).next=t,this.__tokens.add(t),e=t}return this.__tokens},n.prototype._is_first_token=function(){return this.__tokens.isEmpty()},n.prototype._reset=function(){},n.prototype._get_next_token=function(t,e){this._readWhitespace();var n=this._input.read(/.+/g);return n?this._create_token(u.RAW,n):this._create_token(u.EOF,"")},n.prototype._is_comment=function(t){return!1},n.prototype._is_opening=function(t){return!1},n.prototype._is_closing=function(t,e){return!1},n.prototype._create_token=function(t,e){return new s(t,e,this._patterns.whitespace.newline_count,this._patterns.whitespace.whitespace_before_token)},n.prototype._readWhitespace=function(){return this._patterns.whitespace.read()},t.exports.Tokenizer=n,t.exports.TOKEN=u},function(t){function e(t){this.__tokens=[],this.__tokens_length=this.__tokens.length,this.__position=0,this.__parent_token=t}e.prototype.restart=function(){this.__position=0},e.prototype.isEmpty=function(){return 0===this.__tokens_length},e.prototype.hasNext=function(){return this.__position/),erb:e.starting_with(/<%[^%]/).until_after(/[^%]%>/),django:e.starting_with(/{%/).until_after(/%}/),django_value:e.starting_with(/{{/).until_after(/}}/),django_comment:e.starting_with(/{#/).until_after(/#}/),smarty:e.starting_with(/{(?=[^}{\s\n])/).until_after(/[^\s\n]}/),smarty_comment:e.starting_with(/{\*/).until_after(/\*}/),smarty_literal:e.starting_with(/{literal}/).until_after(/{\/literal}/)}}(s.prototype=new i)._create=function(){return new s(this._input,this)},s.prototype._update=function(){this.__set_templated_pattern()},s.prototype.disable=function(t){var e=this._create();return e._disabled[t]=!0,e._update(),e},s.prototype.read_options=function(t){var e,n=this._create();for(e in _)n._disabled[e]=-1===t.templating.indexOf(e);return n._update(),n},s.prototype.exclude=function(t){var e=this._create();return e._excluded[t]=!0,e._update(),e},s.prototype.read=function(){for(var t="",t=this._match_pattern?this._input.read(this._starting_pattern):this._input.read(this._starting_pattern,this.__template_pattern),e=this._read_template();e;)this._match_pattern?e+=this._input.read(this._match_pattern):e+=this._input.readUntil(this.__template_pattern),t+=e,e=this._read_template();return this._until_after&&(t+=this._input.readUntilAfter(this._until_pattern)),t},s.prototype.__set_templated_pattern=function(){var t=[];this._disabled.php||t.push(this.__patterns.php._starting_pattern.source),this._disabled.handlebars||t.push(this.__patterns.handlebars._starting_pattern.source),this._disabled.erb||t.push(this.__patterns.erb._starting_pattern.source),this._disabled.django||(t.push(this.__patterns.django._starting_pattern.source),t.push(this.__patterns.django_value._starting_pattern.source),t.push(this.__patterns.django_comment._starting_pattern.source)),this._disabled.smarty||t.push(this.__patterns.smarty._starting_pattern.source),this._until_pattern&&t.push(this._until_pattern.source),this.__template_pattern=this._input.get_regexp("(?:"+t.join("|")+")")},s.prototype._read_template=function(){var t,e="",n=this._input.peek();return"<"===n?(t=this._input.peek(1),this._disabled.php||this._excluded.php||"?"!==t||(e=e||this.__patterns.php.read()),this._disabled.erb||this._excluded.erb||"%"!==t||(e=e||this.__patterns.erb.read())):"{"===n&&(this._disabled.handlebars||this._excluded.handlebars||(e=(e=(e=e||this.__patterns.handlebars_comment.read())||this.__patterns.handlebars_unescaped.read())||this.__patterns.handlebars.read()),this._disabled.django||(this._excluded.django||this._excluded.handlebars||(e=e||this.__patterns.django_value.read()),this._excluded.django||(e=(e=e||this.__patterns.django_comment.read())||this.__patterns.django.read())),this._disabled.smarty||this._disabled.django&&this._disabled.handlebars&&(e=(e=(
-e=e||this.__patterns.smarty_comment.read())||this.__patterns.smarty_literal.read())||this.__patterns.smarty.read())),e},t.exports.TemplatablePattern=s},,,,function(t,e,n){var _=n(19).Beautifier,i=n(20).Options;t.exports=function(t,e,n,i){return new _(t,e,n,i).beautify()},t.exports.defaultOptions=function(){return new i}},function(e,n,t){var _,s,o,i,u,r=t(20).Options,d=t(2).Output,f=t(21).Tokenizer,h=t(21).TOKEN,g=/\r\n|[\r\n]/,b=/\r\n|[\r\n]/g,p=function(t,e){this.indent_level=0,this.alignment_size=0,this.max_preserve_newlines=t.max_preserve_newlines,this.preserve_newlines=t.preserve_newlines,this._output=new d(t,e)};function a(t,e){return-1!==e.indexOf(t)}function m(t,e,n){this.parent=t||null,this.tag=e?e.tag_name:"",this.indent_level=n||0,this.parser_token=e||null}function l(t){this._printer=t,this._current_frame=null}function c(t,e,n,i){this._source_text=t||"",e=e||{},this._js_beautify=n,this._css_beautify=i,this._tag_stack=null;t=new r(e,"html");this._options=t,this._is_wrap_attributes_force="force"===this._options.wrap_attributes.substr(0,"force".length),this._is_wrap_attributes_force_expand_multiline="force-expand-multiline"===this._options.wrap_attributes,this._is_wrap_attributes_force_aligned="force-aligned"===this._options.wrap_attributes,this._is_wrap_attributes_aligned_multiple="aligned-multiple"===this._options.wrap_attributes,this._is_wrap_attributes_preserve="preserve"===this._options.wrap_attributes.substr(0,"preserve".length),this._is_wrap_attributes_preserve_aligned="preserve-aligned"===this._options.wrap_attributes}p.prototype.current_line_has_match=function(t){return this._output.current_line.has_match(t)},p.prototype.set_space_before_token=function(t,e){this._output.space_before_token=t,this._output.non_breaking_space=e},p.prototype.set_wrap_point=function(){this._output.set_indent(this.indent_level,this.alignment_size),this._output.set_wrap_point()},p.prototype.add_raw_token=function(t){this._output.add_raw_token(t)},p.prototype.print_preserved_newlines=function(t){var e,n=0;for(t.type!==h.TEXT&&t.previous.type!==h.TEXT&&(n=t.newlines?1:0),this.preserve_newlines&&(n=t.newlines|]]>)$/.exec(i)))return void t.add_raw_token(e);s=u+n[1]+"\n",i=n[4],n[5]&&(a=u+n[5]),i=i.replace(/\n[ \t]*$/,""),(n[2]||-1!==n[3].indexOf("\n"))&&(n=n[3].match(/[ \t]+$/))&&(e.whitespace_before=n[0])}i=i&&(_?((n=function(){this.eol="\n"}).prototype=this._options.raw_options,_(u+i,new n)):u+(i=(n=e.whitespace_before)?i.replace(new RegExp("\n("+n+")?","g"),"\n"):i).replace(/\n/g,"\n"+u)),s&&(i=i?s+i+"\n"+a:s+a),t.print_newline(!1),i&&(e.text=i,e.whitespace_before="",e.newlines=0,t.add_raw_token(e),t.print_newline(!0))}},c.prototype._handle_tag_open=function(t,e,n,i){var _=this._get_tag_open_token(e);return!n.is_unformatted&&!n.is_content_unformatted||n.is_empty_element||e.type!==h.TAG_OPEN||0!==e.text.indexOf("")?(t.traverse_whitespace(e),this._set_tag_position(t,e,_,n,i),_.is_inline_element||t.set_wrap_point(),t.print_token(e)):(t.add_raw_token(e),_.start_tag_token=this._tag_stack.try_pop(_.tag_name)),(this._is_wrap_attributes_force_aligned||this._is_wrap_attributes_aligned_multiple||this._is_wrap_attributes_preserve_aligned)&&(_.alignment_size=e.text.length+1),_.tag_complete||_.is_unformatted||(t.alignment_size=_.alignment_size),_},o=function(t,e){var n;this.parent=t||null,this.text="",this.type="TK_TAG_OPEN",this.tag_name="",this.is_inline_element=!1,this.is_unformatted=!1,this.is_content_unformatted=!1,this.is_empty_element=!1,this.is_start_tag=!1,this.is_end_tag=!1,this.indent_content=!1,this.multiline_content=!1,this.custom_beautifier_name=null,this.start_tag_token=null,this.attr_count=0,this.has_wrapped_attrs=!1,this.alignment_size=0,this.tag_complete=!1,this.tag_start_char="",this.tag_check="",e?(this.tag_start_char=e.text[0],this.text=e.text,"<"===this.tag_start_char?(n=e.text.match(/^<([^\s>]*)/),this.tag_check=n?n[1]:""):(n=e.text.match(/^{{~?(?:[\^]|#\*?)?([^\s}]+)/),this.tag_check=n?n[1]:"",(e.text.startsWith("{{#>")||e.text.startsWith("{{~#>"))&&">"===this.tag_check[0]&&(">"===this.tag_check&&null!==e.next?this.tag_check=e.next.text.split(" ")[0]:this.tag_check=e.text.split(">")[1])),this.tag_check=this.tag_check.toLowerCase(),e.type===h.COMMENT&&(this.tag_complete=!0),this.is_start_tag="/"!==this.tag_check.charAt(0),this.tag_name=this.is_start_tag?this.tag_check:this.tag_check.substr(1),this.is_end_tag=!this.is_start_tag||e.closed&&"/>"===e.closed.text,t=2,"{"===this.tag_start_char&&3<=this.text.length&&"~"===this.text.charAt(2)&&(t=3),this.is_end_tag=this.is_end_tag||"{"===this.tag_start_char&&(this.text.length<3||/[^#\^]/.test(this.text.charAt(t)))):this.tag_complete=!0},c.prototype._get_tag_open_token=function(t){t=new o(this._tag_stack.get_parser_token(),t);return t.alignment_size=this._options.wrap_attributes_indent_size,t.is_end_tag=t.is_end_tag||a(t.tag_check,this._options.void_elements),t.is_empty_element=t.tag_complete||t.is_start_tag&&t.is_end_tag,t.is_unformatted=!t.tag_complete&&a(t.tag_check,this._options.unformatted),t.is_content_unformatted=!t.is_empty_element&&a(t.tag_check,this._options.content_unformatted),t.is_inline_element=a(t.tag_name,this._options.inline)||t.tag_name.includes("-")||"{"===t.tag_start_char,t},c.prototype._set_tag_position=function(t,e,n,i,_){n.is_empty_element||(n.is_end_tag?n.start_tag_token=this._tag_stack.try_pop(n.tag_name):(this._do_optional_end_element(n)&&(n.is_inline_element||t.print_newline(!1)),this._tag_stack.record_tag(n),"script"!==n.tag_name&&"style"!==n.tag_name||n.is_unformatted||n.is_content_unformatted||(n.custom_beautifier_name=s(n.tag_check,e)))),a(n.tag_check,this._options.extra_liners)&&(t.print_newline(!1),t._output.just_added_blankline()||t.print_newline(!0)),n.is_empty_element?("{"===n.tag_start_char&&"else"===n.tag_check&&(this._tag_stack.indent_to_tag(["if","unless","each"]),n.indent_content=!0,t.current_line_has_match(/{{#if/)||t.print_newline(!1)),"!--"===n.tag_name&&_.type===h.TAG_CLOSE&&i.is_end_tag&&-1===n.text.indexOf("\n")||(n.is_inline_element||n.is_unformatted||t.print_newline(!1),this._calcluate_parent_multiline(t,n))):n.is_end_tag?(e=!1,e=(e=n.start_tag_token&&n.start_tag_token.multiline_content)||!n.is_inline_element&&!(i.is_inline_element||i.is_unformatted)&&!(_.type===h.TAG_CLOSE&&n.start_tag_token===i)&&"TK_CONTENT"!==_.type,(e=n.is_content_unformatted||n.is_unformatted?!1:e)&&t.print_newline(!1)):(n.indent_content=!n.custom_beautifier_name,"<"===n.tag_start_char&&(
-"html"===n.tag_name?n.indent_content=this._options.indent_inner_html:"head"===n.tag_name?n.indent_content=this._options.indent_head_inner_html:"body"===n.tag_name&&(n.indent_content=this._options.indent_body_inner_html)),n.is_inline_element||n.is_unformatted||"TK_CONTENT"===_.type&&!n.is_content_unformatted||t.print_newline(!1),this._calcluate_parent_multiline(t,n))},c.prototype._calcluate_parent_multiline=function(t,e){!e.parent||!t._output.just_added_newline()||(e.is_inline_element||e.is_unformatted)&&e.parent.is_inline_element||(e.parent.multiline_content=!0)},i=["address","article","aside","blockquote","details","div","dl","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hr","main","nav","ol","p","pre","section","table","ul"],u=["a","audio","del","ins","map","noscript","video"],c.prototype._do_optional_end_element=function(t){var e,n=null;if(!t.is_empty_element&&t.is_start_tag&&t.parent)return"body"===t.tag_name?n=n||this._tag_stack.try_pop("head"):"li"===t.tag_name?n=n||this._tag_stack.try_pop("li",["ol","ul"]):"dd"===t.tag_name||"dt"===t.tag_name?n=(n=n||this._tag_stack.try_pop("dt",["dl"]))||this._tag_stack.try_pop("dd",["dl"]):"p"===t.parent.tag_name&&-1!==i.indexOf(t.tag_name)?(e=t.parent.parent)&&-1!==u.indexOf(e.tag_name)||(n=n||this._tag_stack.try_pop("p")):"rp"===t.tag_name||"rt"===t.tag_name?n=(n=n||this._tag_stack.try_pop("rt",["ruby","rtc"]))||this._tag_stack.try_pop("rp",["ruby","rtc"]):"optgroup"===t.tag_name?n=n||this._tag_stack.try_pop("optgroup",["select"]):"option"===t.tag_name?n=n||this._tag_stack.try_pop("option",["select","datalist","optgroup"]):"colgroup"===t.tag_name?n=n||this._tag_stack.try_pop("caption",["table"]):"thead"===t.tag_name?n=(n=n||this._tag_stack.try_pop("caption",["table"]))||this._tag_stack.try_pop("colgroup",["table"]):"tbody"===t.tag_name||"tfoot"===t.tag_name?n=(n=(n=(n=n||this._tag_stack.try_pop("caption",["table"]))||this._tag_stack.try_pop("colgroup",["table"]))||this._tag_stack.try_pop("thead",["table"]))||this._tag_stack.try_pop("tbody",["table"]):"tr"===t.tag_name?n=(n=(n=n||this._tag_stack.try_pop("caption",["table"]))||this._tag_stack.try_pop("colgroup",["table"]))||this._tag_stack.try_pop("tr",["table","thead","tbody","tfoot"]):"th"!==t.tag_name&&"td"!==t.tag_name||(n=(n=n||this._tag_stack.try_pop("td",["table","thead","tbody","tfoot","tr"]))||this._tag_stack.try_pop("th",["table","thead","tbody","tfoot","tr"])),t.parent=this._tag_stack.get_parser_token(),n},e.exports.Beautifier=c},function(t,e,n){var i=n(6).Options;function _(t){i.call(this,t,"html"),1===this.templating.length&&"auto"===this.templating[0]&&(this.templating=["django","erb","handlebars","php"]),this.indent_inner_html=this._get_boolean("indent_inner_html"),this.indent_body_inner_html=this._get_boolean("indent_body_inner_html",!0),this.indent_head_inner_html=this._get_boolean("indent_head_inner_html",!0),this.indent_handlebars=this._get_boolean("indent_handlebars",!0),this.wrap_attributes=this._get_selection("wrap_attributes",["auto","force","force-aligned","force-expand-multiline","aligned-multiple","preserve","preserve-aligned"]),this.wrap_attributes_indent_size=this._get_number("wrap_attributes_indent_size",this.indent_size),this.extra_liners=this._get_array("extra_liners",["head","body","/html"]),this.inline=this._get_array("inline",["a","abbr","area","audio","b","bdi","bdo","br","button","canvas","cite","code","data","datalist","del","dfn","em","embed","i","iframe","img","input","ins","kbd","keygen","label","map","mark","math","meter","noscript","object","output","progress","q","ruby","s","samp","select","small","span","strong","sub","sup","svg","template","textarea","time","u","var","video","wbr","text","acronym","big","strike","tt"]),this.void_elements=this._get_array("void_elements",["area","base","br","col","embed","hr","img","input","keygen","link","menuitem","meta","param","source","track","wbr","!doctype","?xml","basefont","isindex"]),this.unformatted=this._get_array("unformatted",[]),this.content_unformatted=this._get_array("content_unformatted",["pre","textarea"]),this.unformatted_content_delimiter=this._get_characters("unformatted_content_delimiter"),this.indent_scripts=this._get_selection("indent_scripts",["normal","keep","separate"])}_.prototype=new i,t.exports.Options=_},function(t,o,e){var n=e(9).Tokenizer,i=e(9).TOKEN,_=e(13).Directives,s=e(14).TemplatablePattern,a=e(12).Pattern,u={TAG_OPEN:"TK_TAG_OPEN",TAG_CLOSE:"TK_TAG_CLOSE",ATTRIBUTE:"TK_ATTRIBUTE",EQUALS:"TK_EQUALS",VALUE:"TK_VALUE",COMMENT:"TK_COMMENT",TEXT:"TK_TEXT",UNKNOWN:"TK_UNKNOWN",START:i.START,RAW:i.RAW,EOF:i.EOF},r=new _(/<\!--/,/-->/),e=function(t,e){n.call(this,t,e),this._current_tag_name="",t=new s(this._input).read_options(this._options),e=new a(this._input),this.__patterns={word:t.until(/[\n\r\t <]/),single_quote:t.until_after(/'/),double_quote:t.until_after(/"/),attribute:t.until(/[\n\r\t =>]|\/>/),element_name:t.until(/[\n\r\t >\/]/),handlebars_comment:e.starting_with(/{{!--/).until_after(/--}}/),handlebars:e.starting_with(/{{/).until_after(/}}/),handlebars_open:e.until(/[\n\r\t }]/),handlebars_raw_close:e.until(/}}/),comment:e.starting_with(//),cdata:e.starting_with(//),conditional_comment:e.starting_with(//),processing:e.starting_with(/<\?/).until_after(/\?>/)},this._options.indent_handlebars&&(this.__patterns.word=this.__patterns.word.exclude("handlebars")),this._unformatted_content_delimiter=null,this._options.unformatted_content_delimiter&&(t=this._input.get_literal_regexp(this._options.unformatted_content_delimiter),this.__patterns.unformatted_content_delimiter=e.matching(t).until_after(t))};(e.prototype=new n)._is_comment=function(t){return!1},e.prototype._is_opening=function(t){return t.type===u.TAG_OPEN},e.prototype._is_closing=function(t,e){return t.type===u.TAG_CLOSE&&e&&((">"===t.text||"/>"===t.text
-)&&"<"===e.text[0]||"}}"===t.text&&"{"===e.text[0]&&"{"===e.text[1])},e.prototype._reset=function(){this._current_tag_name=""},e.prototype._get_next_token=function(t,e){var n;return this._readWhitespace(),null===(n=this._input.peek())?this._create_token(u.EOF,""):this._read_open_handlebars(n,e)||this._read_attribute(n,t,e)||this._read_close(n,e)||this._read_raw_content(n,t,e)||this._read_content_word(n)||this._read_comment_or_cdata(n)||this._read_processing(n)||this._read_open(n,e)||this._create_token(u.UNKNOWN,this._input.next())},e.prototype._read_comment_or_cdata=function(t){var e=null,n=null,i=null;return"<"===t&&("!"===this._input.peek(1)&&((n=this.__patterns.comment.read())?(i=r.get_directives(n))&&"start"===i.ignore&&(n+=r.readIgnored(this._input)):n=this.__patterns.cdata.read()),n&&((e=this._create_token(u.COMMENT,n)).directives=i)),e},e.prototype._read_processing=function(t){var e=null,n=null;return"<"===t&&(n="!"!==(t=this._input.peek(1))&&"?"!==t?n:(n=this.__patterns.conditional_comment.read())||this.__patterns.processing.read())&&((e=this._create_token(u.COMMENT,n)).directives=null),e},e.prototype._read_open=function(t,e){var n=null,i=null;return e||"<"===t&&(n=this._input.next(),"/"===this._input.peek()&&(n+=this._input.next()),n+=this.__patterns.element_name.read(),i=this._create_token(u.TAG_OPEN,n)),i},e.prototype._read_open_handlebars=function(t,e){var n=null,i=null;return e||this._options.indent_handlebars&&"{"===t&&"{"===this._input.peek(1)&&(i="!"===this._input.peek(2)?(n=(n=this.__patterns.handlebars_comment.read())||this.__patterns.handlebars.read(),this._create_token(u.COMMENT,n)):(n=this.__patterns.handlebars_open.read(),this._create_token(u.TAG_OPEN,n))),i},e.prototype._read_close=function(t,e){var n=null,i=null;return e&&("<"===e.text[0]&&(">"===t||"/"===t&&">"===this._input.peek(1))?(n=this._input.next(),"/"===t&&(n+=this._input.next()),i=this._create_token(u.TAG_CLOSE,n)):"{"===e.text[0]&&"}"===t&&"}"===this._input.peek(1)&&(this._input.next(),this._input.next(),i=this._create_token(u.TAG_CLOSE,"}}"))),i},e.prototype._read_attribute=function(t,e,n){var i=null;return n&&"<"===n.text[0]&&("="===t?i=this._create_token(u.EQUALS,this._input.next()):'"'===t||"'"===t?(n=this._input.next(),n+=('"'===t?this.__patterns.double_quote:this.__patterns.single_quote).read(),i=this._create_token(u.VALUE,n)):(t=this.__patterns.attribute.read())&&(i=e.type===u.EQUALS?this._create_token(u.VALUE,t):this._create_token(u.ATTRIBUTE,t))),i},e.prototype._is_content_unformatted=function(t){return-1===this._options.void_elements.indexOf(t)&&(-1!==this._options.content_unformatted.indexOf(t)||-1!==this._options.unformatted.indexOf(t))},e.prototype._read_raw_content=function(t,e,n){var i="";if(n&&"{"===n.text[0])i=this.__patterns.handlebars_raw_close.read();else if(e.type===u.TAG_CLOSE&&"<"===e.opened.text[0]&&"/"!==e.text[0])if("script"===(n=e.opened.text.substr(1).toLowerCase())||"style"===n){if(e=this._read_comment_or_cdata(t))return e.type=u.TEXT,e;i=this._input.readUntil(new RegExp(""+n+"[\\n\\r\\t ]*?>","ig"))}else this._is_content_unformatted(n)&&(i=this._input.readUntil(new RegExp(""+n+"[\\n\\r\\t ]*?>","ig")));return i?this._create_token(u.TEXT,i):null},e.prototype._read_content_word=function(t){var e="";if(e=(e=this._options.unformatted_content_delimiter&&t===this._options.unformatted_content_delimiter[0]?this.__patterns.unformatted_content_delimiter.read():e)||this.__patterns.word.read())return this._create_token(u.TEXT,e)},t.exports.Tokenizer=e,t.exports.TOKEN=u}],i={};t=function _(t){var e=i[t];return e!==undefined||(e=i[t]={exports:{}},n[t](e,e.exports,_)),e.exports}(18),u=t}(),n=u,void 0!==r?(_=i=r).html_beautify=function(t,e){return n(t,e,i.js_beautify,_.css_beautify)}:"undefined"!=typeof window?window.html_beautify=function(t,e){return n(t,e,window.js_beautify,window.css_beautify)}:"undefined"!=typeof global&&(global.html_beautify=function(t,e){return n(t,e,global.js_beautify,global.css_beautify)})},"@VERSION@");
\ No newline at end of file
+_="\\u0300-\\u036f\\u0483-\\u0487\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u0620-\\u0649\\u0672-\\u06d3\\u06e7-\\u06e8\\u06fb-\\u06fc\\u0730-\\u074a\\u0800-\\u0814\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0840-\\u0857\\u08e4-\\u08fe\\u0900-\\u0903\\u093a-\\u093c\\u093e-\\u094f\\u0951-\\u0957\\u0962-\\u0963\\u0966-\\u096f\\u0981-\\u0983\\u09bc\\u09be-\\u09c4\\u09c7\\u09c8\\u09d7\\u09df-\\u09e0\\u0a01-\\u0a03\\u0a3c\\u0a3e-\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a66-\\u0a71\\u0a75\\u0a81-\\u0a83\\u0abc\\u0abe-\\u0ac5\\u0ac7-\\u0ac9\\u0acb-\\u0acd\\u0ae2-\\u0ae3\\u0ae6-\\u0aef\\u0b01-\\u0b03\\u0b3c\\u0b3e-\\u0b44\\u0b47\\u0b48\\u0b4b-\\u0b4d\\u0b56\\u0b57\\u0b5f-\\u0b60\\u0b66-\\u0b6f\\u0b82\\u0bbe-\\u0bc2\\u0bc6-\\u0bc8\\u0bca-\\u0bcd\\u0bd7\\u0be6-\\u0bef\\u0c01-\\u0c03\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62-\\u0c63\\u0c66-\\u0c6f\\u0c82\\u0c83\\u0cbc\\u0cbe-\\u0cc4\\u0cc6-\\u0cc8\\u0cca-\\u0ccd\\u0cd5\\u0cd6\\u0ce2-\\u0ce3\\u0ce6-\\u0cef\\u0d02\\u0d03\\u0d46-\\u0d48\\u0d57\\u0d62-\\u0d63\\u0d66-\\u0d6f\\u0d82\\u0d83\\u0dca\\u0dcf-\\u0dd4\\u0dd6\\u0dd8-\\u0ddf\\u0df2\\u0df3\\u0e34-\\u0e3a\\u0e40-\\u0e45\\u0e50-\\u0e59\\u0eb4-\\u0eb9\\u0ec8-\\u0ecd\\u0ed0-\\u0ed9\\u0f18\\u0f19\\u0f20-\\u0f29\\u0f35\\u0f37\\u0f39\\u0f41-\\u0f47\\u0f71-\\u0f84\\u0f86-\\u0f87\\u0f8d-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u1000-\\u1029\\u1040-\\u1049\\u1067-\\u106d\\u1071-\\u1074\\u1082-\\u108d\\u108f-\\u109d\\u135d-\\u135f\\u170e-\\u1710\\u1720-\\u1730\\u1740-\\u1750\\u1772\\u1773\\u1780-\\u17b2\\u17dd\\u17e0-\\u17e9\\u180b-\\u180d\\u1810-\\u1819\\u1920-\\u192b\\u1930-\\u193b\\u1951-\\u196d\\u19b0-\\u19c0\\u19c8-\\u19c9\\u19d0-\\u19d9\\u1a00-\\u1a15\\u1a20-\\u1a53\\u1a60-\\u1a7c\\u1a7f-\\u1a89\\u1a90-\\u1a99\\u1b46-\\u1b4b\\u1b50-\\u1b59\\u1b6b-\\u1b73\\u1bb0-\\u1bb9\\u1be6-\\u1bf3\\u1c00-\\u1c22\\u1c40-\\u1c49\\u1c5b-\\u1c7d\\u1cd0-\\u1cd2\\u1d00-\\u1dbe\\u1e01-\\u1f15\\u200c\\u200d\\u203f\\u2040\\u2054\\u20d0-\\u20dc\\u20e1\\u20e5-\\u20f0\\u2d81-\\u2d96\\u2de0-\\u2dff\\u3021-\\u3028\\u3099\\u309a\\ua640-\\ua66d\\ua674-\\ua67d\\ua69f\\ua6f0-\\ua6f1\\ua7f8-\\ua800\\ua806\\ua80b\\ua823-\\ua827\\ua880-\\ua881\\ua8b4-\\ua8c4\\ua8d0-\\ua8d9\\ua8f3-\\ua8f7\\ua900-\\ua909\\ua926-\\ua92d\\ua930-\\ua945\\ua980-\\ua983\\ua9b3-\\ua9c0\\uaa00-\\uaa27\\uaa40-\\uaa41\\uaa4c-\\uaa4d\\uaa50-\\uaa59\\uaa7b\\uaae0-\\uaae9\\uaaf2-\\uaaf3\\uabc0-\\uabe1\\uabec\\uabed\\uabf0-\\uabf9\\ufb20-\\ufb28\\ufe00-\\ufe0f\\ufe20-\\ufe26\\ufe33\\ufe34\\ufe4d-\\ufe4f\\uff10-\\uff19\\uff3f",s="\\\\u[0-9a-fA-F]{4}|\\\\u\\{[0-9a-fA-F]+\\}",a="(?:"+s+"|[\\x23\\x24\\x40\\x41-\\x5a\\x5f\\x61-\\x7a"+i+"])";e.identifier=new RegExp(
+a+"(?:\\\\u[0-9a-fA-F]{4}|\\\\u\\{[0-9a-fA-F]+\\}|[\\x24\\x30-\\x39\\x41-\\x5a\\x5f\\x61-\\x7a\\xaa\\xb5\\xba\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\u02c1\\u02c6-\\u02d1\\u02e0-\\u02e4\\u02ec\\u02ee\\u0370-\\u0374\\u0376\\u0377\\u037a-\\u037d\\u0386\\u0388-\\u038a\\u038c\\u038e-\\u03a1\\u03a3-\\u03f5\\u03f7-\\u0481\\u048a-\\u0527\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05d0-\\u05ea\\u05f0-\\u05f2\\u0620-\\u064a\\u066e\\u066f\\u0671-\\u06d3\\u06d5\\u06e5\\u06e6\\u06ee\\u06ef\\u06fa-\\u06fc\\u06ff\\u0710\\u0712-\\u072f\\u074d-\\u07a5\\u07b1\\u07ca-\\u07ea\\u07f4\\u07f5\\u07fa\\u0800-\\u0815\\u081a\\u0824\\u0828\\u0840-\\u0858\\u08a0\\u08a2-\\u08ac\\u0904-\\u0939\\u093d\\u0950\\u0958-\\u0961\\u0971-\\u0977\\u0979-\\u097f\\u0985-\\u098c\\u098f\\u0990\\u0993-\\u09a8\\u09aa-\\u09b0\\u09b2\\u09b6-\\u09b9\\u09bd\\u09ce\\u09dc\\u09dd\\u09df-\\u09e1\\u09f0\\u09f1\\u0a05-\\u0a0a\\u0a0f\\u0a10\\u0a13-\\u0a28\\u0a2a-\\u0a30\\u0a32\\u0a33\\u0a35\\u0a36\\u0a38\\u0a39\\u0a59-\\u0a5c\\u0a5e\\u0a72-\\u0a74\\u0a85-\\u0a8d\\u0a8f-\\u0a91\\u0a93-\\u0aa8\\u0aaa-\\u0ab0\\u0ab2\\u0ab3\\u0ab5-\\u0ab9\\u0abd\\u0ad0\\u0ae0\\u0ae1\\u0b05-\\u0b0c\\u0b0f\\u0b10\\u0b13-\\u0b28\\u0b2a-\\u0b30\\u0b32\\u0b33\\u0b35-\\u0b39\\u0b3d\\u0b5c\\u0b5d\\u0b5f-\\u0b61\\u0b71\\u0b83\\u0b85-\\u0b8a\\u0b8e-\\u0b90\\u0b92-\\u0b95\\u0b99\\u0b9a\\u0b9c\\u0b9e\\u0b9f\\u0ba3\\u0ba4\\u0ba8-\\u0baa\\u0bae-\\u0bb9\\u0bd0\\u0c05-\\u0c0c\\u0c0e-\\u0c10\\u0c12-\\u0c28\\u0c2a-\\u0c33\\u0c35-\\u0c39\\u0c3d\\u0c58\\u0c59\\u0c60\\u0c61\\u0c85-\\u0c8c\\u0c8e-\\u0c90\\u0c92-\\u0ca8\\u0caa-\\u0cb3\\u0cb5-\\u0cb9\\u0cbd\\u0cde\\u0ce0\\u0ce1\\u0cf1\\u0cf2\\u0d05-\\u0d0c\\u0d0e-\\u0d10\\u0d12-\\u0d3a\\u0d3d\\u0d4e\\u0d60\\u0d61\\u0d7a-\\u0d7f\\u0d85-\\u0d96\\u0d9a-\\u0db1\\u0db3-\\u0dbb\\u0dbd\\u0dc0-\\u0dc6\\u0e01-\\u0e30\\u0e32\\u0e33\\u0e40-\\u0e46\\u0e81\\u0e82\\u0e84\\u0e87\\u0e88\\u0e8a\\u0e8d\\u0e94-\\u0e97\\u0e99-\\u0e9f\\u0ea1-\\u0ea3\\u0ea5\\u0ea7\\u0eaa\\u0eab\\u0ead-\\u0eb0\\u0eb2\\u0eb3\\u0ebd\\u0ec0-\\u0ec4\\u0ec6\\u0edc-\\u0edf\\u0f00\\u0f40-\\u0f47\\u0f49-\\u0f6c\\u0f88-\\u0f8c\\u1000-\\u102a\\u103f\\u1050-\\u1055\\u105a-\\u105d\\u1061\\u1065\\u1066\\u106e-\\u1070\\u1075-\\u1081\\u108e\\u10a0-\\u10c5\\u10c7\\u10cd\\u10d0-\\u10fa\\u10fc-\\u1248\\u124a-\\u124d\\u1250-\\u1256\\u1258\\u125a-\\u125d\\u1260-\\u1288\\u128a-\\u128d\\u1290-\\u12b0\\u12b2-\\u12b5\\u12b8-\\u12be\\u12c0\\u12c2-\\u12c5\\u12c8-\\u12d6\\u12d8-\\u1310\\u1312-\\u1315\\u1318-\\u135a\\u1380-\\u138f\\u13a0-\\u13f4\\u1401-\\u166c\\u166f-\\u167f\\u1681-\\u169a\\u16a0-\\u16ea\\u16ee-\\u16f0\\u1700-\\u170c\\u170e-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176c\\u176e-\\u1770\\u1780-\\u17b3\\u17d7\\u17dc\\u1820-\\u1877\\u1880-\\u18a8\\u18aa\\u18b0-\\u18f5\\u1900-\\u191c\\u1950-\\u196d\\u1970-\\u1974\\u1980-\\u19ab\\u19c1-\\u19c7\\u1a00-\\u1a16\\u1a20-\\u1a54\\u1aa7\\u1b05-\\u1b33\\u1b45-\\u1b4b\\u1b83-\\u1ba0\\u1bae\\u1baf\\u1bba-\\u1be5\\u1c00-\\u1c23\\u1c4d-\\u1c4f\\u1c5a-\\u1c7d\\u1ce9-\\u1cec\\u1cee-\\u1cf1\\u1cf5\\u1cf6\\u1d00-\\u1dbf\\u1e00-\\u1f15\\u1f18-\\u1f1d\\u1f20-\\u1f45\\u1f48-\\u1f4d\\u1f50-\\u1f57\\u1f59\\u1f5b\\u1f5d\\u1f5f-\\u1f7d\\u1f80-\\u1fb4\\u1fb6-\\u1fbc\\u1fbe\\u1fc2-\\u1fc4\\u1fc6-\\u1fcc\\u1fd0-\\u1fd3\\u1fd6-\\u1fdb\\u1fe0-\\u1fec\\u1ff2-\\u1ff4\\u1ff6-\\u1ffc\\u2071\\u207f\\u2090-\\u209c\\u2102\\u2107\\u210a-\\u2113\\u2115\\u2119-\\u211d\\u2124\\u2126\\u2128\\u212a-\\u212d\\u212f-\\u2139\\u213c-\\u213f\\u2145-\\u2149\\u214e\\u2160-\\u2188\\u2c00-\\u2c2e\\u2c30-\\u2c5e\\u2c60-\\u2ce4\\u2ceb-\\u2cee\\u2cf2\\u2cf3\\u2d00-\\u2d25\\u2d27\\u2d2d\\u2d30-\\u2d67\\u2d6f\\u2d80-\\u2d96\\u2da0-\\u2da6\\u2da8-\\u2dae\\u2db0-\\u2db6\\u2db8-\\u2dbe\\u2dc0-\\u2dc6\\u2dc8-\\u2dce\\u2dd0-\\u2dd6\\u2dd8-\\u2dde\\u2e2f\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303c\\u3041-\\u3096\\u309d-\\u309f\\u30a1-\\u30fa\\u30fc-\\u30ff\\u3105-\\u312d\\u3131-\\u318e\\u31a0-\\u31ba\\u31f0-\\u31ff\\u3400-\\u4db5\\u4e00-\\u9fcc\\ua000-\\ua48c\\ua4d0-\\ua4fd\\ua500-\\ua60c\\ua610-\\ua61f\\ua62a\\ua62b\\ua640-\\ua66e\\ua67f-\\ua697\\ua6a0-\\ua6ef\\ua717-\\ua71f\\ua722-\\ua788\\ua78b-\\ua78e\\ua790-\\ua793\\ua7a0-\\ua7aa\\ua7f8-\\ua801\\ua803-\\ua805\\ua807-\\ua80a\\ua80c-\\ua822\\ua840-\\ua873\\ua882-\\ua8b3\\ua8f2-\\ua8f7\\ua8fb\\ua90a-\\ua925\\ua930-\\ua946\\ua960-\\ua97c\\ua984-\\ua9b2\\ua9cf\\uaa00-\\uaa28\\uaa40-\\uaa42\\uaa44-\\uaa4b\\uaa60-\\uaa76\\uaa7a\\uaa80-\\uaaaf\\uaab1\\uaab5\\uaab6\\uaab9-\\uaabd\\uaac0\\uaac2\\uaadb-\\uaadd\\uaae0-\\uaaea\\uaaf2-\\uaaf4\\uab01-\\uab06\\uab09-\\uab0e\\uab11-\\uab16\\uab20-\\uab26\\uab28-\\uab2e\\uabc0-\\uabe2\\uac00-\\ud7a3\\ud7b0-\\ud7c6\\ud7cb-\\ud7fb\\uf900-\\ufa6d\\ufa70-\\ufad9\\ufb00-\\ufb06\\ufb13-\\ufb17\\ufb1d\\ufb1f-\\ufb28\\ufb2a-\\ufb36\\ufb38-\\ufb3c\\ufb3e\\ufb40\\ufb41\\ufb43\\ufb44\\ufb46-\\ufbb1\\ufbd3-\\ufd3d\\ufd50-\\ufd8f\\ufd92-\\ufdc7\\ufdf0-\\ufdfb\\ufe70-\\ufe74\\ufe76-\\ufefc\\uff21-\\uff3a\\uff41-\\uff5a\\uff66-\\uffbe\\uffc2-\\uffc7\\uffca-\\uffcf\\uffd2-\\uffd7\\uffda-\\uffdc\\u0300-\\u036f\\u0483-\\u0487\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u0620-\\u0649\\u0672-\\u06d3\\u06e7-\\u06e8\\u06fb-\\u06fc\\u0730-\\u074a\\u0800-\\u0814\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0840-\\u0857\\u08e4-\\u08fe\\u0900-\\u0903\\u093a-\\u093c\\u093e-\\u094f\\u0951-\\u0957\\u0962-\\u0963\\u0966-\\u096f\\u0981-\\u0983\\u09bc\\u09be-\\u09c4\\u09c7\\u09c8\\u09d7\\u09df-\\u09e0\\u0a01-\\u0a03\\u0a3c\\u0a3e-\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a66-\\u0a71\\u0a75\\u0a81-\\u0a83\\u0abc\\u0abe-\\u0ac5\\u0ac7-\\u0ac9\\u0acb-\\u0acd\\u0ae2-\\u0ae3\\u0ae6-\\u0aef\\u0b01-\\u0b03\\u0b3c\\u0b3e-\\u0b44\\u0b47\\u0b48\\u0b4b-\\u0b4d\\u0b56\\u0b57\\u0b5f-\\u0b60\\u0b66-\\u0b6f\\u0b82\\u0bbe-\\u0bc2\\u0bc6-\\u0bc8\\u0bca-\\u0bcd\\u0bd7\\u0be6-\\u0bef\\u0c01-\\u0c03\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62-\\u0c63\\u0c66-\\u0c6f\\u0c82\\u0c83\\u0cbc\\u0cbe-\\u0cc4\\u0cc6-\\u0cc8\\u0cca-\\u0ccd\\u0cd5\\u0cd6\\u0ce2-\\u0ce3\\u0ce6-\\u0cef\\u0d02\\u0d03\\u0d46-\\u0d48\\u0d57\\u0d62-\\u0d63\\u0d66-\\u0d6f\\u0d82\\u0d83\\u0dca\\u0dcf-\\u0dd4\\u0dd6\\u0dd8-\\u0ddf\\u0df2\\u0df3\\u0e34-\\u0e3a\\u0e40-\\u0e45\\u0e50-\\u0e59\\u0eb4-\\u0eb9\\u0ec8-\\u0ecd\\u0ed0-\\u0ed9\\u0f18\\u0f19\\u0f20-\\u0f29\\u0f35\\u0f37\\u0f39\\u0f41-\\u0f47\\u0f71-\\u0f84\\u0f86-\\u0f87\\u0f8d-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u1000-\\u1029\\u1040-\\u1049\\u1067-\\u106d\\u1071-\\u1074\\u1082-\\u108d\\u108f-\\u109d\\u135d-\\u135f\\u170e-\\u1710\\u1720-\\u1730\\u1740-\\u1750\\u1772\\u1773\\u1780-\\u17b2\\u17dd\\u17e0-\\u17e9\\u180b-\\u180d\\u1810-\\u1819\\u1920-\\u192b\\u1930-\\u193b\\u1951-\\u196d\\u19b0-\\u19c0\\u19c8-\\u19c9\\u19d0-\\u19d9\\u1a00-\\u1a15\\u1a20-\\u1a53\\u1a60-\\u1a7c\\u1a7f-\\u1a89\\u1a90-\\u1a99\\u1b46-\\u1b4b\\u1b50-\\u1b59\\u1b6b-\\u1b73\\u1bb0-\\u1bb9\\u1be6-\\u1bf3\\u1c00-\\u1c22\\u1c40-\\u1c49\\u1c5b-\\u1c7d\\u1cd0-\\u1cd2\\u1d00-\\u1dbe\\u1e01-\\u1f15\\u200c\\u200d\\u203f\\u2040\\u2054\\u20d0-\\u20dc\\u20e1\\u20e5-\\u20f0\\u2d81-\\u2d96\\u2de0-\\u2dff\\u3021-\\u3028\\u3099\\u309a\\ua640-\\ua66d\\ua674-\\ua67d\\ua69f\\ua6f0-\\ua6f1\\ua7f8-\\ua800\\ua806\\ua80b\\ua823-\\ua827\\ua880-\\ua881\\ua8b4-\\ua8c4\\ua8d0-\\ua8d9\\ua8f3-\\ua8f7\\ua900-\\ua909\\ua926-\\ua92d\\ua930-\\ua945\\ua980-\\ua983\\ua9b3-\\ua9c0\\uaa00-\\uaa27\\uaa40-\\uaa41\\uaa4c-\\uaa4d\\uaa50-\\uaa59\\uaa7b\\uaae0-\\uaae9\\uaaf2-\\uaaf3\\uabc0-\\uabe1\\uabec\\uabed\\uabf0-\\uabf9\\ufb20-\\ufb28\\ufe00-\\ufe0f\\ufe20-\\ufe26\\ufe33\\ufe34\\ufe4d-\\ufe4f\\uff10-\\uff19\\uff3f])*"
+,"g"),e.identifierStart=new RegExp(a),e.identifierMatch=new RegExp("(?:"+s+"|["+n+i+_+"])+"),e.newline=/[\n\r\u2028\u2029]/,e.lineBreak=new RegExp("\r\n|"+e.newline.source),e.allLineBreaks=new RegExp(e.lineBreak.source,"g")},function(t,e,n){var i=n(6).Options,_=["before-newline","after-newline","preserve-newline"];function s(t){var e,n;for(i.call(this,t,"js"),"expand-strict"===(t=this.raw_options.brace_style||null)?this.raw_options.brace_style="expand":"collapse-preserve-inline"===t?this.raw_options.brace_style="collapse,preserve-inline":this.raw_options.braces_on_own_line!==undefined&&(this.raw_options.brace_style=this.raw_options.braces_on_own_line?"expand":"collapse"),e=this._get_selection_list("brace_style",["collapse","expand","end-expand","none","preserve-inline"]),this.brace_preserve_inline=!1,this.brace_style="collapse",n=0;n>> === !== &&= ??= ||= << && >= ** != == <= >> || ?? |> < / - + > : & % ? ^ | *".split(" "),s=(s="\\?\\.(?!\\d) "+(s=(s=">>>= ... >>= <<= === >>> !== **= &&= ??= ||= => ^= :: /= << <= == && -= >= >> != -- += ** || ?? ++ %= &= *= |= |> = ! ? > < : / ^ - + * & % ~ |").replace(/[-[\]{}()*+?.,\\^$|#]/g,"\\$&"))).replace(/ /g,"|"),c=new RegExp(s),s=(a="continue,try,throw,return,var,let,const,if,switch,case,default,for,while,break,function,import,export".split(",")).concat(["do","in","of","else","get","set","new","catch","finally","typeof","yield","async","await","from","as","class","extends"]),d=new RegExp("^(?:"+s.join("|")+")$"),((s=function(t,e){g.call(
+this,t,e),this._patterns.whitespace=this._patterns.whitespace.matching(/\u00A0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff/.source,/\u2028\u2029/.source),t=new b(this._input),e=new m(this._input).read_options(this._options),this.__patterns={template:e,identifier:e.starting_with(h.identifier).matching(h.identifierMatch),number:t.matching(n),punct:t.matching(c),comment:t.starting_with(/\/\//).until(/[\n\r\u2028\u2029]/),block_comment:t.starting_with(/\/\*/).until_after(/\*\//),html_comment_start:t.matching(//),include:t.starting_with(/#include/).until_after(h.lineBreak),shebang:t.starting_with(/#!/).until_after(h.lineBreak),xml:t.matching(/[\s\S]*?<(\/?)([-a-zA-Z:0-9_.]+|{[^}]+?}|!\[CDATA\[[^\]]*?\]\]|)(\s*{[^}]+?}|\s+[-a-zA-Z:0-9_.]+|\s+[-a-zA-Z:0-9_.]+\s*=\s*('[^']*'|"[^"]*"|{([^{}]|{[^}]+?})+?}))*\s*(\/?)\s*>/),single_quote:e.until(/['\\\n\r\u2028\u2029]/),double_quote:e.until(/["\\\n\r\u2028\u2029]/),template_text:e.until(/[`\\$]/),template_expression:e.until(/[`}\\]/)}}).prototype=new g)._is_comment=function(t){return t.type===o.COMMENT||t.type===o.BLOCK_COMMENT||t.type===o.UNKNOWN},s.prototype._is_opening=function(t){return t.type===o.START_BLOCK||t.type===o.START_EXPR},s.prototype._is_closing=function(t,e){return(t.type===o.END_BLOCK||t.type===o.END_EXPR)&&e&&("]"===t.text&&"["===e.text||")"===t.text&&"("===e.text||"}"===t.text&&"{"===e.text)},s.prototype._reset=function(){_=!1},s.prototype._get_next_token=function(t,e){var n;return this._readWhitespace(),null===(n=this._input.peek())?this._create_token(o.EOF,""):this._read_non_javascript(n)||this._read_string(n)||this._read_pair(n,this._input.peek(1))||this._read_word(t)||this._read_singles(n)||this._read_comment(n)||this._read_regexp(n,t)||this._read_xml(n,t)||this._read_punctuation()||this._create_token(o.UNKNOWN,this._input.next())},s.prototype._read_word=function(t){var e=this.__patterns.identifier.read();return""!==e?(e=e.replace(h.allLineBreaks,"\n"),t.type!==o.DOT&&(t.type!==o.RESERVED||"set"!==t.text&&"get"!==t.text)&&d.test(e)?"in"!==e&&"of"!==e||t.type!==o.WORD&&t.type!==o.STRING?this._create_token(o.RESERVED,e):this._create_token(o.OPERATOR,e):this._create_token(o.WORD,e)):""!==(e=this.__patterns.number.read())?this._create_token(o.WORD,e):void 0},s.prototype._read_singles=function(t){var e=null;return"("===t||"["===t?e=this._create_token(o.START_EXPR,t):")"===t||"]"===t?e=this._create_token(o.END_EXPR,t):"{"===t?e=this._create_token(o.START_BLOCK,t):"}"===t?e=this._create_token(o.END_BLOCK,t):";"===t?e=this._create_token(o.SEMICOLON,t):"."===t&&l.test(this._input.peek(1))?e=this._create_token(o.DOT,t):","===t&&(e=this._create_token(o.COMMA,t)),e&&this._input.next(),e},s.prototype._read_pair=function(t,e){var n=null;return(n="#"===t&&"{"===e?this._create_token(o.START_BLOCK,t+e):n)&&(this._input.next(),this._input.next()),n},s.prototype._read_punctuation=function(){var t=this.__patterns.punct.read();if(""!==t)return"="===t?this._create_token(o.EQUALS,t):"?."===t?this._create_token(o.DOT,t):this._create_token(o.OPERATOR,t)},s.prototype._read_non_javascript=function(t){var e,n="";if("#"===t){if(this._is_first_token()&&(n=this.__patterns.shebang.read()))return this._create_token(o.UNKNOWN,n.trim()+"\n");if(n=this.__patterns.include.read())return this._create_token(o.UNKNOWN,n.trim()+"\n");if(t=this._input.next(),e="#",this._input.hasNext()&&this._input.testChar(p)){for(;e+=t=this._input.next(),this._input.hasNext()&&"#"!==t&&"="!==t;);return"#"===t||("["===this._input.peek()&&"]"===this._input.peek(1)?(e+="[]",this._input.next(),this._input.next()):"{"===this._input.peek()&&"}"===this._input.peek(1)&&(e+="{}",this._input.next(),this._input.next())),this._create_token(o.WORD,e)}this._input.back()}else if("<"===t&&this._is_first_token()){if(n=this.__patterns.html_comment_start.read()){for(;this._input.hasNext()&&!this._input.testChar(h.newline);)n+=this._input.next();return _=!0,this._create_token(o.COMMENT,n)}}else if(_&&"-"===t&&(n=this.__patterns.html_comment_end.read()))return _=!1,this._create_token(o.COMMENT,n);return null},s.prototype._read_comment=function(t){var e,n=null;return"/"===t&&(t="","*"===this._input.peek(1)?(t=this.__patterns.block_comment.read(),(e=i.get_directives(t))&&"start"===e.ignore&&(t+=i.readIgnored(this._input)),t=t.replace(h.allLineBreaks,"\n"),(n=this._create_token(o.BLOCK_COMMENT,t)).directives=e):"/"===this._input.peek(1)&&(t=this.__patterns.comment.read(),n=this._create_token(o.COMMENT,t))),n},s.prototype._read_string=function(t){var e;return"`"===t||"'"===t||'"'===t?(e=this._input.next(),this.has_char_escapes=!1,e+="`"===t?this._read_string_recursive("`",!0,"${"):this._read_string_recursive(t),this.has_char_escapes&&this._options.unescape_strings&&(e=function(t){var e="",n=0,i=new f(t),_=null;for(;i.hasNext();)if((_=i.match(/([\s]|[^\\]|\\\\)+/g))&&(e+=_[0]),"\\"===i.peek()){if(i.next(),"x"===i.peek())_=i.match(/x([0-9A-Fa-f]{2})/g);else{if("u"!==i.peek()){e+="\\",i.hasNext()&&(e+=i.next());continue}_=(_=i.match(/u([0-9A-Fa-f]{4})/g))||i.match(/u\{([0-9A-Fa-f]+)\}/g)}if(!_)return t;if(126<(n=parseInt(_[1],16))&&n<=255&&0===_[0].indexOf("x"))return t;e+=0<=n&&n<32||1114111=t.length&&this.__input.substring(e-t.length,e).toLowerCase()===t},t.exports.InputScanner=e},function(t,e,n){var i=n(8).InputScanner,s=n(3).Token,a=n(10).TokenStream,_=n(11).WhitespacePattern,r={START:"TK_START",RAW:"TK_RAW",EOF:"TK_EOF"},n=function(t,e){this._input=new i(t),this._options=e||{},this.__tokens=null,this._patterns={},this._patterns.whitespace=new _(this._input)};n.prototype.tokenize=function(){var t,e,n,i,_;for(this._input.restart(),this.__tokens=new a,this._reset(),e=new s(r.START,""),n=null,i=[],_=new a;e.type!==r.EOF;){for(t=this._get_next_token(e,n);this._is_comment(t);)_.add(t),t=this._get_next_token(e,n);_.isEmpty()||(t.comments_before=_,_=new a),t.parent=n,this._is_opening(t)?(i.push(n),n=t):n&&this._is_closing(t,n)&&((t.opened=n).closed=t,n=i.pop(),t.parent=n),(t.previous=e).next=t,this.__tokens.add(t),e=t}return this.__tokens},n.prototype._is_first_token=function(){return this.__tokens.isEmpty()},n.prototype._reset=function(){},n.prototype._get_next_token=function(t,e){this._readWhitespace();var n=this._input.read(/.+/g);return n?this._create_token(r.RAW,n):this._create_token(r.EOF,"")},n.prototype._is_comment=function(t){return!1},n.prototype._is_opening=function(t){return!1},n.prototype._is_closing=function(t,e){return!1},n.prototype._create_token=function(t,e){return new s(t,e,this._patterns.whitespace.newline_count,this._patterns.whitespace.whitespace_before_token)},n.prototype._readWhitespace=function(){return this._patterns.whitespace.read()},t.exports.Tokenizer=n,t.exports.TOKEN=r},function(t){function e(t){this.__tokens=[],this.__tokens_length=this.__tokens.length,this.__position=0,this.__parent_token=t}e.prototype.restart=function(){this.__position=0},e.prototype.isEmpty=function(){return 0===this.__tokens_length},e.prototype.hasNext=function(){return this.__position/),erb:e.starting_with(/<%[^%]/).until_after(/[^%]%>/),django:e.starting_with(/{%/).until_after(/%}/),django_value:e.starting_with(/{{/).until_after(/}}/),django_comment:e.starting_with(/{#/).until_after(/#}/),smarty:e.starting_with(/{(?=[^}{\s\n])/).until_after(/[^\s\n]}/),smarty_comment:e.starting_with(/{\*/).until_after(/\*}/),smarty_literal:e.starting_with(/{literal}/).until_after(/{\/literal}/)}}(s.prototype=new i)._create=function(){return new s(this._input,this)},s.prototype._update=function(){this.__set_templated_pattern()},s.prototype.disable=function(t){var e=this._create();return e._disabled[t]=!0,e._update(),e},s.prototype.read_options=function(t){var e,n=this._create();for(e in _)n._disabled[e]=-1===t.templating.indexOf(e);return n._update(),n},s.prototype.exclude=function(t){var e=this._create();return e._excluded[t]=!0,e._update(),e},s.prototype.read=function(){for(var t="",t=this._match_pattern?this._input.read(this._starting_pattern):this._input.read(this._starting_pattern,this.__template_pattern),e=this._read_template();e;)this._match_pattern?e+=this._input.read(this._match_pattern):e+=this._input.readUntil(this.__template_pattern),t+=e,e=this._read_template();return this._until_after&&(t+=this._input.readUntilAfter(this._until_pattern)),t},s.prototype.__set_templated_pattern=function(){var t=[];this._disabled.php||t.push(this.__patterns.php._starting_pattern.source),this._disabled.handlebars||t.push(this.__patterns.handlebars._starting_pattern.source),this._disabled.erb||t.push(this.__patterns.erb._starting_pattern.source),this._disabled.django||(t.push(this.__patterns.django._starting_pattern.source),t.push(this.__patterns.django_value._starting_pattern.source),t.push(this.__patterns.django_comment._starting_pattern.source)),this._disabled.smarty||t.push(this.__patterns.smarty._starting_pattern.source),this._until_pattern&&t.push(this._until_pattern.source),this.__template_pattern=this._input.get_regexp("(?:"+t.join("|")+")")},s.prototype._read_template=function(){var t,e="",n=this._input.peek();return"<"===n?(t=this._input.peek(1),this._disabled.php||this._excluded.php||"?"!==t||(e=e||this.__patterns.php.read()),this._disabled.erb||this._excluded.erb||"%"!==t||(e=e||this.__patterns.erb.read())):"{"===n&&(
+this._disabled.handlebars||this._excluded.handlebars||(e=(e=(e=e||this.__patterns.handlebars_comment.read())||this.__patterns.handlebars_unescaped.read())||this.__patterns.handlebars.read()),this._disabled.django||(this._excluded.django||this._excluded.handlebars||(e=e||this.__patterns.django_value.read()),this._excluded.django||(e=(e=e||this.__patterns.django_comment.read())||this.__patterns.django.read())),this._disabled.smarty||this._disabled.django&&this._disabled.handlebars&&(e=(e=(e=e||this.__patterns.smarty_comment.read())||this.__patterns.smarty_literal.read())||this.__patterns.smarty.read())),e},t.exports.TemplatablePattern=s}],i={};t=function _(t){var e=i[t];return e!==undefined||(e=i[t]={exports:{}},n[t](e,e.exports,_)),e.exports}(0),s=t}(),t=s,void 0!==u?u.js_beautify=t:"undefined"!=typeof window?window.js_beautify=t:"undefined"!=typeof global&&(global.js_beautify=t),function(){"use strict";var t,n=[,,function(t){function _(t){this.__parent=t,this.__character_count=0,this.__indent_count=-1,this.__alignment_count=0,this.__wrap_point_index=0,this.__wrap_point_character_count=0,this.__wrap_point_indent_count=-1,this.__wrap_point_alignment_count=0,this.__items=[]}function n(t,e){this.__cache=[""],this.__indent_size=t.indent_size,this.__indent_string=t.indent_char,t.indent_with_tabs||(this.__indent_string=new Array(t.indent_size+1).join(t.indent_char)),e=e||"",0this.__parent.wrap_line_length&&this.__wrap_point_character_count>this.__parent.next_line.__character_count},_.prototype._allow_wrap=function(){var t;return!!this._should_wrap()&&(this.__parent.add_new_line(),(t=this.__parent.current_line).set_indent(this.__wrap_point_indent_count,this.__wrap_point_alignment_count),t.__items=this.__items.slice(this.__wrap_point_index),this.__items=this.__items.slice(0,this.__wrap_point_index),t.__character_count+=this.__character_count-this.__wrap_point_character_count,this.__character_count=this.__wrap_point_character_count," "===t.__items[0]&&(t.__items.splice(0,1),--t.__character_count),!0)},_.prototype.is_empty=function(){return 0===this.__items.length},_.prototype.last=function(){return this.is_empty()?null:this.__items[this.__items.length-1]},_.prototype.push=function(t){this.__items.push(t);var e=t.lastIndexOf("\n");-1!==e?this.__character_count=t.length-e:this.__character_count+=t.length},_.prototype.pop=function(){var t=null;return this.is_empty()||(t=this.__items.pop(),this.__character_count-=t.length),t},_.prototype._remove_indent=function(){0=this.__cache.length;)this.__add_column()},n.prototype.__add_column=function(){var t,e=this.__cache.length,n="";this.__indent_size&&e>=this.__indent_size&&(e-=(t=Math.floor(e/this.__indent_size))*this.__indent_size,n=new Array(t+1).join(this.__indent_string)),e&&(n+=new Array(e+1).join(" ")),this.__cache.push(n)},e.prototype.__add_outputline=function(){this.previous_line=this.current_line,this.current_line=this.next_line.clone_empty(),this.__lines.push(this.current_line)},e.prototype.get_line_number=function(){return this.__lines.length},e.prototype.get_indent_string=function(t,e){return this.__indent_cache.get_indent_string(t,e)},e.prototype.get_indent_size=function(t,e){return this.__indent_cache.get_indent_size(t,e)},e.prototype.is_empty=function(){return!this.previous_line&&this.current_line.is_empty()},e.prototype.add_new_line=function(t){return!(this.is_empty()||!t&&this.just_added_newline())&&(this.raw||this.__add_outputline(),!0)},e.prototype.get_code=function(t){var e;return this.trim(!0),(e=this.current_line.pop())&&("\n"===e[e.length-1]&&(e=e.replace(/\n+$/g,
+"")),this.current_line.push(e)),this._end_with_newline&&this.__add_outputline(),e=this.__lines.join("\n"),e="\n"!==t?e.replace(/[\n]/g,t):e},e.prototype.set_wrap_point=function(){this.current_line._set_wrap_point()},e.prototype.set_indent=function(t,e){return this.next_line.set_indent(t=t||0,e=e||0),1=t.length&&this.__input.substring(e-t.length,e).toLowerCase()===t},t.exports.InputScanner=e},,,,,function(t){function e(t,e){t="string"==typeof t?t:t.source,e="string"==typeof e?e:e.source,this.__directives_block_pattern=new RegExp(t+/ beautify( \w+[:]\w+)+ /.source+e,"g"),this.__directive_pattern=/ (\w+)[:](\w+)/g,this.__directives_end_ignore_pattern=new RegExp(t+/\sbeautify\signore:end\s/.source+e,"g")}e.prototype.get_directives=function(t){var e,n;if(!t.match(this.__directives_block_pattern))return null;for(e={},this.__directive_pattern.lastIndex=0,n=this.__directive_pattern.exec(t);n;)e[n[1]]=n[2],n=this.__directive_pattern.exec(t);return e},e.prototype.readIgnored=function(t){return t.readUntilAfter(this.__directives_end_ignore_pattern)},t.exports.Directives=e},,function(t,e,n){var i=n(16).Beautifier,_=n(17).Options;t.exports=function(t,e){return new i(t,e).beautify()},t.exports.defaultOptions=function(){return new _}},function(t,_,e){var n=e(17).Options,b=e(2).Output,m=e(8).InputScanner,e=e(13).Directives,y=new e(/\/\*/,/\*\//),w=/\r\n|[\r\n]/,k=/\r\n|[\r\n]/g,x=/\s/,v=/(?:\s|\n)+/g,E=/\/\*(?:[\s\S]*?)((?:\*\/)|$)/g,O=/\/\/(?:[^\n\r\u2028\u2029]*)/g;function i(t,e){this._source_text=t||"",this._options=new n(e),this._ch=null,this._input=null,this.NESTED_AT_RULE={page:!0,"font-face":!0,keyframes:!0,media:!0,supports:!0,document:!0},this.CONDITIONAL_GROUP_RULE={media:!0,supports:!0,document:!0},this.NON_SEMICOLON_NEWLINE_PROPERTY=["grid-template-areas","grid-template"]}i.prototype.eatString=function(t){var e="";for(this._ch=this._input.next();this._ch;){if(e+=this._ch,"\\"===this._ch)e+=this._input.next();else if(-1!==t.indexOf(this._ch)||"\n"===this._ch)break;this._ch=this._input.next()}return e},i.prototype.eatWhitespace=function(t){for(var e=x.test(this._input.peek()),n=0;x.test(this._input.peek());)this._ch=this._input.next(),t&&"\n"===this._ch&&(0===n||n=this._nestedLevel):this._indentLevel>=this._nestedLevel-1,this._options.newline_between_rules&&n&&this._output.previous_line&&"{"!==this._output.previous_line.item(-1)&&this._output.ensure_empty_line_above("/",","),this._output.space_before_token=!0,"expand"===this._options.brace_style?(this._output.add_new_line(),this.print_string(this._ch),this.indent(),this._output.set_indent(this._indentLevel)):("("===r?this._output.space_before_token=!1:","!==r&&this.indent(),this.print_string(this._ch)),this.eatWhitespace(!0),this._output.add_new_line();else if("}"===this._ch)this.outdent(),this._output.add_new_line(),"{"===r&&this._output.trim(!0),i&&(this.outdent(),i=!1),this.print_string(this._ch),n=!1,this._nestedLevel&&this._nestedLevel--,this.eatWhitespace(!0),this._output.add_new_line(),
+this._options.newline_between_rules&&!this._output.just_added_blankline()&&"}"!==this._input.peek()&&this._output.add_new_line(!0),")"===this._input.peek()&&(this._output.trim(!0),"expand"===this._options.brace_style&&this._output.add_new_line(!0));else if(":"===this._ch){for(f=0;f"!==this._ch&&"+"!==this._ch&&"~"!==this._ch||i||0!==e?"]"===this._ch?this.print_string(this._ch):"["===this._ch?(this.preserveSingleSpace(a),this.print_string(this._ch)):"="===this._ch?(this.eatWhitespace(),this.print_string("="),x.test(this._ch)&&(this._ch="")):"!"!==this._ch||this._input.lookBack("\\")?(this.preserveSingleSpace('"'===r||"'"===r||a),this.print_string(this._ch),!this._output.just_added_newline()&&"\n"===this._input.peek()&&d&&this._output.add_new_line()):(this._output.space_before_token=!0,this.print_string(this._ch)):this._options.space_around_combinator?(this._output.space_before_token=!0,this.print_string(this._ch),this._output.space_before_token=!0):(this.print_string(this._ch),this.eatWhitespace(),this._ch&&x.test(this._ch)&&(this._ch=""))}return this._output.get_code(h)},t.exports.Beautifier=i},function(t,e,n){var i=n(6).Options;function _(t){var e,n;for(i.call(this,t,"css"),this.selector_separator_newline=this._get_boolean("selector_separator_newline",!0),this.newline_between_rules=this._get_boolean("newline_between_rules",!0),t=this._get_boolean("space_around_selector_separator"),this.space_around_combinator=this._get_boolean("space_around_combinator")||t,e=this._get_selection_list("brace_style",["collapse","expand","end-expand","none","preserve-inline"]),this.brace_style="collapse",n=0;nthis.__parent.wrap_line_length&&this.__wrap_point_character_count>this.__parent.next_line.__character_count},_.prototype._allow_wrap=function(){var t;return!!this._should_wrap()&&(
+this.__parent.add_new_line(),(t=this.__parent.current_line).set_indent(this.__wrap_point_indent_count,this.__wrap_point_alignment_count),t.__items=this.__items.slice(this.__wrap_point_index),this.__items=this.__items.slice(0,this.__wrap_point_index),t.__character_count+=this.__character_count-this.__wrap_point_character_count,this.__character_count=this.__wrap_point_character_count," "===t.__items[0]&&(t.__items.splice(0,1),--t.__character_count),!0)},_.prototype.is_empty=function(){return 0===this.__items.length},_.prototype.last=function(){return this.is_empty()?null:this.__items[this.__items.length-1]},_.prototype.push=function(t){this.__items.push(t);var e=t.lastIndexOf("\n");-1!==e?this.__character_count=t.length-e:this.__character_count+=t.length},_.prototype.pop=function(){var t=null;return this.is_empty()||(t=this.__items.pop(),this.__character_count-=t.length),t},_.prototype._remove_indent=function(){0=this.__cache.length;)this.__add_column()},n.prototype.__add_column=function(){var t,e=this.__cache.length,n="";this.__indent_size&&e>=this.__indent_size&&(e-=(t=Math.floor(e/this.__indent_size))*this.__indent_size,n=new Array(t+1).join(this.__indent_string)),e&&(n+=new Array(e+1).join(" ")),this.__cache.push(n)},e.prototype.__add_outputline=function(){this.previous_line=this.current_line,this.current_line=this.next_line.clone_empty(),this.__lines.push(this.current_line)},e.prototype.get_line_number=function(){return this.__lines.length},e.prototype.get_indent_string=function(t,e){return this.__indent_cache.get_indent_string(t,e)},e.prototype.get_indent_size=function(t,e){return this.__indent_cache.get_indent_size(t,e)},e.prototype.is_empty=function(){return!this.previous_line&&this.current_line.is_empty()},e.prototype.add_new_line=function(t){return!(this.is_empty()||!t&&this.just_added_newline())&&(this.raw||this.__add_outputline(),!0)},e.prototype.get_code=function(t){var e;return this.trim(!0),(e=this.current_line.pop())&&("\n"===e[e.length-1]&&(e=e.replace(/\n+$/g,"")),this.current_line.push(e)),this._end_with_newline&&this.__add_outputline(),e=this.__lines.join("\n"),e="\n"!==t?e.replace(/[\n]/g,t):e},e.prototype.set_wrap_point=function(){this.current_line._set_wrap_point()},e.prototype.set_indent=function(t,e){return this.next_line.set_indent(t=t||0,e=e||0),1=t.length&&this.__input.substring(e-t.length,e).toLowerCase()===t},t.exports.InputScanner=e},function(t,e,n){var i=n(8).InputScanner,s=n(3).Token,a=n(10).TokenStream,_=n(11).WhitespacePattern,r={START:"TK_START",RAW:"TK_RAW",EOF:"TK_EOF"},n=function(t,e){this._input=new i(t),this._options=e||{},this.__tokens=null,this._patterns={},this._patterns.whitespace=new _(this._input)};n.prototype.tokenize=function(){var t,e,n,i,_;for(this._input.restart(),this.__tokens=new a,this._reset(),e=new s(r.START,""),n=null,i=[],_=new a;e.type!==r.EOF;){for(t=this._get_next_token(e,n);this._is_comment(t);)_.add(t),t=this._get_next_token(e,n);_.isEmpty()||(t.comments_before=_,_=new a),t.parent=n,this._is_opening(t)?(i.push(n),n=t):n&&this._is_closing(t,n)&&((t.opened=n).closed=t,n=i.pop(),t.parent=n),(t.previous=e).next=t,this.__tokens.add(t),e=t}return this.__tokens},n.prototype._is_first_token=function(){return this.__tokens.isEmpty()},n.prototype._reset=function(){},n.prototype._get_next_token=function(t,e){this._readWhitespace();var n=this._input.read(/.+/g);return n?this._create_token(r.RAW,n):this._create_token(r.EOF,"")},n.prototype._is_comment=function(t){return!1},n.prototype._is_opening=function(t){return!1},n.prototype._is_closing=function(t,e){return!1},n.prototype._create_token=function(t,e){return new s(t,e,this._patterns.whitespace.newline_count,this._patterns.whitespace.whitespace_before_token)},n.prototype._readWhitespace=function(){return this._patterns.whitespace.read()},t.exports.Tokenizer=n,t.exports.TOKEN=r},function(t){function e(t){this.__tokens=[],this.__tokens_length=this.__tokens.length,this.__position=0,this.__parent_token=t}e.prototype.restart=function(){this.__position=0},e.prototype.isEmpty=function(){return 0===this.__tokens_length},e.prototype.hasNext=function(){return this.__position/),erb:e.starting_with(/<%[^%]/).until_after(/[^%]%>/),django:e.starting_with(/{%/).until_after(/%}/),django_value:e.starting_with(/{{/).until_after(/}}/),django_comment:e.starting_with(/{#/).until_after(/#}/),smarty:e.starting_with(/{(?=[^}{\s\n])/).until_after(/[^\s\n]}/),smarty_comment:e.starting_with(/{\*/).until_after(/\*}/),smarty_literal:e.starting_with(/{literal}/).until_after(/{\/literal}/)}}(s.prototype=new i)._create=function(){return new s(this._input,this)},s.prototype._update=function(){this.__set_templated_pattern()},s.prototype.disable=function(t){var e=this._create();return e._disabled[t]=!0,e._update(),e},s.prototype.read_options=function(t){var e,n=this._create();for(e in _)n._disabled[e]=-1===t.templating.indexOf(e);return n._update(),n},s.prototype.exclude=function(t){var e=this._create();return e._excluded[t]=!0,e._update(),e},s.prototype.read=function(){for(var t="",t=this._match_pattern?this._input.read(this._starting_pattern):this._input.read(this._starting_pattern,this.__template_pattern),e=this._read_template();e;)this._match_pattern?e+=this._input.read(this._match_pattern):e+=this._input.readUntil(this.__template_pattern),t+=e,e=this._read_template();return this._until_after&&(t+=this._input.readUntilAfter(this._until_pattern)),t},s.prototype.__set_templated_pattern=function(){var t=[];this._disabled.php||t.push(this.__patterns.php._starting_pattern.source),this._disabled.handlebars||t.push(this.__patterns.handlebars._starting_pattern.source),this._disabled.erb||t.push(this.__patterns.erb._starting_pattern.source),this._disabled.django||(t.push(this.__patterns.django._starting_pattern.source),t.push(this.__patterns.django_value._starting_pattern.source),t.push(this.__patterns.django_comment._starting_pattern.source)),this._disabled.smarty||t.push(this.__patterns.smarty._starting_pattern.source),this._until_pattern&&t.push(this._until_pattern.source),this.__template_pattern=this._input.get_regexp("(?:"+t.join("|")+")")},s.prototype._read_template=function(){var t,e="",n=this._input.peek();return"<"===n?(t=this._input.peek(1),this._disabled.php||this._excluded.php||"?"!==t||(e=e||this.__patterns.php.read()),
+this._disabled.erb||this._excluded.erb||"%"!==t||(e=e||this.__patterns.erb.read())):"{"===n&&(this._disabled.handlebars||this._excluded.handlebars||(e=(e=(e=e||this.__patterns.handlebars_comment.read())||this.__patterns.handlebars_unescaped.read())||this.__patterns.handlebars.read()),this._disabled.django||(this._excluded.django||this._excluded.handlebars||(e=e||this.__patterns.django_value.read()),this._excluded.django||(e=(e=e||this.__patterns.django_comment.read())||this.__patterns.django.read())),this._disabled.smarty||this._disabled.django&&this._disabled.handlebars&&(e=(e=(e=e||this.__patterns.smarty_comment.read())||this.__patterns.smarty_literal.read())||this.__patterns.smarty.read())),e},t.exports.TemplatablePattern=s},,,,function(t,e,n){var _=n(19).Beautifier,i=n(20).Options;t.exports=function(t,e,n,i){return new _(t,e,n,i).beautify()},t.exports.defaultOptions=function(){return new i}},function(e,n,t){var _,s,o,i,r,u=t(20).Options,d=t(2).Output,f=t(21).Tokenizer,h=t(21).TOKEN,g=/\r\n|[\r\n]/,b=/\r\n|[\r\n]/g,p=function(t,e){this.indent_level=0,this.alignment_size=0,this.max_preserve_newlines=t.max_preserve_newlines,this.preserve_newlines=t.preserve_newlines,this._output=new d(t,e)};function a(t,e){return-1!==e.indexOf(t)}function m(t,e,n){this.parent=t||null,this.tag=e?e.tag_name:"",this.indent_level=n||0,this.parser_token=e||null}function l(t){this._printer=t,this._current_frame=null}function c(t,e,n,i){this._source_text=t||"",e=e||{},this._js_beautify=n,this._css_beautify=i,this._tag_stack=null;t=new u(e,"html");this._options=t,this._is_wrap_attributes_force="force"===this._options.wrap_attributes.substr(0,"force".length),this._is_wrap_attributes_force_expand_multiline="force-expand-multiline"===this._options.wrap_attributes,this._is_wrap_attributes_force_aligned="force-aligned"===this._options.wrap_attributes,this._is_wrap_attributes_aligned_multiple="aligned-multiple"===this._options.wrap_attributes,this._is_wrap_attributes_preserve="preserve"===this._options.wrap_attributes.substr(0,"preserve".length),this._is_wrap_attributes_preserve_aligned="preserve-aligned"===this._options.wrap_attributes}p.prototype.current_line_has_match=function(t){return this._output.current_line.has_match(t)},p.prototype.set_space_before_token=function(t,e){this._output.space_before_token=t,this._output.non_breaking_space=e},p.prototype.set_wrap_point=function(){this._output.set_indent(this.indent_level,this.alignment_size),this._output.set_wrap_point()},p.prototype.add_raw_token=function(t){this._output.add_raw_token(t)},p.prototype.print_preserved_newlines=function(t){var e,n=0;for(t.type!==h.TEXT&&t.previous.type!==h.TEXT&&(n=t.newlines?1:0),this.preserve_newlines&&(n=t.newlines=this._options.wrap_attributes_min_attrs&&(i.type!==h.TAG_OPEN||this._is_wrap_attributes_force_expand_multiline)&&(t.print_newline(!1),_=!0)),t.print_token(e),_=_||t.previous_token_wrapped(),n.has_wrapped_attrs=_),s},c.prototype._handle_text=function(t,e,n){var i={text:e.text,type:"TK_CONTENT"};return n.custom_beautifier_name?this._print_custom_beatifier_text(t,e,n):n.is_unformatted||n.is_content_unformatted?t.add_raw_token(e):(t.traverse_whitespace(e),t.print_token(e)),i},c.prototype._print_custom_beatifier_text=function(t,e,n){var i,_,s,a,r,u=this;if(""!==e.text){if(i=e.text,r=1,a=s="","javascript"===n.custom_beautifier_name&&"function"==typeof this._js_beautify?_=this._js_beautify:"css"===n.custom_beautifier_name&&"function"==typeof this._css_beautify?_=this._css_beautify:"html"===n.custom_beautifier_name&&(_=function(t,e){return new c(t,e,u._js_beautify,u._css_beautify).beautify()}),"keep"===this._options.indent_scripts?r=0:"separate"===this._options.indent_scripts&&(r=-t.indent_level),r=t.get_full_indent(r),i=i.replace(/\n[ \t]*$/,""),"html"!==n.custom_beautifier_name&&"<"===i[0]&&i.match(/^(|]]>)$/.exec(i)))return void t.add_raw_token(e);s=r+n[1]+"\n",i=n[4],n[5]&&(a=r+n[5]),i=i.replace(/\n[ \t]*$/,""),(n[2]||-1!==n[3].indexOf("\n"))&&(n=n[3].match(/[ \t]+$/))&&(e.whitespace_before=n[0])}i=i&&(_?((n=function(){this.eol="\n"}).prototype=this._options.raw_options,_(r+i,new n)):r+(i=(n=e.whitespace_before)?i.replace(new RegExp("\n("+n+")?","g"),"\n"):i).replace(/\n/g,"\n"+r)),s&&(i=i?s+i+"\n"+a:s+a),t.print_newline(!1),i&&(e.text=i,e.whitespace_before="",e.newlines=0,t.add_raw_token(e),t.print_newline(!0))}},c.prototype._handle_tag_open=function(t,e,n,i,_){var s,a,r=this._get_tag_open_token(e);if(!n.is_unformatted&&!n.is_content_unformatted||n.is_empty_element||e.type!==h.TAG_OPEN||r.is_start_tag?(t.traverse_whitespace(e),this._set_tag_position(t,e,r,n,i),r.is_inline_element||t.set_wrap_point(),t.print_token(e)):(t.add_raw_token(e),r.start_tag_token=this._tag_stack.try_pop(r.tag_name)),r.is_start_tag&&this._is_wrap_attributes_force)for(s=0;(a=_.peek(s)).type===h.ATTRIBUTE&&(r.attr_count+=1),s+=1,a.type!==h.EOF&&a.type!==h.TAG_CLOSE;);return(this._is_wrap_attributes_force_aligned||this._is_wrap_attributes_aligned_multiple||this._is_wrap_attributes_preserve_aligned)&&(r.alignment_size=e.text.length+1),r.tag_complete||r.is_unformatted||(t.alignment_size=r.alignment_size),r},o=function(t,e){var n;this.parent=t||null,this.text="",this.type="TK_TAG_OPEN",this.tag_name="",this.is_inline_element=!1,this.is_unformatted=!1,this.is_content_unformatted=!1,this.is_empty_element=!1,this.is_start_tag=!1,this.is_end_tag=!1,this.indent_content=!1,this.multiline_content=!1,this.custom_beautifier_name=null,this.start_tag_token=null,this.attr_count=0,this.has_wrapped_attrs=!1,this.alignment_size=0,this.tag_complete=!1,this.tag_start_char="",this.tag_check="",e?(this.tag_start_char=e.text[0],this.text=e.text,"<"===this.tag_start_char?(n=e.text.match(/^<([^\s>]*)/),this.tag_check=n?n[1]:""):(n=e.text.match(/^{{~?(?:[\^]|#\*?)?([^\s}]+)/),this.tag_check=n?n[1]:"",(e.text.startsWith("{{#>")||e.text.startsWith("{{~#>"))&&">"===this.tag_check[0]&&(">"===this.tag_check&&null!==e.next?this.tag_check=e.next.text.split(" ")[0]:this.tag_check=e.text.split(">")[1])),this.tag_check=this.tag_check.toLowerCase(),e.type===h.COMMENT&&(this.tag_complete=!0),this.is_start_tag="/"!==this.tag_check.charAt(0),this.tag_name=this.is_start_tag?this.tag_check:this.tag_check.substr(1),this.is_end_tag=!this.is_start_tag||e.closed&&"/>"===e.closed.text,t=2,"{"===this.tag_start_char&&3<=this.text.length&&"~"===this.text.charAt(2)&&(t=3),this.is_end_tag=this.is_end_tag||"{"===this.tag_start_char&&(this.text.length<3||/[^#\^]/.test(this.text.charAt(t)))):this.tag_complete=!0},c.prototype._get_tag_open_token=function(t){t=new o(this._tag_stack.get_parser_token(),t);return t.alignment_size=this._options.wrap_attributes_indent_size,t.is_end_tag=t.is_end_tag||a(t.tag_check,this._options.void_elements),t.is_empty_element=t.tag_complete||t.is_start_tag&&t.is_end_tag,t.is_unformatted=!t.tag_complete&&a(t.tag_check,this._options.unformatted),t.is_content_unformatted=!t.is_empty_element&&a(
+t.tag_check,this._options.content_unformatted),t.is_inline_element=a(t.tag_name,this._options.inline)||this._options.inline_custom_elements&&t.tag_name.includes("-")||"{"===t.tag_start_char,t},c.prototype._set_tag_position=function(t,e,n,i,_){n.is_empty_element||(n.is_end_tag?n.start_tag_token=this._tag_stack.try_pop(n.tag_name):(this._do_optional_end_element(n)&&(n.is_inline_element||t.print_newline(!1)),this._tag_stack.record_tag(n),"script"!==n.tag_name&&"style"!==n.tag_name||n.is_unformatted||n.is_content_unformatted||(n.custom_beautifier_name=s(n.tag_check,e)))),a(n.tag_check,this._options.extra_liners)&&(t.print_newline(!1),t._output.just_added_blankline()||t.print_newline(!0)),n.is_empty_element?("{"===n.tag_start_char&&"else"===n.tag_check&&(this._tag_stack.indent_to_tag(["if","unless","each"]),n.indent_content=!0,t.current_line_has_match(/{{#if/)||t.print_newline(!1)),"!--"===n.tag_name&&_.type===h.TAG_CLOSE&&i.is_end_tag&&-1===n.text.indexOf("\n")||(n.is_inline_element||n.is_unformatted||t.print_newline(!1),this._calcluate_parent_multiline(t,n))):n.is_end_tag?(e=!1,e=(e=n.start_tag_token&&n.start_tag_token.multiline_content)||!n.is_inline_element&&!(i.is_inline_element||i.is_unformatted)&&!(_.type===h.TAG_CLOSE&&n.start_tag_token===i)&&"TK_CONTENT"!==_.type,(e=n.is_content_unformatted||n.is_unformatted?!1:e)&&t.print_newline(!1)):(n.indent_content=!n.custom_beautifier_name,"<"===n.tag_start_char&&("html"===n.tag_name?n.indent_content=this._options.indent_inner_html:"head"===n.tag_name?n.indent_content=this._options.indent_head_inner_html:"body"===n.tag_name&&(n.indent_content=this._options.indent_body_inner_html)),n.is_inline_element||n.is_unformatted||"TK_CONTENT"===_.type&&!n.is_content_unformatted||t.print_newline(!1),this._calcluate_parent_multiline(t,n))},c.prototype._calcluate_parent_multiline=function(t,e){!e.parent||!t._output.just_added_newline()||(e.is_inline_element||e.is_unformatted)&&e.parent.is_inline_element||(e.parent.multiline_content=!0)},i=["address","article","aside","blockquote","details","div","dl","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hr","main","menu","nav","ol","p","pre","section","table","ul"],r=["a","audio","del","ins","map","noscript","video"],c.prototype._do_optional_end_element=function(t){var e,n=null;if(!t.is_empty_element&&t.is_start_tag&&t.parent)return"body"===t.tag_name?n=n||this._tag_stack.try_pop("head"):"li"===t.tag_name?n=n||this._tag_stack.try_pop("li",["ol","ul","menu"]):"dd"===t.tag_name||"dt"===t.tag_name?n=(n=n||this._tag_stack.try_pop("dt",["dl"]))||this._tag_stack.try_pop("dd",["dl"]):"p"===t.parent.tag_name&&-1!==i.indexOf(t.tag_name)?(e=t.parent.parent)&&-1!==r.indexOf(e.tag_name)||(n=n||this._tag_stack.try_pop("p")):"rp"===t.tag_name||"rt"===t.tag_name?n=(n=n||this._tag_stack.try_pop("rt",["ruby","rtc"]))||this._tag_stack.try_pop("rp",["ruby","rtc"]):"optgroup"===t.tag_name?n=n||this._tag_stack.try_pop("optgroup",["select"]):"option"===t.tag_name?n=n||this._tag_stack.try_pop("option",["select","datalist","optgroup"]):"colgroup"===t.tag_name?n=n||this._tag_stack.try_pop("caption",["table"]):"thead"===t.tag_name?n=(n=n||this._tag_stack.try_pop("caption",["table"]))||this._tag_stack.try_pop("colgroup",["table"]):"tbody"===t.tag_name||"tfoot"===t.tag_name?n=(n=(n=(n=n||this._tag_stack.try_pop("caption",["table"]))||this._tag_stack.try_pop("colgroup",["table"]))||this._tag_stack.try_pop("thead",["table"]))||this._tag_stack.try_pop("tbody",["table"]):"tr"===t.tag_name?n=(n=(n=n||this._tag_stack.try_pop("caption",["table"]))||this._tag_stack.try_pop("colgroup",["table"]))||this._tag_stack.try_pop("tr",["table","thead","tbody","tfoot"]):"th"!==t.tag_name&&"td"!==t.tag_name||(n=(n=n||this._tag_stack.try_pop("td",["table","thead","tbody","tfoot","tr"]))||this._tag_stack.try_pop("th",["table","thead","tbody","tfoot","tr"])),t.parent=this._tag_stack.get_parser_token(),n},e.exports.Beautifier=c},function(t,e,n){var i=n(6).Options;function _(t){i.call(this,t,"html"),1===this.templating.length&&"auto"===this.templating[0]&&(this.templating=["django","erb","handlebars","php"]),this.indent_inner_html=this._get_boolean("indent_inner_html"),this.indent_body_inner_html=this._get_boolean("indent_body_inner_html",!0),this.indent_head_inner_html=this._get_boolean("indent_head_inner_html",!0),this.indent_handlebars=this._get_boolean("indent_handlebars",!0),this.wrap_attributes=this._get_selection("wrap_attributes",["auto","force","force-aligned","force-expand-multiline","aligned-multiple","preserve","preserve-aligned"]),this.wrap_attributes_min_attrs=this._get_number("wrap_attributes_min_attrs",2),this.wrap_attributes_indent_size=this._get_number("wrap_attributes_indent_size",this.indent_size),this.extra_liners=this._get_array("extra_liners",["head","body","/html"]),this.inline=this._get_array("inline",["a","abbr","area","audio","b","bdi","bdo","br","button","canvas","cite","code","data","datalist","del","dfn","em","embed","i","iframe","img","input","ins","kbd","keygen","label","map","mark","math","meter","noscript","object","output","progress","q","ruby","s","samp","select","small","span","strong","sub","sup","svg","template","textarea","time","u","var","video","wbr","text","acronym","big","strike","tt"]),this.inline_custom_elements=this._get_boolean("inline_custom_elements",!0),this.void_elements=this._get_array("void_elements",["area","base","br","col","embed","hr","img","input","keygen","link","menuitem","meta","param","source","track","wbr","!doctype","?xml","basefont","isindex"]),this.unformatted=this._get_array("unformatted",[]),this.content_unformatted=this._get_array("content_unformatted",["pre","textarea"]),this.unformatted_content_delimiter=this._get_characters("unformatted_content_delimiter"),this.indent_scripts=this._get_selection("indent_scripts",["normal","keep","separate"])}_.prototype=new i,t.exports.Options=_},function(t,o,e){var n=e(9).Tokenizer,i=e(9).TOKEN,_=e(13).Directives,s=e(14
+).TemplatablePattern,a=e(12).Pattern,r={TAG_OPEN:"TK_TAG_OPEN",TAG_CLOSE:"TK_TAG_CLOSE",CONTROL_FLOW_OPEN:"TK_CONTROL_FLOW_OPEN",CONTROL_FLOW_CLOSE:"TK_CONTROL_FLOW_CLOSE",ATTRIBUTE:"TK_ATTRIBUTE",EQUALS:"TK_EQUALS",VALUE:"TK_VALUE",COMMENT:"TK_COMMENT",TEXT:"TK_TEXT",UNKNOWN:"TK_UNKNOWN",START:i.START,RAW:i.RAW,EOF:i.EOF},u=new _(/<\!--/,/-->/),e=function(t,e){n.call(this,t,e),this._current_tag_name="",t=new s(this._input).read_options(this._options),e=new a(this._input),this.__patterns={word:t.until(/[\n\r\t <]/),word_control_flow_close_excluded:t.until(/[\n\r\t <}]/),single_quote:t.until_after(/'/),double_quote:t.until_after(/"/),attribute:t.until(/[\n\r\t =>]|\/>/),element_name:t.until(/[\n\r\t >\/]/),angular_control_flow_start:e.matching(/\@[a-zA-Z]+[^({]*[({]/),handlebars_comment:e.starting_with(/{{!--/).until_after(/--}}/),handlebars:e.starting_with(/{{/).until_after(/}}/),handlebars_open:e.until(/[\n\r\t }]/),handlebars_raw_close:e.until(/}}/),comment:e.starting_with(//),cdata:e.starting_with(//),conditional_comment:e.starting_with(//),processing:e.starting_with(/<\?/).until_after(/\?>/)},this._options.indent_handlebars&&(this.__patterns.word=this.__patterns.word.exclude("handlebars"),this.__patterns.word_control_flow_close_excluded=this.__patterns.word_control_flow_close_excluded.exclude("handlebars")),this._unformatted_content_delimiter=null,this._options.unformatted_content_delimiter&&(t=this._input.get_literal_regexp(this._options.unformatted_content_delimiter),this.__patterns.unformatted_content_delimiter=e.matching(t).until_after(t))};(e.prototype=new n)._is_comment=function(t){return!1},e.prototype._is_opening=function(t){return t.type===r.TAG_OPEN||t.type===r.CONTROL_FLOW_OPEN},e.prototype._is_closing=function(t,e){return t.type===r.TAG_CLOSE&&e&&((">"===t.text||"/>"===t.text)&&"<"===e.text[0]||"}}"===t.text&&"{"===e.text[0]&&"{"===e.text[1])||t.type===r.CONTROL_FLOW_CLOSE&&"}"===t.text&&e.text.endsWith("{")},e.prototype._reset=function(){this._current_tag_name=""},e.prototype._get_next_token=function(t,e){var n;return this._readWhitespace(),null===(n=this._input.peek())?this._create_token(r.EOF,""):this._read_open_handlebars(n,e)||this._read_attribute(n,t,e)||this._read_close(n,e)||this._read_control_flows(n,e)||this._read_raw_content(n,t,e)||this._read_content_word(n,e)||this._read_comment_or_cdata(n)||this._read_processing(n)||this._read_open(n,e)||this._create_token(r.UNKNOWN,this._input.next())},e.prototype._read_comment_or_cdata=function(t){var e=null,n=null,i=null;return"<"===t&&("!"===this._input.peek(1)&&((n=this.__patterns.comment.read())?(i=u.get_directives(n))&&"start"===i.ignore&&(n+=u.readIgnored(this._input)):n=this.__patterns.cdata.read()),n&&((e=this._create_token(r.COMMENT,n)).directives=i)),e},e.prototype._read_processing=function(t){var e=null,n=null;return"<"===t&&(n="!"!==(t=this._input.peek(1))&&"?"!==t?n:(n=this.__patterns.conditional_comment.read())||this.__patterns.processing.read())&&((e=this._create_token(r.COMMENT,n)).directives=null),e},e.prototype._read_open=function(t,e){var n=null,i=null;return e&&e.type!==r.CONTROL_FLOW_OPEN||"<"===t&&(n=this._input.next(),"/"===this._input.peek()&&(n+=this._input.next()),n+=this.__patterns.element_name.read(),i=this._create_token(r.TAG_OPEN,n)),i},e.prototype._read_open_handlebars=function(t,e){var n=null,i=null;return e&&e.type!==r.CONTROL_FLOW_OPEN||this._options.indent_handlebars&&"{"===t&&"{"===this._input.peek(1)&&(i="!"===this._input.peek(2)?(n=(n=this.__patterns.handlebars_comment.read())||this.__patterns.handlebars.read(),this._create_token(r.COMMENT,n)):(n=this.__patterns.handlebars_open.read(),this._create_token(r.TAG_OPEN,n))),i},e.prototype._read_control_flows=function(t,e){var n,i,_,s="",a=null;if(!this._options.templating.includes("angular")||!this._options.indent_handlebars)return a;if("@"===t){if(""===(s=this.__patterns.angular_control_flow_start.read()))return a;for(n=s.endsWith("(")?1:0,i=0;(!s.endsWith("{")||n!==i)&&null!==(_=this._input.next());)"("===_?n++:")"===_&&i++,s+=_;a=this._create_token(r.CONTROL_FLOW_OPEN,s)}else"}"===t&&e&&e.type===r.CONTROL_FLOW_OPEN&&(s=this._input.next(),a=this._create_token(r.CONTROL_FLOW_CLOSE,s));return a},e.prototype._read_close=function(t,e){var n=null,i=null;return e&&e.type===r.TAG_OPEN&&("<"===e.text[0]&&(">"===t||"/"===t&&">"===this._input.peek(1))?(n=this._input.next(),"/"===t&&(n+=this._input.next()),i=this._create_token(r.TAG_CLOSE,n)):"{"===e.text[0]&&"}"===t&&"}"===this._input.peek(1)&&(this._input.next(),this._input.next(),i=this._create_token(r.TAG_CLOSE,"}}"))),i},e.prototype._read_attribute=function(t,e,n){var i=null;return n&&"<"===n.text[0]&&("="===t?i=this._create_token(r.EQUALS,this._input.next()):'"'===t||"'"===t?(n=this._input.next(),n+=('"'===t?this.__patterns.double_quote:this.__patterns.single_quote).read(),i=this._create_token(r.VALUE,n)):(t=this.__patterns.attribute.read())&&(i=e.type===r.EQUALS?this._create_token(r.VALUE,t):this._create_token(r.ATTRIBUTE,t))),i},e.prototype._is_content_unformatted=function(t){return-1===this._options.void_elements.indexOf(t)&&(-1!==this._options.content_unformatted.indexOf(t)||-1!==this._options.unformatted.indexOf(t))},e.prototype._read_raw_content=function(t,e,n){var i="";if(n&&"{"===n.text[0])i=this.__patterns.handlebars_raw_close.read();else if(e.type===r.TAG_CLOSE&&"<"===e.opened.text[0]&&"/"!==e.text[0])if("script"===(n=e.opened.text.substr(1).toLowerCase())||"style"===n){if(e=this._read_comment_or_cdata(t))return e.type=r.TEXT,e;i=this._input.readUntil(new RegExp(""+n+"[\\n\\r\\t ]*?>","ig"))}else this._is_content_unformatted(n)&&(i=this._input.readUntil(new RegExp(""+n+"[\\n\\r\\t ]*?>","ig")));return i?this._create_token(r.TEXT,i):null},e.prototype._read_content_word=function(t,e){var n="";if(n=(
+n=this._options.unformatted_content_delimiter&&t===this._options.unformatted_content_delimiter[0]?this.__patterns.unformatted_content_delimiter.read():n)||(e&&e.type===r.CONTROL_FLOW_OPEN?this.__patterns.word_control_flow_close_excluded:this.__patterns.word).read())return this._create_token(r.TEXT,n)},t.exports.Tokenizer=e,t.exports.TOKEN=r}],i={};t=function _(t){var e=i[t];return e!==undefined||(e=i[t]={exports:{}},n[t](e,e.exports,_)),e.exports}(18),r=t}(),n=r,void 0!==u?(_=i=u).html_beautify=function(t,e){return n(t,e,i.js_beautify,_.css_beautify)}:"undefined"!=typeof window?window.html_beautify=function(t,e){return n(t,e,window.js_beautify,window.css_beautify)}:"undefined"!=typeof global&&(global.html_beautify=function(t,e){return n(t,e,global.js_beautify,global.css_beautify)})},"@VERSION@");
\ No newline at end of file
diff --git a/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify.js b/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify.js
index 6ebc08992d70..4bd9ce1b0259 100644
--- a/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify.js
+++ b/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-beautify/moodle-atto_html-beautify.js
@@ -77,7 +77,7 @@ Y.namespace('M.atto_html').beautify = exports;
} }
space_after_anon_function (default false) - should the space before an anonymous function's parens be added, "function()" vs "function ()",
- NOTE: This option is overriden by jslint_happy (i.e. if jslint_happy is true, space_after_anon_function is true by design)
+ NOTE: This option is overridden by jslint_happy (i.e. if jslint_happy is true, space_after_anon_function is true by design)
brace_style (default "collapse") - "collapse" | "expand" | "end-expand" | "none" | any of the former + ",preserve-inline"
put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line, or attempt to keep them where they are.
@@ -928,7 +928,7 @@ Beautifier.prototype.handle_start_block = function(current_token) {
}
}
if (this._flags.last_token.type !== TOKEN.OPERATOR && this._flags.last_token.type !== TOKEN.START_EXPR) {
- if (this._flags.last_token.type === TOKEN.START_BLOCK && !this._flags.inline_frame) {
+ if (in_array(this._flags.last_token.type, [TOKEN.START_BLOCK, TOKEN.SEMICOLON]) && !this._flags.inline_frame) {
this.print_newline();
} else {
this._output.space_before_token = true;
@@ -1054,7 +1054,9 @@ Beautifier.prototype.handle_word = function(current_token) {
}
if (this._flags.last_token.type === TOKEN.COMMA || this._flags.last_token.type === TOKEN.START_EXPR || this._flags.last_token.type === TOKEN.EQUALS || this._flags.last_token.type === TOKEN.OPERATOR) {
- if (!this.start_of_object_property()) {
+ if (!this.start_of_object_property() && !(
+ // start of object property is different for numeric values with +/- prefix operators
+ in_array(this._flags.last_token.text, ['+', '-']) && this._last_last_text === ':' && this._flags.parent.mode === MODE.ObjectLiteral)) {
this.allow_wrap_or_preserved_newline(current_token);
}
}
@@ -1335,6 +1337,12 @@ Beautifier.prototype.handle_operator = function(current_token) {
return;
}
+ if (in_array(current_token.text, ['-', '+']) && this.start_of_object_property()) {
+ // numeric value with +/- symbol in front as a property
+ this.print_token(current_token);
+ return;
+ }
+
// Allow line wrapping between operators when operator_position is
// set to before or preserve
if (this._flags.last_token.type === TOKEN.OPERATOR && in_array(this._options.operator_position, OPERATOR_POSITION_BEFORE_OR_PRESERVE)) {
@@ -2161,12 +2169,13 @@ var nonASCIIidentifierChars = "\\u0300-\\u036f\\u0483-\\u0487\\u0591-\\u05bd\\u0
//var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
//var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
-var identifierStart = "(?:\\\\u[0-9a-fA-F]{4}|[" + baseASCIIidentifierStartChars + nonASCIIidentifierStartChars + "])";
-var identifierChars = "(?:\\\\u[0-9a-fA-F]{4}|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])*";
+var unicodeEscapeOrCodePoint = "\\\\u[0-9a-fA-F]{4}|\\\\u\\{[0-9a-fA-F]+\\}";
+var identifierStart = "(?:" + unicodeEscapeOrCodePoint + "|[" + baseASCIIidentifierStartChars + nonASCIIidentifierStartChars + "])";
+var identifierChars = "(?:" + unicodeEscapeOrCodePoint + "|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])*";
exports.identifier = new RegExp(identifierStart + identifierChars, 'g');
exports.identifierStart = new RegExp(identifierStart);
-exports.identifierMatch = new RegExp("(?:\\\\u[0-9a-fA-F]{4}|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])+");
+exports.identifierMatch = new RegExp("(?:" + unicodeEscapeOrCodePoint + "|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])+");
var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/; // jshint ignore:line
@@ -2355,10 +2364,10 @@ function Options(options, merge_child_field) {
this.indent_empty_lines = this._get_boolean('indent_empty_lines');
- // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty']
- // For now, 'auto' = all off for javascript, all on for html (and inline javascript).
+ // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular']
+ // For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css).
// other values ignored
- this.templating = this._get_selection_list('templating', ['auto', 'none', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
+ this.templating = this._get_selection_list('templating', ['auto', 'none', 'angular', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
}
Options.prototype._get_array = function(name, default_value) {
@@ -2654,6 +2663,7 @@ Tokenizer.prototype._get_next_token = function(previous_token, open_token) { //
token = token || this._read_non_javascript(c);
token = token || this._read_string(c);
+ token = token || this._read_pair(c, this._input.peek(1)); // Issue #2062 hack for record type '#{'
token = token || this._read_word(previous_token);
token = token || this._read_singles(c);
token = token || this._read_comment(c);
@@ -2712,6 +2722,19 @@ Tokenizer.prototype._read_singles = function(c) {
return token;
};
+Tokenizer.prototype._read_pair = function(c, d) {
+ var token = null;
+ if (c === '#' && d === '{') {
+ token = this._create_token(TOKEN.START_BLOCK, c + d);
+ }
+
+ if (token) {
+ this._input.next();
+ this._input.next();
+ }
+ return token;
+};
+
Tokenizer.prototype._read_punctuation = function() {
var resulting_string = this.__patterns.punct.read();
@@ -2957,6 +2980,9 @@ function unescape_string(s) {
matched = input_scan.match(/x([0-9A-Fa-f]{2})/g);
} else if (input_scan.peek() === 'u') {
matched = input_scan.match(/u([0-9A-Fa-f]{4})/g);
+ if (!matched) {
+ matched = input_scan.match(/u\{([0-9A-Fa-f]+)\}/g);
+ }
} else {
out += '\\';
if (input_scan.hasNext()) {
@@ -2980,7 +3006,9 @@ function unescape_string(s) {
} else if (escaped >= 0x00 && escaped < 0x20) {
// leave 0x00...0x1f escaped
out += '\\' + matched[0];
- continue;
+ } else if (escaped > 0x10FFFF) {
+ // If the escape sequence is out of bounds, keep the original sequence and continue conversion
+ out += '\\' + matched[0];
} else if (escaped === 0x22 || escaped === 0x27 || escaped === 0x5c) {
// single-quote, apostrophe, backslash - escape these
out += '\\' + String.fromCharCode(escaped);
@@ -3803,7 +3831,8 @@ var template_names = {
erb: false,
handlebars: false,
php: false,
- smarty: false
+ smarty: false,
+ angular: false
};
// This lets templates appear anywhere we would do a readUntil
@@ -4609,10 +4638,10 @@ function Options(options, merge_child_field) {
this.indent_empty_lines = this._get_boolean('indent_empty_lines');
- // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty']
- // For now, 'auto' = all off for javascript, all on for html (and inline javascript).
+ // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular']
+ // For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css).
// other values ignored
- this.templating = this._get_selection_list('templating', ['auto', 'none', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
+ this.templating = this._get_selection_list('templating', ['auto', 'none', 'angular', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
}
Options.prototype._get_array = function(name, default_value) {
@@ -5115,18 +5144,18 @@ function Beautifier(source_text, options) {
// https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
this.NESTED_AT_RULE = {
- "@page": true,
- "@font-face": true,
- "@keyframes": true,
+ "page": true,
+ "font-face": true,
+ "keyframes": true,
// also in CONDITIONAL_GROUP_RULE below
- "@media": true,
- "@supports": true,
- "@document": true
+ "media": true,
+ "supports": true,
+ "document": true
};
this.CONDITIONAL_GROUP_RULE = {
- "@media": true,
- "@supports": true,
- "@document": true
+ "media": true,
+ "supports": true,
+ "document": true
};
this.NON_SEMICOLON_NEWLINE_PROPERTY = [
"grid-template-areas",
@@ -5254,8 +5283,7 @@ Beautifier.prototype.beautify = function() {
// label { content: blue }
var insidePropertyValue = false;
var enteringConditionalGroup = false;
- var insideAtExtend = false;
- var insideAtImport = false;
+ var insideNonNestedAtRule = false;
var insideScssMap = false;
var topCharacter = this._ch;
var insideNonSemiColonValues = false;
@@ -5310,10 +5338,30 @@ Beautifier.prototype.beautify = function() {
// Ensures any new lines following the comment are preserved
this.eatWhitespace(true);
- } else if (this._ch === '@' || this._ch === '$') {
+ } else if (this._ch === '$') {
+ this.preserveSingleSpace(isAfterSpace);
+
+ this.print_string(this._ch);
+
+ // strip trailing space, if present, for hash property checks
+ var variable = this._input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g);
+
+ if (variable.match(/[ :]$/)) {
+ // we have a variable or pseudo-class, add it and insert one space before continuing
+ variable = this.eatString(": ").replace(/\s+$/, '');
+ this.print_string(variable);
+ this._output.space_before_token = true;
+ }
+
+ // might be sass variable
+ if (parenLevel === 0 && variable.indexOf(':') !== -1) {
+ insidePropertyValue = true;
+ this.indent();
+ }
+ } else if (this._ch === '@') {
this.preserveSingleSpace(isAfterSpace);
- // deal with less propery mixins @{...}
+ // deal with less property mixins @{...}
if (this._input.peek() === '{') {
this.print_string(this._ch + this.eatString('}'));
} else {
@@ -5324,29 +5372,26 @@ Beautifier.prototype.beautify = function() {
if (variableOrRule.match(/[ :]$/)) {
// we have a variable or pseudo-class, add it and insert one space before continuing
- variableOrRule = this.eatString(": ").replace(/\s$/, '');
+ variableOrRule = this.eatString(": ").replace(/\s+$/, '');
this.print_string(variableOrRule);
this._output.space_before_token = true;
}
- variableOrRule = variableOrRule.replace(/\s$/, '');
-
- if (variableOrRule === 'extend') {
- insideAtExtend = true;
- } else if (variableOrRule === 'import') {
- insideAtImport = true;
- }
+ // might be less variable
+ if (parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
+ insidePropertyValue = true;
+ this.indent();
- // might be a nesting at-rule
- if (variableOrRule in this.NESTED_AT_RULE) {
+ // might be a nesting at-rule
+ } else if (variableOrRule in this.NESTED_AT_RULE) {
this._nestedLevel += 1;
if (variableOrRule in this.CONDITIONAL_GROUP_RULE) {
enteringConditionalGroup = true;
}
- // might be less variable
- } else if (!insideRule && parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
- insidePropertyValue = true;
- this.indent();
+
+ // might be a non-nested at-rule
+ } else if (parenLevel === 0 && !insidePropertyValue) {
+ insideNonNestedAtRule = true;
}
}
} else if (this._ch === '#' && this._input.peek() === '{') {
@@ -5358,6 +5403,9 @@ Beautifier.prototype.beautify = function() {
this.outdent();
}
+ // non nested at rule becomes nested
+ insideNonNestedAtRule = false;
+
// when entering conditional groups, only rulesets are allowed
if (enteringConditionalGroup) {
enteringConditionalGroup = false;
@@ -5398,8 +5446,7 @@ Beautifier.prototype.beautify = function() {
if (previous_ch === '{') {
this._output.trim(true);
}
- insideAtImport = false;
- insideAtExtend = false;
+
if (insidePropertyValue) {
this.outdent();
insidePropertyValue = false;
@@ -5433,9 +5480,10 @@ Beautifier.prototype.beautify = function() {
}
}
- if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideAtExtend && parenLevel === 0) {
+ if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideNonNestedAtRule && parenLevel === 0) {
// 'property: value' delimiter
// which could be in a conditional group query
+
this.print_string(':');
if (!insidePropertyValue) {
insidePropertyValue = true;
@@ -5472,8 +5520,7 @@ Beautifier.prototype.beautify = function() {
this.outdent();
insidePropertyValue = false;
}
- insideAtExtend = false;
- insideAtImport = false;
+ insideNonNestedAtRule = false;
this.print_string(this._ch);
this.eatWhitespace(true);
@@ -5538,7 +5585,7 @@ Beautifier.prototype.beautify = function() {
} else if (this._ch === ',') {
this.print_string(this._ch);
this.eatWhitespace(true);
- if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideAtImport && !insideAtExtend) {
+ if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideNonNestedAtRule) {
this._output.add_new_line();
} else {
this._output.space_before_token = true;
@@ -6353,10 +6400,10 @@ function Options(options, merge_child_field) {
this.indent_empty_lines = this._get_boolean('indent_empty_lines');
- // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty']
- // For now, 'auto' = all off for javascript, all on for html (and inline javascript).
+ // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular']
+ // For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css).
// other values ignored
- this.templating = this._get_selection_list('templating', ['auto', 'none', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
+ this.templating = this._get_selection_list('templating', ['auto', 'none', 'angular', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
}
Options.prototype._get_array = function(name, default_value) {
@@ -7229,7 +7276,8 @@ var template_names = {
erb: false,
handlebars: false,
php: false,
- smarty: false
+ smarty: false,
+ angular: false
};
// This lets templates appear anywhere we would do a readUntil
@@ -7572,6 +7620,13 @@ Printer.prototype.indent = function() {
this.indent_level++;
};
+Printer.prototype.deindent = function() {
+ if (this.indent_level > 0) {
+ this.indent_level--;
+ this._output.set_indent(this.indent_level, this.alignment_size);
+ }
+};
+
Printer.prototype.get_full_indent = function(level) {
level = this.indent_level + (level || 0);
if (level < 1) {
@@ -7757,15 +7812,19 @@ Beautifier.prototype.beautify = function() {
while (raw_token.type !== TOKEN.EOF) {
if (raw_token.type === TOKEN.TAG_OPEN || raw_token.type === TOKEN.COMMENT) {
- parser_token = this._handle_tag_open(printer, raw_token, last_tag_token, last_token);
+ parser_token = this._handle_tag_open(printer, raw_token, last_tag_token, last_token, tokens);
last_tag_token = parser_token;
} else if ((raw_token.type === TOKEN.ATTRIBUTE || raw_token.type === TOKEN.EQUALS || raw_token.type === TOKEN.VALUE) ||
(raw_token.type === TOKEN.TEXT && !last_tag_token.tag_complete)) {
- parser_token = this._handle_inside_tag(printer, raw_token, last_tag_token, tokens);
+ parser_token = this._handle_inside_tag(printer, raw_token, last_tag_token, last_token);
} else if (raw_token.type === TOKEN.TAG_CLOSE) {
parser_token = this._handle_tag_close(printer, raw_token, last_tag_token);
} else if (raw_token.type === TOKEN.TEXT) {
parser_token = this._handle_text(printer, raw_token, last_tag_token);
+ } else if (raw_token.type === TOKEN.CONTROL_FLOW_OPEN) {
+ parser_token = this._handle_control_flow_open(printer, raw_token);
+ } else if (raw_token.type === TOKEN.CONTROL_FLOW_CLOSE) {
+ parser_token = this._handle_control_flow_close(printer, raw_token);
} else {
// This should never happen, but if it does. Print the raw token
printer.add_raw_token(raw_token);
@@ -7780,6 +7839,38 @@ Beautifier.prototype.beautify = function() {
return sweet_code;
};
+Beautifier.prototype._handle_control_flow_open = function(printer, raw_token) {
+ var parser_token = {
+ text: raw_token.text,
+ type: raw_token.type
+ };
+ printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true);
+ if (raw_token.newlines) {
+ printer.print_preserved_newlines(raw_token);
+ } else {
+ printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true);
+ }
+ printer.print_token(raw_token);
+ printer.indent();
+ return parser_token;
+};
+
+Beautifier.prototype._handle_control_flow_close = function(printer, raw_token) {
+ var parser_token = {
+ text: raw_token.text,
+ type: raw_token.type
+ };
+
+ printer.deindent();
+ if (raw_token.newlines) {
+ printer.print_preserved_newlines(raw_token);
+ } else {
+ printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true);
+ }
+ printer.print_token(raw_token);
+ return parser_token;
+};
+
Beautifier.prototype._handle_tag_close = function(printer, raw_token, last_tag_token) {
var parser_token = {
text: raw_token.text,
@@ -7818,7 +7909,7 @@ Beautifier.prototype._handle_tag_close = function(printer, raw_token, last_tag_t
return parser_token;
};
-Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_token, tokens) {
+Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_token, last_token) {
var wrapped = last_tag_token.has_wrapped_attrs;
var parser_token = {
text: raw_token.text,
@@ -7839,7 +7930,6 @@ Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_
} else {
if (raw_token.type === TOKEN.ATTRIBUTE) {
printer.set_space_before_token(true);
- last_tag_token.attr_count += 1;
} else if (raw_token.type === TOKEN.EQUALS) { //no space before =
printer.set_space_before_token(false);
} else if (raw_token.type === TOKEN.VALUE && raw_token.previous.type === TOKEN.EQUALS) { //no space before value
@@ -7852,29 +7942,15 @@ Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_
wrapped = wrapped || raw_token.newlines !== 0;
}
-
- if (this._is_wrap_attributes_force) {
- var force_attr_wrap = last_tag_token.attr_count > 1;
- if (this._is_wrap_attributes_force_expand_multiline && last_tag_token.attr_count === 1) {
- var is_only_attribute = true;
- var peek_index = 0;
- var peek_token;
- do {
- peek_token = tokens.peek(peek_index);
- if (peek_token.type === TOKEN.ATTRIBUTE) {
- is_only_attribute = false;
- break;
- }
- peek_index += 1;
- } while (peek_index < 4 && peek_token.type !== TOKEN.EOF && peek_token.type !== TOKEN.TAG_CLOSE);
-
- force_attr_wrap = !is_only_attribute;
- }
-
- if (force_attr_wrap) {
- printer.print_newline(false);
- wrapped = true;
- }
+ // Wrap for 'force' options, and if the number of attributes is at least that specified in 'wrap_attributes_min_attrs':
+ // 1. always wrap the second and beyond attributes
+ // 2. wrap the first attribute only if 'force-expand-multiline' is specified
+ if (this._is_wrap_attributes_force &&
+ last_tag_token.attr_count >= this._options.wrap_attributes_min_attrs &&
+ (last_token.type !== TOKEN.TAG_OPEN || // ie. second attribute and beyond
+ this._is_wrap_attributes_force_expand_multiline)) {
+ printer.print_newline(false);
+ wrapped = true;
}
}
printer.print_token(raw_token);
@@ -8003,12 +8079,12 @@ Beautifier.prototype._print_custom_beatifier_text = function(printer, raw_token,
}
};
-Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_token, last_token) {
+Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_token, last_token, tokens) {
var parser_token = this._get_tag_open_token(raw_token);
if ((last_tag_token.is_unformatted || last_tag_token.is_content_unformatted) &&
!last_tag_token.is_empty_element &&
- raw_token.type === TOKEN.TAG_OPEN && raw_token.text.indexOf('') === 0) {
+ raw_token.type === TOKEN.TAG_OPEN && !parser_token.is_start_tag) {
// End element tags for unformatted or content_unformatted elements
// are printed raw to keep any newlines inside them exactly the same.
printer.add_raw_token(raw_token);
@@ -8022,6 +8098,19 @@ Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_to
printer.print_token(raw_token);
}
+ // count the number of attributes
+ if (parser_token.is_start_tag && this._is_wrap_attributes_force) {
+ var peek_index = 0;
+ var peek_token;
+ do {
+ peek_token = tokens.peek(peek_index);
+ if (peek_token.type === TOKEN.ATTRIBUTE) {
+ parser_token.attr_count += 1;
+ }
+ peek_index += 1;
+ } while (peek_token.type !== TOKEN.EOF && peek_token.type !== TOKEN.TAG_CLOSE);
+ }
+
//indent attributes an auto, forced, aligned or forced-align line-wrap
if (this._is_wrap_attributes_force_aligned || this._is_wrap_attributes_aligned_multiple || this._is_wrap_attributes_preserve_aligned) {
parser_token.alignment_size = raw_token.text.length + 1;
@@ -8119,7 +8208,7 @@ Beautifier.prototype._get_tag_open_token = function(raw_token) { //function to g
parser_token.is_unformatted = !parser_token.tag_complete && in_array(parser_token.tag_check, this._options.unformatted);
parser_token.is_content_unformatted = !parser_token.is_empty_element && in_array(parser_token.tag_check, this._options.content_unformatted);
- parser_token.is_inline_element = in_array(parser_token.tag_name, this._options.inline) || parser_token.tag_name.includes("-") || parser_token.tag_start_char === '{';
+ parser_token.is_inline_element = in_array(parser_token.tag_name, this._options.inline) || (this._options.inline_custom_elements && parser_token.tag_name.includes("-")) || parser_token.tag_start_char === '{';
return parser_token;
};
@@ -8226,7 +8315,7 @@ Beautifier.prototype._calcluate_parent_multiline = function(printer, parser_toke
};
//To be used for
tag special case:
-var p_closers = ['address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'];
+var p_closers = ['address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'menu', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'];
var p_parent_excludes = ['a', 'audio', 'del', 'ins', 'map', 'noscript', 'video'];
Beautifier.prototype._do_optional_end_element = function(parser_token) {
@@ -8249,7 +8338,7 @@ Beautifier.prototype._do_optional_end_element = function(parser_token) {
} else if (parser_token.tag_name === 'li') {
// An li element’s end tag may be omitted if the li element is immediately followed by another li element or if there is no more content in the parent element.
- result = result || this._tag_stack.try_pop('li', ['ol', 'ul']);
+ result = result || this._tag_stack.try_pop('li', ['ol', 'ul', 'menu']);
} else if (parser_token.tag_name === 'dd' || parser_token.tag_name === 'dt') {
// A dd element’s end tag may be omitted if the dd element is immediately followed by another dd element or a dt element, or if there is no more content in the parent element.
@@ -8388,6 +8477,7 @@ function Options(options) {
this.indent_handlebars = this._get_boolean('indent_handlebars', true);
this.wrap_attributes = this._get_selection('wrap_attributes',
['auto', 'force', 'force-aligned', 'force-expand-multiline', 'aligned-multiple', 'preserve', 'preserve-aligned']);
+ this.wrap_attributes_min_attrs = this._get_number('wrap_attributes_min_attrs', 2);
this.wrap_attributes_indent_size = this._get_number('wrap_attributes_indent_size', this.indent_size);
this.extra_liners = this._get_array('extra_liners', ['head', 'body', '/html']);
@@ -8405,6 +8495,7 @@ function Options(options) {
// obsolete inline tags
'acronym', 'big', 'strike', 'tt'
]);
+ this.inline_custom_elements = this._get_boolean('inline_custom_elements', true);
this.void_elements = this._get_array('void_elements', [
// HTLM void elements - aka self-closing tags - aka singletons
// https://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
@@ -8479,6 +8570,8 @@ var Pattern = (__webpack_require__(12).Pattern);
var TOKEN = {
TAG_OPEN: 'TK_TAG_OPEN',
TAG_CLOSE: 'TK_TAG_CLOSE',
+ CONTROL_FLOW_OPEN: 'TK_CONTROL_FLOW_OPEN',
+ CONTROL_FLOW_CLOSE: 'TK_CONTROL_FLOW_CLOSE',
ATTRIBUTE: 'TK_ATTRIBUTE',
EQUALS: 'TK_EQUALS',
VALUE: 'TK_VALUE',
@@ -8503,11 +8596,13 @@ var Tokenizer = function(input_string, options) {
this.__patterns = {
word: templatable_reader.until(/[\n\r\t <]/),
+ word_control_flow_close_excluded: templatable_reader.until(/[\n\r\t <}]/),
single_quote: templatable_reader.until_after(/'/),
double_quote: templatable_reader.until_after(/"/),
attribute: templatable_reader.until(/[\n\r\t =>]|\/>/),
element_name: templatable_reader.until(/[\n\r\t >\/]/),
+ angular_control_flow_start: pattern_reader.matching(/\@[a-zA-Z]+[^({]*[({]/),
handlebars_comment: pattern_reader.starting_with(/{{!--/).until_after(/--}}/),
handlebars: pattern_reader.starting_with(/{{/).until_after(/}}/),
handlebars_open: pattern_reader.until(/[\n\r\t }]/),
@@ -8521,6 +8616,7 @@ var Tokenizer = function(input_string, options) {
if (this._options.indent_handlebars) {
this.__patterns.word = this.__patterns.word.exclude('handlebars');
+ this.__patterns.word_control_flow_close_excluded = this.__patterns.word_control_flow_close_excluded.exclude('handlebars');
}
this._unformatted_content_delimiter = null;
@@ -8539,14 +8635,16 @@ Tokenizer.prototype._is_comment = function(current_token) { // jshint unused:fal
};
Tokenizer.prototype._is_opening = function(current_token) {
- return current_token.type === TOKEN.TAG_OPEN;
+ return current_token.type === TOKEN.TAG_OPEN || current_token.type === TOKEN.CONTROL_FLOW_OPEN;
};
Tokenizer.prototype._is_closing = function(current_token, open_token) {
- return current_token.type === TOKEN.TAG_CLOSE &&
+ return (current_token.type === TOKEN.TAG_CLOSE &&
(open_token && (
((current_token.text === '>' || current_token.text === '/>') && open_token.text[0] === '<') ||
- (current_token.text === '}}' && open_token.text[0] === '{' && open_token.text[1] === '{')));
+ (current_token.text === '}}' && open_token.text[0] === '{' && open_token.text[1] === '{')))
+ ) || (current_token.type === TOKEN.CONTROL_FLOW_CLOSE &&
+ (current_token.text === '}' && open_token.text.endsWith('{')));
};
Tokenizer.prototype._reset = function() {
@@ -8565,8 +8663,9 @@ Tokenizer.prototype._get_next_token = function(previous_token, open_token) { //
token = token || this._read_open_handlebars(c, open_token);
token = token || this._read_attribute(c, previous_token, open_token);
token = token || this._read_close(c, open_token);
+ token = token || this._read_control_flows(c, open_token);
token = token || this._read_raw_content(c, previous_token, open_token);
- token = token || this._read_content_word(c);
+ token = token || this._read_content_word(c, open_token);
token = token || this._read_comment_or_cdata(c);
token = token || this._read_processing(c);
token = token || this._read_open(c, open_token);
@@ -8631,7 +8730,7 @@ Tokenizer.prototype._read_processing = function(c) { // jshint unused:false
Tokenizer.prototype._read_open = function(c, open_token) {
var resulting_string = null;
var token = null;
- if (!open_token) {
+ if (!open_token || open_token.type === TOKEN.CONTROL_FLOW_OPEN) {
if (c === '<') {
resulting_string = this._input.next();
@@ -8648,7 +8747,7 @@ Tokenizer.prototype._read_open = function(c, open_token) {
Tokenizer.prototype._read_open_handlebars = function(c, open_token) {
var resulting_string = null;
var token = null;
- if (!open_token) {
+ if (!open_token || open_token.type === TOKEN.CONTROL_FLOW_OPEN) {
if (this._options.indent_handlebars && c === '{' && this._input.peek(1) === '{') {
if (this._input.peek(2) === '!') {
resulting_string = this.__patterns.handlebars_comment.read();
@@ -8663,11 +8762,48 @@ Tokenizer.prototype._read_open_handlebars = function(c, open_token) {
return token;
};
+Tokenizer.prototype._read_control_flows = function(c, open_token) {
+ var resulting_string = '';
+ var token = null;
+ // Only check for control flows if angular templating is set AND indenting is set
+ if (!this._options.templating.includes('angular') || !this._options.indent_handlebars) {
+ return token;
+ }
+
+ if (c === '@') {
+ resulting_string = this.__patterns.angular_control_flow_start.read();
+ if (resulting_string === '') {
+ return token;
+ }
+
+ var opening_parentheses_count = resulting_string.endsWith('(') ? 1 : 0;
+ var closing_parentheses_count = 0;
+ // The opening brace of the control flow is where the number of opening and closing parentheses equal
+ // e.g. @if({value: true} !== null) {
+ while (!(resulting_string.endsWith('{') && opening_parentheses_count === closing_parentheses_count)) {
+ var next_char = this._input.next();
+ if (next_char === null) {
+ break;
+ } else if (next_char === '(') {
+ opening_parentheses_count++;
+ } else if (next_char === ')') {
+ closing_parentheses_count++;
+ }
+ resulting_string += next_char;
+ }
+ token = this._create_token(TOKEN.CONTROL_FLOW_OPEN, resulting_string);
+ } else if (c === '}' && open_token && open_token.type === TOKEN.CONTROL_FLOW_OPEN) {
+ resulting_string = this._input.next();
+ token = this._create_token(TOKEN.CONTROL_FLOW_CLOSE, resulting_string);
+ }
+ return token;
+};
+
Tokenizer.prototype._read_close = function(c, open_token) {
var resulting_string = null;
var token = null;
- if (open_token) {
+ if (open_token && open_token.type === TOKEN.TAG_OPEN) {
if (open_token.text[0] === '<' && (c === '>' || (c === '/' && this._input.peek(1) === '>'))) {
resulting_string = this._input.next();
if (c === '/') { // for close tag "/>"
@@ -8754,7 +8890,7 @@ Tokenizer.prototype._read_raw_content = function(c, previous_token, open_token)
return null;
};
-Tokenizer.prototype._read_content_word = function(c) {
+Tokenizer.prototype._read_content_word = function(c, open_token) {
var resulting_string = '';
if (this._options.unformatted_content_delimiter) {
if (c === this._options.unformatted_content_delimiter[0]) {
@@ -8763,7 +8899,7 @@ Tokenizer.prototype._read_content_word = function(c) {
}
if (!resulting_string) {
- resulting_string = this.__patterns.word.read();
+ resulting_string = (open_token && open_token.type === TOKEN.CONTROL_FLOW_OPEN) ? this.__patterns.word_control_flow_close_excluded.read() : this.__patterns.word.read();
}
if (resulting_string) {
return this._create_token(TOKEN.TEXT, resulting_string);
diff --git a/lib/editor/atto/plugins/html/yui/src/beautify/js/beautify-css.js b/lib/editor/atto/plugins/html/yui/src/beautify/js/beautify-css.js
index aa7d008bd8a4..36bc68577a63 100644
--- a/lib/editor/atto/plugins/html/yui/src/beautify/js/beautify-css.js
+++ b/lib/editor/atto/plugins/html/yui/src/beautify/js/beautify-css.js
@@ -571,10 +571,10 @@ function Options(options, merge_child_field) {
this.indent_empty_lines = this._get_boolean('indent_empty_lines');
- // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty']
- // For now, 'auto' = all off for javascript, all on for html (and inline javascript).
+ // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular']
+ // For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css).
// other values ignored
- this.templating = this._get_selection_list('templating', ['auto', 'none', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
+ this.templating = this._get_selection_list('templating', ['auto', 'none', 'angular', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
}
Options.prototype._get_array = function(name, default_value) {
@@ -1077,18 +1077,18 @@ function Beautifier(source_text, options) {
// https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
this.NESTED_AT_RULE = {
- "@page": true,
- "@font-face": true,
- "@keyframes": true,
+ "page": true,
+ "font-face": true,
+ "keyframes": true,
// also in CONDITIONAL_GROUP_RULE below
- "@media": true,
- "@supports": true,
- "@document": true
+ "media": true,
+ "supports": true,
+ "document": true
};
this.CONDITIONAL_GROUP_RULE = {
- "@media": true,
- "@supports": true,
- "@document": true
+ "media": true,
+ "supports": true,
+ "document": true
};
this.NON_SEMICOLON_NEWLINE_PROPERTY = [
"grid-template-areas",
@@ -1216,8 +1216,7 @@ Beautifier.prototype.beautify = function() {
// label { content: blue }
var insidePropertyValue = false;
var enteringConditionalGroup = false;
- var insideAtExtend = false;
- var insideAtImport = false;
+ var insideNonNestedAtRule = false;
var insideScssMap = false;
var topCharacter = this._ch;
var insideNonSemiColonValues = false;
@@ -1272,10 +1271,30 @@ Beautifier.prototype.beautify = function() {
// Ensures any new lines following the comment are preserved
this.eatWhitespace(true);
- } else if (this._ch === '@' || this._ch === '$') {
+ } else if (this._ch === '$') {
this.preserveSingleSpace(isAfterSpace);
- // deal with less propery mixins @{...}
+ this.print_string(this._ch);
+
+ // strip trailing space, if present, for hash property checks
+ var variable = this._input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g);
+
+ if (variable.match(/[ :]$/)) {
+ // we have a variable or pseudo-class, add it and insert one space before continuing
+ variable = this.eatString(": ").replace(/\s+$/, '');
+ this.print_string(variable);
+ this._output.space_before_token = true;
+ }
+
+ // might be sass variable
+ if (parenLevel === 0 && variable.indexOf(':') !== -1) {
+ insidePropertyValue = true;
+ this.indent();
+ }
+ } else if (this._ch === '@') {
+ this.preserveSingleSpace(isAfterSpace);
+
+ // deal with less property mixins @{...}
if (this._input.peek() === '{') {
this.print_string(this._ch + this.eatString('}'));
} else {
@@ -1286,29 +1305,26 @@ Beautifier.prototype.beautify = function() {
if (variableOrRule.match(/[ :]$/)) {
// we have a variable or pseudo-class, add it and insert one space before continuing
- variableOrRule = this.eatString(": ").replace(/\s$/, '');
+ variableOrRule = this.eatString(": ").replace(/\s+$/, '');
this.print_string(variableOrRule);
this._output.space_before_token = true;
}
- variableOrRule = variableOrRule.replace(/\s$/, '');
-
- if (variableOrRule === 'extend') {
- insideAtExtend = true;
- } else if (variableOrRule === 'import') {
- insideAtImport = true;
- }
+ // might be less variable
+ if (parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
+ insidePropertyValue = true;
+ this.indent();
- // might be a nesting at-rule
- if (variableOrRule in this.NESTED_AT_RULE) {
+ // might be a nesting at-rule
+ } else if (variableOrRule in this.NESTED_AT_RULE) {
this._nestedLevel += 1;
if (variableOrRule in this.CONDITIONAL_GROUP_RULE) {
enteringConditionalGroup = true;
}
- // might be less variable
- } else if (!insideRule && parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
- insidePropertyValue = true;
- this.indent();
+
+ // might be a non-nested at-rule
+ } else if (parenLevel === 0 && !insidePropertyValue) {
+ insideNonNestedAtRule = true;
}
}
} else if (this._ch === '#' && this._input.peek() === '{') {
@@ -1320,6 +1336,9 @@ Beautifier.prototype.beautify = function() {
this.outdent();
}
+ // non nested at rule becomes nested
+ insideNonNestedAtRule = false;
+
// when entering conditional groups, only rulesets are allowed
if (enteringConditionalGroup) {
enteringConditionalGroup = false;
@@ -1360,8 +1379,7 @@ Beautifier.prototype.beautify = function() {
if (previous_ch === '{') {
this._output.trim(true);
}
- insideAtImport = false;
- insideAtExtend = false;
+
if (insidePropertyValue) {
this.outdent();
insidePropertyValue = false;
@@ -1395,9 +1413,10 @@ Beautifier.prototype.beautify = function() {
}
}
- if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideAtExtend && parenLevel === 0) {
+ if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideNonNestedAtRule && parenLevel === 0) {
// 'property: value' delimiter
// which could be in a conditional group query
+
this.print_string(':');
if (!insidePropertyValue) {
insidePropertyValue = true;
@@ -1434,8 +1453,7 @@ Beautifier.prototype.beautify = function() {
this.outdent();
insidePropertyValue = false;
}
- insideAtExtend = false;
- insideAtImport = false;
+ insideNonNestedAtRule = false;
this.print_string(this._ch);
this.eatWhitespace(true);
@@ -1500,7 +1518,7 @@ Beautifier.prototype.beautify = function() {
} else if (this._ch === ',') {
this.print_string(this._ch);
this.eatWhitespace(true);
- if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideAtImport && !insideAtExtend) {
+ if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideNonNestedAtRule) {
this._output.add_new_line();
} else {
this._output.space_before_token = true;
diff --git a/lib/editor/atto/plugins/html/yui/src/beautify/js/beautify-html.js b/lib/editor/atto/plugins/html/yui/src/beautify/js/beautify-html.js
index ff60dace527c..48fa73716ab9 100644
--- a/lib/editor/atto/plugins/html/yui/src/beautify/js/beautify-html.js
+++ b/lib/editor/atto/plugins/html/yui/src/beautify/js/beautify-html.js
@@ -640,10 +640,10 @@ function Options(options, merge_child_field) {
this.indent_empty_lines = this._get_boolean('indent_empty_lines');
- // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty']
- // For now, 'auto' = all off for javascript, all on for html (and inline javascript).
+ // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular']
+ // For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css).
// other values ignored
- this.templating = this._get_selection_list('templating', ['auto', 'none', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
+ this.templating = this._get_selection_list('templating', ['auto', 'none', 'angular', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
}
Options.prototype._get_array = function(name, default_value) {
@@ -1516,7 +1516,8 @@ var template_names = {
erb: false,
handlebars: false,
php: false,
- smarty: false
+ smarty: false,
+ angular: false
};
// This lets templates appear anywhere we would do a readUntil
@@ -1859,6 +1860,13 @@ Printer.prototype.indent = function() {
this.indent_level++;
};
+Printer.prototype.deindent = function() {
+ if (this.indent_level > 0) {
+ this.indent_level--;
+ this._output.set_indent(this.indent_level, this.alignment_size);
+ }
+};
+
Printer.prototype.get_full_indent = function(level) {
level = this.indent_level + (level || 0);
if (level < 1) {
@@ -2044,15 +2052,19 @@ Beautifier.prototype.beautify = function() {
while (raw_token.type !== TOKEN.EOF) {
if (raw_token.type === TOKEN.TAG_OPEN || raw_token.type === TOKEN.COMMENT) {
- parser_token = this._handle_tag_open(printer, raw_token, last_tag_token, last_token);
+ parser_token = this._handle_tag_open(printer, raw_token, last_tag_token, last_token, tokens);
last_tag_token = parser_token;
} else if ((raw_token.type === TOKEN.ATTRIBUTE || raw_token.type === TOKEN.EQUALS || raw_token.type === TOKEN.VALUE) ||
(raw_token.type === TOKEN.TEXT && !last_tag_token.tag_complete)) {
- parser_token = this._handle_inside_tag(printer, raw_token, last_tag_token, tokens);
+ parser_token = this._handle_inside_tag(printer, raw_token, last_tag_token, last_token);
} else if (raw_token.type === TOKEN.TAG_CLOSE) {
parser_token = this._handle_tag_close(printer, raw_token, last_tag_token);
} else if (raw_token.type === TOKEN.TEXT) {
parser_token = this._handle_text(printer, raw_token, last_tag_token);
+ } else if (raw_token.type === TOKEN.CONTROL_FLOW_OPEN) {
+ parser_token = this._handle_control_flow_open(printer, raw_token);
+ } else if (raw_token.type === TOKEN.CONTROL_FLOW_CLOSE) {
+ parser_token = this._handle_control_flow_close(printer, raw_token);
} else {
// This should never happen, but if it does. Print the raw token
printer.add_raw_token(raw_token);
@@ -2067,6 +2079,38 @@ Beautifier.prototype.beautify = function() {
return sweet_code;
};
+Beautifier.prototype._handle_control_flow_open = function(printer, raw_token) {
+ var parser_token = {
+ text: raw_token.text,
+ type: raw_token.type
+ };
+ printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true);
+ if (raw_token.newlines) {
+ printer.print_preserved_newlines(raw_token);
+ } else {
+ printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true);
+ }
+ printer.print_token(raw_token);
+ printer.indent();
+ return parser_token;
+};
+
+Beautifier.prototype._handle_control_flow_close = function(printer, raw_token) {
+ var parser_token = {
+ text: raw_token.text,
+ type: raw_token.type
+ };
+
+ printer.deindent();
+ if (raw_token.newlines) {
+ printer.print_preserved_newlines(raw_token);
+ } else {
+ printer.set_space_before_token(raw_token.newlines || raw_token.whitespace_before !== '', true);
+ }
+ printer.print_token(raw_token);
+ return parser_token;
+};
+
Beautifier.prototype._handle_tag_close = function(printer, raw_token, last_tag_token) {
var parser_token = {
text: raw_token.text,
@@ -2105,7 +2149,7 @@ Beautifier.prototype._handle_tag_close = function(printer, raw_token, last_tag_t
return parser_token;
};
-Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_token, tokens) {
+Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_token, last_token) {
var wrapped = last_tag_token.has_wrapped_attrs;
var parser_token = {
text: raw_token.text,
@@ -2126,7 +2170,6 @@ Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_
} else {
if (raw_token.type === TOKEN.ATTRIBUTE) {
printer.set_space_before_token(true);
- last_tag_token.attr_count += 1;
} else if (raw_token.type === TOKEN.EQUALS) { //no space before =
printer.set_space_before_token(false);
} else if (raw_token.type === TOKEN.VALUE && raw_token.previous.type === TOKEN.EQUALS) { //no space before value
@@ -2139,29 +2182,15 @@ Beautifier.prototype._handle_inside_tag = function(printer, raw_token, last_tag_
wrapped = wrapped || raw_token.newlines !== 0;
}
-
- if (this._is_wrap_attributes_force) {
- var force_attr_wrap = last_tag_token.attr_count > 1;
- if (this._is_wrap_attributes_force_expand_multiline && last_tag_token.attr_count === 1) {
- var is_only_attribute = true;
- var peek_index = 0;
- var peek_token;
- do {
- peek_token = tokens.peek(peek_index);
- if (peek_token.type === TOKEN.ATTRIBUTE) {
- is_only_attribute = false;
- break;
- }
- peek_index += 1;
- } while (peek_index < 4 && peek_token.type !== TOKEN.EOF && peek_token.type !== TOKEN.TAG_CLOSE);
-
- force_attr_wrap = !is_only_attribute;
- }
-
- if (force_attr_wrap) {
- printer.print_newline(false);
- wrapped = true;
- }
+ // Wrap for 'force' options, and if the number of attributes is at least that specified in 'wrap_attributes_min_attrs':
+ // 1. always wrap the second and beyond attributes
+ // 2. wrap the first attribute only if 'force-expand-multiline' is specified
+ if (this._is_wrap_attributes_force &&
+ last_tag_token.attr_count >= this._options.wrap_attributes_min_attrs &&
+ (last_token.type !== TOKEN.TAG_OPEN || // ie. second attribute and beyond
+ this._is_wrap_attributes_force_expand_multiline)) {
+ printer.print_newline(false);
+ wrapped = true;
}
}
printer.print_token(raw_token);
@@ -2290,12 +2319,12 @@ Beautifier.prototype._print_custom_beatifier_text = function(printer, raw_token,
}
};
-Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_token, last_token) {
+Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_token, last_token, tokens) {
var parser_token = this._get_tag_open_token(raw_token);
if ((last_tag_token.is_unformatted || last_tag_token.is_content_unformatted) &&
!last_tag_token.is_empty_element &&
- raw_token.type === TOKEN.TAG_OPEN && raw_token.text.indexOf('') === 0) {
+ raw_token.type === TOKEN.TAG_OPEN && !parser_token.is_start_tag) {
// End element tags for unformatted or content_unformatted elements
// are printed raw to keep any newlines inside them exactly the same.
printer.add_raw_token(raw_token);
@@ -2309,6 +2338,19 @@ Beautifier.prototype._handle_tag_open = function(printer, raw_token, last_tag_to
printer.print_token(raw_token);
}
+ // count the number of attributes
+ if (parser_token.is_start_tag && this._is_wrap_attributes_force) {
+ var peek_index = 0;
+ var peek_token;
+ do {
+ peek_token = tokens.peek(peek_index);
+ if (peek_token.type === TOKEN.ATTRIBUTE) {
+ parser_token.attr_count += 1;
+ }
+ peek_index += 1;
+ } while (peek_token.type !== TOKEN.EOF && peek_token.type !== TOKEN.TAG_CLOSE);
+ }
+
//indent attributes an auto, forced, aligned or forced-align line-wrap
if (this._is_wrap_attributes_force_aligned || this._is_wrap_attributes_aligned_multiple || this._is_wrap_attributes_preserve_aligned) {
parser_token.alignment_size = raw_token.text.length + 1;
@@ -2406,7 +2448,7 @@ Beautifier.prototype._get_tag_open_token = function(raw_token) { //function to g
parser_token.is_unformatted = !parser_token.tag_complete && in_array(parser_token.tag_check, this._options.unformatted);
parser_token.is_content_unformatted = !parser_token.is_empty_element && in_array(parser_token.tag_check, this._options.content_unformatted);
- parser_token.is_inline_element = in_array(parser_token.tag_name, this._options.inline) || parser_token.tag_name.includes("-") || parser_token.tag_start_char === '{';
+ parser_token.is_inline_element = in_array(parser_token.tag_name, this._options.inline) || (this._options.inline_custom_elements && parser_token.tag_name.includes("-")) || parser_token.tag_start_char === '{';
return parser_token;
};
@@ -2513,7 +2555,7 @@ Beautifier.prototype._calcluate_parent_multiline = function(printer, parser_toke
};
//To be used for
tag special case:
-var p_closers = ['address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'];
+var p_closers = ['address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'menu', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'];
var p_parent_excludes = ['a', 'audio', 'del', 'ins', 'map', 'noscript', 'video'];
Beautifier.prototype._do_optional_end_element = function(parser_token) {
@@ -2536,7 +2578,7 @@ Beautifier.prototype._do_optional_end_element = function(parser_token) {
} else if (parser_token.tag_name === 'li') {
// An li element’s end tag may be omitted if the li element is immediately followed by another li element or if there is no more content in the parent element.
- result = result || this._tag_stack.try_pop('li', ['ol', 'ul']);
+ result = result || this._tag_stack.try_pop('li', ['ol', 'ul', 'menu']);
} else if (parser_token.tag_name === 'dd' || parser_token.tag_name === 'dt') {
// A dd element’s end tag may be omitted if the dd element is immediately followed by another dd element or a dt element, or if there is no more content in the parent element.
@@ -2675,6 +2717,7 @@ function Options(options) {
this.indent_handlebars = this._get_boolean('indent_handlebars', true);
this.wrap_attributes = this._get_selection('wrap_attributes',
['auto', 'force', 'force-aligned', 'force-expand-multiline', 'aligned-multiple', 'preserve', 'preserve-aligned']);
+ this.wrap_attributes_min_attrs = this._get_number('wrap_attributes_min_attrs', 2);
this.wrap_attributes_indent_size = this._get_number('wrap_attributes_indent_size', this.indent_size);
this.extra_liners = this._get_array('extra_liners', ['head', 'body', '/html']);
@@ -2692,6 +2735,7 @@ function Options(options) {
// obsolete inline tags
'acronym', 'big', 'strike', 'tt'
]);
+ this.inline_custom_elements = this._get_boolean('inline_custom_elements', true);
this.void_elements = this._get_array('void_elements', [
// HTLM void elements - aka self-closing tags - aka singletons
// https://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
@@ -2766,6 +2810,8 @@ var Pattern = (__webpack_require__(12).Pattern);
var TOKEN = {
TAG_OPEN: 'TK_TAG_OPEN',
TAG_CLOSE: 'TK_TAG_CLOSE',
+ CONTROL_FLOW_OPEN: 'TK_CONTROL_FLOW_OPEN',
+ CONTROL_FLOW_CLOSE: 'TK_CONTROL_FLOW_CLOSE',
ATTRIBUTE: 'TK_ATTRIBUTE',
EQUALS: 'TK_EQUALS',
VALUE: 'TK_VALUE',
@@ -2790,11 +2836,13 @@ var Tokenizer = function(input_string, options) {
this.__patterns = {
word: templatable_reader.until(/[\n\r\t <]/),
+ word_control_flow_close_excluded: templatable_reader.until(/[\n\r\t <}]/),
single_quote: templatable_reader.until_after(/'/),
double_quote: templatable_reader.until_after(/"/),
attribute: templatable_reader.until(/[\n\r\t =>]|\/>/),
element_name: templatable_reader.until(/[\n\r\t >\/]/),
+ angular_control_flow_start: pattern_reader.matching(/\@[a-zA-Z]+[^({]*[({]/),
handlebars_comment: pattern_reader.starting_with(/{{!--/).until_after(/--}}/),
handlebars: pattern_reader.starting_with(/{{/).until_after(/}}/),
handlebars_open: pattern_reader.until(/[\n\r\t }]/),
@@ -2808,6 +2856,7 @@ var Tokenizer = function(input_string, options) {
if (this._options.indent_handlebars) {
this.__patterns.word = this.__patterns.word.exclude('handlebars');
+ this.__patterns.word_control_flow_close_excluded = this.__patterns.word_control_flow_close_excluded.exclude('handlebars');
}
this._unformatted_content_delimiter = null;
@@ -2826,14 +2875,16 @@ Tokenizer.prototype._is_comment = function(current_token) { // jshint unused:fal
};
Tokenizer.prototype._is_opening = function(current_token) {
- return current_token.type === TOKEN.TAG_OPEN;
+ return current_token.type === TOKEN.TAG_OPEN || current_token.type === TOKEN.CONTROL_FLOW_OPEN;
};
Tokenizer.prototype._is_closing = function(current_token, open_token) {
- return current_token.type === TOKEN.TAG_CLOSE &&
+ return (current_token.type === TOKEN.TAG_CLOSE &&
(open_token && (
((current_token.text === '>' || current_token.text === '/>') && open_token.text[0] === '<') ||
- (current_token.text === '}}' && open_token.text[0] === '{' && open_token.text[1] === '{')));
+ (current_token.text === '}}' && open_token.text[0] === '{' && open_token.text[1] === '{')))
+ ) || (current_token.type === TOKEN.CONTROL_FLOW_CLOSE &&
+ (current_token.text === '}' && open_token.text.endsWith('{')));
};
Tokenizer.prototype._reset = function() {
@@ -2852,8 +2903,9 @@ Tokenizer.prototype._get_next_token = function(previous_token, open_token) { //
token = token || this._read_open_handlebars(c, open_token);
token = token || this._read_attribute(c, previous_token, open_token);
token = token || this._read_close(c, open_token);
+ token = token || this._read_control_flows(c, open_token);
token = token || this._read_raw_content(c, previous_token, open_token);
- token = token || this._read_content_word(c);
+ token = token || this._read_content_word(c, open_token);
token = token || this._read_comment_or_cdata(c);
token = token || this._read_processing(c);
token = token || this._read_open(c, open_token);
@@ -2918,7 +2970,7 @@ Tokenizer.prototype._read_processing = function(c) { // jshint unused:false
Tokenizer.prototype._read_open = function(c, open_token) {
var resulting_string = null;
var token = null;
- if (!open_token) {
+ if (!open_token || open_token.type === TOKEN.CONTROL_FLOW_OPEN) {
if (c === '<') {
resulting_string = this._input.next();
@@ -2935,7 +2987,7 @@ Tokenizer.prototype._read_open = function(c, open_token) {
Tokenizer.prototype._read_open_handlebars = function(c, open_token) {
var resulting_string = null;
var token = null;
- if (!open_token) {
+ if (!open_token || open_token.type === TOKEN.CONTROL_FLOW_OPEN) {
if (this._options.indent_handlebars && c === '{' && this._input.peek(1) === '{') {
if (this._input.peek(2) === '!') {
resulting_string = this.__patterns.handlebars_comment.read();
@@ -2950,11 +3002,48 @@ Tokenizer.prototype._read_open_handlebars = function(c, open_token) {
return token;
};
+Tokenizer.prototype._read_control_flows = function(c, open_token) {
+ var resulting_string = '';
+ var token = null;
+ // Only check for control flows if angular templating is set AND indenting is set
+ if (!this._options.templating.includes('angular') || !this._options.indent_handlebars) {
+ return token;
+ }
+
+ if (c === '@') {
+ resulting_string = this.__patterns.angular_control_flow_start.read();
+ if (resulting_string === '') {
+ return token;
+ }
+
+ var opening_parentheses_count = resulting_string.endsWith('(') ? 1 : 0;
+ var closing_parentheses_count = 0;
+ // The opening brace of the control flow is where the number of opening and closing parentheses equal
+ // e.g. @if({value: true} !== null) {
+ while (!(resulting_string.endsWith('{') && opening_parentheses_count === closing_parentheses_count)) {
+ var next_char = this._input.next();
+ if (next_char === null) {
+ break;
+ } else if (next_char === '(') {
+ opening_parentheses_count++;
+ } else if (next_char === ')') {
+ closing_parentheses_count++;
+ }
+ resulting_string += next_char;
+ }
+ token = this._create_token(TOKEN.CONTROL_FLOW_OPEN, resulting_string);
+ } else if (c === '}' && open_token && open_token.type === TOKEN.CONTROL_FLOW_OPEN) {
+ resulting_string = this._input.next();
+ token = this._create_token(TOKEN.CONTROL_FLOW_CLOSE, resulting_string);
+ }
+ return token;
+};
+
Tokenizer.prototype._read_close = function(c, open_token) {
var resulting_string = null;
var token = null;
- if (open_token) {
+ if (open_token && open_token.type === TOKEN.TAG_OPEN) {
if (open_token.text[0] === '<' && (c === '>' || (c === '/' && this._input.peek(1) === '>'))) {
resulting_string = this._input.next();
if (c === '/') { // for close tag "/>"
@@ -3041,7 +3130,7 @@ Tokenizer.prototype._read_raw_content = function(c, previous_token, open_token)
return null;
};
-Tokenizer.prototype._read_content_word = function(c) {
+Tokenizer.prototype._read_content_word = function(c, open_token) {
var resulting_string = '';
if (this._options.unformatted_content_delimiter) {
if (c === this._options.unformatted_content_delimiter[0]) {
@@ -3050,7 +3139,7 @@ Tokenizer.prototype._read_content_word = function(c) {
}
if (!resulting_string) {
- resulting_string = this.__patterns.word.read();
+ resulting_string = (open_token && open_token.type === TOKEN.CONTROL_FLOW_OPEN) ? this.__patterns.word_control_flow_close_excluded.read() : this.__patterns.word.read();
}
if (resulting_string) {
return this._create_token(TOKEN.TEXT, resulting_string);
diff --git a/lib/editor/atto/plugins/html/yui/src/beautify/js/beautify.js b/lib/editor/atto/plugins/html/yui/src/beautify/js/beautify.js
index d02605dca719..377364038124 100644
--- a/lib/editor/atto/plugins/html/yui/src/beautify/js/beautify.js
+++ b/lib/editor/atto/plugins/html/yui/src/beautify/js/beautify.js
@@ -59,7 +59,7 @@
} }
space_after_anon_function (default false) - should the space before an anonymous function's parens be added, "function()" vs "function ()",
- NOTE: This option is overriden by jslint_happy (i.e. if jslint_happy is true, space_after_anon_function is true by design)
+ NOTE: This option is overridden by jslint_happy (i.e. if jslint_happy is true, space_after_anon_function is true by design)
brace_style (default "collapse") - "collapse" | "expand" | "end-expand" | "none" | any of the former + ",preserve-inline"
put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line, or attempt to keep them where they are.
@@ -910,7 +910,7 @@ Beautifier.prototype.handle_start_block = function(current_token) {
}
}
if (this._flags.last_token.type !== TOKEN.OPERATOR && this._flags.last_token.type !== TOKEN.START_EXPR) {
- if (this._flags.last_token.type === TOKEN.START_BLOCK && !this._flags.inline_frame) {
+ if (in_array(this._flags.last_token.type, [TOKEN.START_BLOCK, TOKEN.SEMICOLON]) && !this._flags.inline_frame) {
this.print_newline();
} else {
this._output.space_before_token = true;
@@ -1036,7 +1036,9 @@ Beautifier.prototype.handle_word = function(current_token) {
}
if (this._flags.last_token.type === TOKEN.COMMA || this._flags.last_token.type === TOKEN.START_EXPR || this._flags.last_token.type === TOKEN.EQUALS || this._flags.last_token.type === TOKEN.OPERATOR) {
- if (!this.start_of_object_property()) {
+ if (!this.start_of_object_property() && !(
+ // start of object property is different for numeric values with +/- prefix operators
+ in_array(this._flags.last_token.text, ['+', '-']) && this._last_last_text === ':' && this._flags.parent.mode === MODE.ObjectLiteral)) {
this.allow_wrap_or_preserved_newline(current_token);
}
}
@@ -1317,6 +1319,12 @@ Beautifier.prototype.handle_operator = function(current_token) {
return;
}
+ if (in_array(current_token.text, ['-', '+']) && this.start_of_object_property()) {
+ // numeric value with +/- symbol in front as a property
+ this.print_token(current_token);
+ return;
+ }
+
// Allow line wrapping between operators when operator_position is
// set to before or preserve
if (this._flags.last_token.type === TOKEN.OPERATOR && in_array(this._options.operator_position, OPERATOR_POSITION_BEFORE_OR_PRESERVE)) {
@@ -2143,12 +2151,13 @@ var nonASCIIidentifierChars = "\\u0300-\\u036f\\u0483-\\u0487\\u0591-\\u05bd\\u0
//var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
//var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
-var identifierStart = "(?:\\\\u[0-9a-fA-F]{4}|[" + baseASCIIidentifierStartChars + nonASCIIidentifierStartChars + "])";
-var identifierChars = "(?:\\\\u[0-9a-fA-F]{4}|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])*";
+var unicodeEscapeOrCodePoint = "\\\\u[0-9a-fA-F]{4}|\\\\u\\{[0-9a-fA-F]+\\}";
+var identifierStart = "(?:" + unicodeEscapeOrCodePoint + "|[" + baseASCIIidentifierStartChars + nonASCIIidentifierStartChars + "])";
+var identifierChars = "(?:" + unicodeEscapeOrCodePoint + "|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])*";
exports.identifier = new RegExp(identifierStart + identifierChars, 'g');
exports.identifierStart = new RegExp(identifierStart);
-exports.identifierMatch = new RegExp("(?:\\\\u[0-9a-fA-F]{4}|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])+");
+exports.identifierMatch = new RegExp("(?:" + unicodeEscapeOrCodePoint + "|[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "])+");
var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/; // jshint ignore:line
@@ -2337,10 +2346,10 @@ function Options(options, merge_child_field) {
this.indent_empty_lines = this._get_boolean('indent_empty_lines');
- // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty']
- // For now, 'auto' = all off for javascript, all on for html (and inline javascript).
+ // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty', 'angular']
+ // For now, 'auto' = all off for javascript, all except angular on for html (and inline javascript/css).
// other values ignored
- this.templating = this._get_selection_list('templating', ['auto', 'none', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
+ this.templating = this._get_selection_list('templating', ['auto', 'none', 'angular', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']);
}
Options.prototype._get_array = function(name, default_value) {
@@ -2636,6 +2645,7 @@ Tokenizer.prototype._get_next_token = function(previous_token, open_token) { //
token = token || this._read_non_javascript(c);
token = token || this._read_string(c);
+ token = token || this._read_pair(c, this._input.peek(1)); // Issue #2062 hack for record type '#{'
token = token || this._read_word(previous_token);
token = token || this._read_singles(c);
token = token || this._read_comment(c);
@@ -2694,6 +2704,19 @@ Tokenizer.prototype._read_singles = function(c) {
return token;
};
+Tokenizer.prototype._read_pair = function(c, d) {
+ var token = null;
+ if (c === '#' && d === '{') {
+ token = this._create_token(TOKEN.START_BLOCK, c + d);
+ }
+
+ if (token) {
+ this._input.next();
+ this._input.next();
+ }
+ return token;
+};
+
Tokenizer.prototype._read_punctuation = function() {
var resulting_string = this.__patterns.punct.read();
@@ -2939,6 +2962,9 @@ function unescape_string(s) {
matched = input_scan.match(/x([0-9A-Fa-f]{2})/g);
} else if (input_scan.peek() === 'u') {
matched = input_scan.match(/u([0-9A-Fa-f]{4})/g);
+ if (!matched) {
+ matched = input_scan.match(/u\{([0-9A-Fa-f]+)\}/g);
+ }
} else {
out += '\\';
if (input_scan.hasNext()) {
@@ -2962,7 +2988,9 @@ function unescape_string(s) {
} else if (escaped >= 0x00 && escaped < 0x20) {
// leave 0x00...0x1f escaped
out += '\\' + matched[0];
- continue;
+ } else if (escaped > 0x10FFFF) {
+ // If the escape sequence is out of bounds, keep the original sequence and continue conversion
+ out += '\\' + matched[0];
} else if (escaped === 0x22 || escaped === 0x27 || escaped === 0x5c) {
// single-quote, apostrophe, backslash - escape these
out += '\\' + String.fromCharCode(escaped);
@@ -3785,7 +3813,8 @@ var template_names = {
erb: false,
handlebars: false,
php: false,
- smarty: false
+ smarty: false,
+ angular: false
};
// This lets templates appear anywhere we would do a readUntil
diff --git a/lib/editor/atto/plugins/html/yui/src/beautify/readme_moodle.txt b/lib/editor/atto/plugins/html/yui/src/beautify/readme_moodle.txt
index 50583795bcd4..150a51141586 100644
--- a/lib/editor/atto/plugins/html/yui/src/beautify/readme_moodle.txt
+++ b/lib/editor/atto/plugins/html/yui/src/beautify/readme_moodle.txt
@@ -1,7 +1,7 @@
Description of importing the js-beautify library into Moodle.
* Download the latest version from https://github.com/beautify-web/js-beautify/releases
-* Copy lib/beautify*.js into lib/editor/atto/plugins/html/yui/src/beautify/js
+* Copy js/lib/beautify*.js into lib/editor/atto/plugins/html/yui/src/beautify/js
* Copy LICENSE into lib/editor/atto/plugins/html/yui/src/beautify
* Update lib/editor/atto/plugins/html/thirdpartylibs.xml
* Rebuild the module
diff --git a/lib/editor/tiny/plugins/premium/lang/en/tiny_premium.php b/lib/editor/tiny/plugins/premium/lang/en/tiny_premium.php
index dd88bf64b8a7..78788f06e978 100644
--- a/lib/editor/tiny/plugins/premium/lang/en/tiny_premium.php
+++ b/lib/editor/tiny/plugins/premium/lang/en/tiny_premium.php
@@ -25,8 +25,8 @@
defined('MOODLE_INTERNAL') || die();
-$string['pluginname'] = 'Tiny premium';
+$string['pluginname'] = 'TinyMCE Premium';
$string['apikey'] = 'API key';
-$string['apikey_desc'] = 'Your Tiny premium API key requires a paid subscription. You can find your key on your Tiny Cloud account page.';
-$string['premium:accesspremium'] = 'Access Tiny Premium features';
+$string['apikey_desc'] = '
Your API key is available on your Tiny Cloud account page if you have purchased a subscription, or if you are on a free trial.
See the list of available TinyMCE Premium features for Moodle in Moodle Docs.
';
+$string['premium:accesspremium'] = 'Access TinyMCE Premium features';
$string['privacy:metadata'] = 'The Tiny premium plugin for TinyMCE does not store any personal data.';
diff --git a/lib/external/tests/external_api_test.php b/lib/external/tests/external_api_test.php
index cc359cae2294..f806785b7797 100644
--- a/lib/external/tests/external_api_test.php
+++ b/lib/external/tests/external_api_test.php
@@ -469,7 +469,6 @@ public function test_call_external_function(): void {
protected function get_context_from_params() {
$rc = new \ReflectionClass(external_api::class);
$method = $rc->getMethod('get_context_from_params');
- $method->setAccessible(true);
return $method->invokeArgs(null, func_get_args());
}
}
diff --git a/lib/filestorage/tests/file_system_filedir_test.php b/lib/filestorage/tests/file_system_filedir_test.php
index 2d7532f405d1..69d5bca3462e 100644
--- a/lib/filestorage/tests/file_system_filedir_test.php
+++ b/lib/filestorage/tests/file_system_filedir_test.php
@@ -218,7 +218,6 @@ public function test_get_remote_path_from_hash() {
->willReturn($expectedresult);
$method = new \ReflectionMethod(file_system_filedir::class, 'get_remote_path_from_hash');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, [$contenthash]);
$this->assertEquals($expectedresult, $result);
@@ -294,7 +293,6 @@ public function test_get_fulldir_from_hash($hash, $hashdir) {
$fs = new file_system_filedir();
$method = new \ReflectionMethod(file_system_filedir::class, 'get_fulldir_from_hash');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, array($hash));
$expectedpath = sprintf('%s/filedir/%s', $CFG->dataroot, $hashdir);
@@ -326,7 +324,6 @@ public function test_get_fulldir_from_storedfile($hash, $hashdir) {
$fs = new file_system_filedir();
$method = new \ReflectionMethod('file_system_filedir', 'get_fulldir_from_storedfile');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, array($file));
$expectedpath = sprintf('%s/filedir/%s', $CFG->dataroot, $hashdir);
@@ -345,7 +342,6 @@ public function test_get_fulldir_from_storedfile($hash, $hashdir) {
*/
public function test_get_contentdir_from_hash($hash, $hashdir) {
$method = new \ReflectionMethod(file_system_filedir::class, 'get_contentdir_from_hash');
- $method->setAccessible(true);
$fs = new file_system_filedir();
$result = $method->invokeArgs($fs, array($hash));
@@ -365,7 +361,6 @@ public function test_get_contentdir_from_hash($hash, $hashdir) {
*/
public function test_get_contentpath_from_hash($hash, $hashdir) {
$method = new \ReflectionMethod(file_system_filedir::class, 'get_contentpath_from_hash');
- $method->setAccessible(true);
$fs = new file_system_filedir();
$result = $method->invokeArgs($fs, array($hash));
@@ -389,7 +384,6 @@ public function test_get_trash_fullpath_from_hash($hash, $hashdir) {
$fs = new file_system_filedir();
$method = new \ReflectionMethod(file_system_filedir::class, 'get_trash_fullpath_from_hash');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, array($hash));
$expectedpath = sprintf('%s/trashdir/%s/%s', $CFG->dataroot, $hashdir, $hash);
@@ -411,7 +405,6 @@ public function test_get_trash_fulldir_from_hash($hash, $hashdir) {
$fs = new file_system_filedir();
$method = new \ReflectionMethod(file_system_filedir::class, 'get_trash_fulldir_from_hash');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, array($hash));
$expectedpath = sprintf('%s/trashdir/%s', $CFG->dataroot, $hashdir);
@@ -486,7 +479,6 @@ public function test_recover_file() {
$fs = new file_system_filedir();
$method = new \ReflectionMethod(file_system_filedir::class, 'recover_file');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, array($file));
// Test the output.
@@ -526,7 +518,6 @@ public function test_recover_file_already_present() {
$fs = new file_system_filedir();
$method = new \ReflectionMethod(file_system_filedir::class, 'recover_file');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, array($file));
// Test the output.
@@ -564,7 +555,6 @@ public function test_recover_file_size_mismatch() {
$fs = new file_system_filedir();
$method = new \ReflectionMethod(file_system_filedir::class, 'recover_file');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, array($file));
// Test the output.
@@ -601,7 +591,6 @@ public function test_recover_file_has_mismatch() {
$fs = new file_system_filedir();
$method = new \ReflectionMethod(file_system_filedir::class, 'recover_file');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, array($file));
// Test the output.
@@ -635,7 +624,6 @@ public function test_recover_file_alttrash() {
$fs = new file_system_filedir();
$method = new \ReflectionMethod(file_system_filedir::class, 'recover_file');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, array($file));
// Test the output.
@@ -675,7 +663,6 @@ public function test_recover_file_contentdir_readonly() {
$fs = new file_system_filedir();
$method = new \ReflectionMethod(file_system_filedir::class, 'recover_file');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, array($file));
// Test the output.
@@ -1092,7 +1079,6 @@ public function test_empty_trash() {
$fs = new file_system_filedir();
$method = new \ReflectionMethod(file_system_filedir::class, 'empty_trash');
- $method->setAccessible(true);
$result = $method->invoke($fs);
$this->assertTrue($vfileroot->hasChild('filedir/0f/f3/' . $contenthash));
diff --git a/lib/filestorage/tests/file_system_test.php b/lib/filestorage/tests/file_system_test.php
index 9a854308ed93..edd1d8d1075f 100644
--- a/lib/filestorage/tests/file_system_test.php
+++ b/lib/filestorage/tests/file_system_test.php
@@ -494,7 +494,6 @@ public function test_is_file_removable_empty() {
$contenthash = \file_storage::hash_from_string($filecontent);
$method = new \ReflectionMethod(file_system::class, 'is_file_removable');
- $method->setAccessible(true);
$result = $method->invokeArgs(null, [$contenthash]);
$this->assertFalse($result);
}
@@ -517,7 +516,6 @@ public function test_is_file_removable_in_use() {
$DB->method('record_exists')->willReturn(true);
$method = new \ReflectionMethod(file_system::class, 'is_file_removable');
- $method->setAccessible(true);
$result = $method->invokeArgs(null, [$contenthash]);
$this->assertFalse($result);
@@ -541,7 +539,6 @@ public function test_is_file_removable_not_in_use() {
$DB->method('record_exists')->willReturn(false);
$method = new \ReflectionMethod(file_system::class, 'is_file_removable');
- $method->setAccessible(true);
$result = $method->invokeArgs(null, [$contenthash]);
$this->assertTrue($result);
@@ -910,7 +907,6 @@ public function test_get_imageinfo_from_path() {
$fs = $this->get_testable_mock();
$method = new \ReflectionMethod(file_system::class, 'get_imageinfo_from_path');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, [$filepath]);
$this->assertArrayHasKey('width', $result);
@@ -932,7 +928,6 @@ public function test_get_imageinfo_from_path_no_image() {
$fs = $this->get_testable_mock();
$method = new \ReflectionMethod(file_system::class, 'get_imageinfo_from_path');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, [$filepath]);
$this->assertFalse($result);
@@ -949,7 +944,6 @@ public function test_get_imageinfo_from_path_svg_viewbox() {
$fs = $this->get_testable_mock();
$method = new \ReflectionMethod(file_system::class, 'get_imageinfo_from_path');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, [$filepath]);
$this->assertArrayHasKey('width', $result);
@@ -971,7 +965,6 @@ public function test_get_imageinfo_from_path_svg_with_width_height() {
$fs = $this->get_testable_mock();
$method = new \ReflectionMethod(file_system::class, 'get_imageinfo_from_path');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, [$filepath]);
$this->assertArrayHasKey('width', $result);
@@ -993,7 +986,6 @@ public function test_get_imageinfo_from_path_svg_without_attribute() {
$fs = $this->get_testable_mock();
$method = new \ReflectionMethod(file_system::class, 'get_imageinfo_from_path');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, [$filepath]);
$this->assertArrayHasKey('width', $result);
@@ -1015,7 +1007,6 @@ public function test_get_imageinfo_from_path_svg_invalid() {
$fs = $this->get_testable_mock();
$method = new \ReflectionMethod(file_system::class, 'get_imageinfo_from_path');
- $method->setAccessible(true);
$result = $method->invokeArgs($fs, [$filepath]);
$this->assertFalse($result);
diff --git a/lib/form/amd/build/events.min.js b/lib/form/amd/build/events.min.js
index 1769f39fabae..2dcca565d70b 100644
--- a/lib/form/amd/build/events.min.js
+++ b/lib/form/amd/build/events.min.js
@@ -14,6 +14,6 @@ define("core_form/events",["exports","core/str","core/event_dispatcher","jquery"
* window.console.log(e.target); // The form that was submitted.
* window.console.log(e.detail.skipValidation); // Whether form validation was skipped.
* });
- */let changesMadeString;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.types=_exports.triggerUploadStarted=_exports.triggerUploadCompleted=_exports.notifyUploadStarted=_exports.notifyUploadCompleted=_exports.notifyUploadChanged=_exports.notifyFormSubmittedByJavascript=_exports.notifyFormError=_exports.notifyFieldValidationFailure=_exports.eventTypes=void 0,_jquery=_interopRequireDefault(_jquery),_yui=_interopRequireDefault(_yui);const changesMadeCheck=e=>{e&&(e.returnValue=changesMadeString)},eventTypes={formError:"core_form/error",formSubmittedByJavascript:"core_form/submittedByJavascript",formFieldValidationFailed:"core_form/fieldValidationFailed",uploadStarted:"core_form/uploadStarted",uploadCompleted:"core_form/uploadCompleted",uploadChanged:"core_form/uploadChanged"};_exports.eventTypes=eventTypes;_exports.notifyFormError=field=>(0,_event_dispatcher.dispatchEvent)(eventTypes.formError,{},field);_exports.notifyFormSubmittedByJavascript=function(form){let skipValidation=arguments.length>1&&void 0!==arguments[1]&&arguments[1],fallbackHandled=arguments.length>2&&void 0!==arguments[2]&&arguments[2];skipValidation&&(window.skipClientValidation=!0);const customEvent=(0,_event_dispatcher.dispatchEvent)(eventTypes.formSubmittedByJavascript,{skipValidation:skipValidation,fallbackHandled:fallbackHandled},form);return skipValidation&&(window.skipClientValidation=!1),customEvent};_exports.notifyFieldValidationFailure=(field,message)=>(0,_event_dispatcher.dispatchEvent)(eventTypes.formFieldValidationFailed,{message:message},field,{cancelable:!0});const notifyUploadStarted=async elementId=>(changesMadeString=await(0,_str.getString)("changesmadereallygoaway","moodle"),window.addEventListener("beforeunload",changesMadeCheck),(0,_event_dispatcher.dispatchEvent)(eventTypes.uploadStarted,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1}));_exports.notifyUploadStarted=notifyUploadStarted;const notifyUploadCompleted=elementId=>(window.removeEventListener("beforeunload",changesMadeCheck),(0,_event_dispatcher.dispatchEvent)(eventTypes.uploadCompleted,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1}));_exports.notifyUploadCompleted=notifyUploadCompleted;const triggerUploadStarted=notifyUploadStarted;_exports.triggerUploadStarted=triggerUploadStarted;const triggerUploadCompleted=notifyUploadCompleted;_exports.triggerUploadCompleted=triggerUploadCompleted;_exports.types={uploadStarted:"core_form/uploadStarted",uploadCompleted:"core_form/uploadCompleted"};let legacyEventsRegistered=!1;legacyEventsRegistered||(_yui.default.use("event","moodle-core-event",(()=>{document.addEventListener(eventTypes.formError,(e=>{const element=_yui.default.one(e.target),formElement=_yui.default.one(e.target.closest("form"));_yui.default.Global.fire(M.core.globalEvents.FORM_ERROR,{formid:formElement.generateID(),elementid:element.generateID()})})),document.addEventListener(eventTypes.formSubmittedByJavascript,(e=>{if(e.detail.fallbackHandled)return;e.skipValidation&&(window.skipClientValidation=!0);const form=_yui.default.one(e.target);form.fire(M.core.event.FORM_SUBMIT_AJAX,{currentTarget:form,fallbackHandled:!0}),e.skipValidation&&(window.skipClientValidation=!1)}))})),document.addEventListener(eventTypes.formFieldValidationFailed,(e=>{const legacyEvent=_jquery.default.Event("core_form-field-validation");(0,_jquery.default)(e.target).trigger(legacyEvent,e.detail.message)})),legacyEventsRegistered=!0);_exports.notifyUploadChanged=elementId=>(0,_event_dispatcher.dispatchEvent)(eventTypes.uploadChanged,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1})}));
+ */let changesMadeString;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.types=_exports.triggerUploadStarted=_exports.triggerUploadCompleted=_exports.notifyUploadStarted=_exports.notifyUploadCompleted=_exports.notifyUploadChanged=_exports.notifyFormSubmittedByJavascript=_exports.notifyFormError=_exports.notifyFieldValidationFailure=_exports.notifyFieldStructureChanged=_exports.eventTypes=void 0,_jquery=_interopRequireDefault(_jquery),_yui=_interopRequireDefault(_yui);const changesMadeCheck=e=>{e&&(e.returnValue=changesMadeString)},eventTypes={formError:"core_form/error",formSubmittedByJavascript:"core_form/submittedByJavascript",formFieldValidationFailed:"core_form/fieldValidationFailed",uploadStarted:"core_form/uploadStarted",uploadCompleted:"core_form/uploadCompleted",uploadChanged:"core_form/uploadChanged",fieldStructureChanged:"core_form/fieldStructureChanged"};_exports.eventTypes=eventTypes;_exports.notifyFormError=field=>(0,_event_dispatcher.dispatchEvent)(eventTypes.formError,{},field);_exports.notifyFormSubmittedByJavascript=function(form){let skipValidation=arguments.length>1&&void 0!==arguments[1]&&arguments[1],fallbackHandled=arguments.length>2&&void 0!==arguments[2]&&arguments[2];skipValidation&&(window.skipClientValidation=!0);const customEvent=(0,_event_dispatcher.dispatchEvent)(eventTypes.formSubmittedByJavascript,{skipValidation:skipValidation,fallbackHandled:fallbackHandled},form);return skipValidation&&(window.skipClientValidation=!1),customEvent};_exports.notifyFieldValidationFailure=(field,message)=>(0,_event_dispatcher.dispatchEvent)(eventTypes.formFieldValidationFailed,{message:message},field,{cancelable:!0});const notifyUploadStarted=async elementId=>(changesMadeString=await(0,_str.getString)("changesmadereallygoaway","moodle"),window.addEventListener("beforeunload",changesMadeCheck),(0,_event_dispatcher.dispatchEvent)(eventTypes.uploadStarted,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1}));_exports.notifyUploadStarted=notifyUploadStarted;const notifyUploadCompleted=elementId=>(window.removeEventListener("beforeunload",changesMadeCheck),(0,_event_dispatcher.dispatchEvent)(eventTypes.uploadCompleted,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1}));_exports.notifyUploadCompleted=notifyUploadCompleted;const triggerUploadStarted=notifyUploadStarted;_exports.triggerUploadStarted=triggerUploadStarted;const triggerUploadCompleted=notifyUploadCompleted;_exports.triggerUploadCompleted=triggerUploadCompleted;_exports.types={uploadStarted:"core_form/uploadStarted",uploadCompleted:"core_form/uploadCompleted"};let legacyEventsRegistered=!1;legacyEventsRegistered||(_yui.default.use("event","moodle-core-event",(()=>{document.addEventListener(eventTypes.formError,(e=>{const element=_yui.default.one(e.target),formElement=_yui.default.one(e.target.closest("form"));_yui.default.Global.fire(M.core.globalEvents.FORM_ERROR,{formid:formElement.generateID(),elementid:element.generateID()})})),document.addEventListener(eventTypes.formSubmittedByJavascript,(e=>{if(e.detail.fallbackHandled)return;e.skipValidation&&(window.skipClientValidation=!0);const form=_yui.default.one(e.target);form.fire(M.core.event.FORM_SUBMIT_AJAX,{currentTarget:form,fallbackHandled:!0}),e.skipValidation&&(window.skipClientValidation=!1)}))})),document.addEventListener(eventTypes.formFieldValidationFailed,(e=>{const legacyEvent=_jquery.default.Event("core_form-field-validation");(0,_jquery.default)(e.target).trigger(legacyEvent,e.detail.message)})),legacyEventsRegistered=!0);_exports.notifyUploadChanged=elementId=>(0,_event_dispatcher.dispatchEvent)(eventTypes.uploadChanged,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1});_exports.notifyFieldStructureChanged=elementId=>(0,_event_dispatcher.dispatchEvent)(eventTypes.fieldStructureChanged,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1})}));
//# sourceMappingURL=events.min.js.map
\ No newline at end of file
diff --git a/lib/form/amd/build/events.min.js.map b/lib/form/amd/build/events.min.js.map
index f928286812d6..5757b431f7d2 100644
--- a/lib/form/amd/build/events.min.js.map
+++ b/lib/form/amd/build/events.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"events.min.js","sources":["../src/events.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript events for the `core_form` subsystem.\n *\n * @module core_form/events\n * @copyright 2021 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.10\n *\n * @example
Example of listening to a form event.
\n * import {eventTypes as formEventTypes} from 'core_form/events';\n *\n * document.addEventListener(formEventTypes.formSubmittedByJavascript, e => {\n * window.console.log(e.target); // The form that was submitted.\n * window.console.log(e.detail.skipValidation); // Whether form validation was skipped.\n * });\n */\n\nimport {getString} from 'core/str';\nimport {dispatchEvent} from 'core/event_dispatcher';\n\nlet changesMadeString;\n\n/**\n * Prevent user navigate away when upload progress still running.\n * @param {Event} e The event\n */\nconst changesMadeCheck = e => {\n if (e) {\n e.returnValue = changesMadeString;\n }\n};\n\n/**\n * Events for `core_form`.\n *\n * @constant\n * @property {String} formError See {@link event:core_form/error}\n * @property {String} formFieldValidationFailed See {@link event:core_form/fieldValidationFailed}\n * @property {String} formSubmittedByJavascript See {@link event:core_form/submittedByJavascript}\n * @property {String} uploadChanged See {@link event:core_form/uploadChanged}\n */\nexport const eventTypes = {\n /**\n * An event triggered when a form contains an error\n *\n * @event formError\n * @type {CustomEvent}\n * @property {HTMLElement} target The form field which errored\n */\n formError: 'core_form/error',\n\n /**\n * An event triggered when an mform is about to be submitted via javascript.\n *\n * @event core_form/submittedByJavascript\n * @type {CustomEvent}\n * @property {HTMLElement} target The form that was submitted\n * @property {object} detail\n * @property {boolean} detail.skipValidation Whether the form was submitted without validation (i.e. via a Cancel button)\n * @property {boolean} detail.fallbackHandled Whether the legacy YUI event has been handled\n */\n formSubmittedByJavascript: 'core_form/submittedByJavascript',\n\n /**\n * An event triggered upon form field validation failure.\n *\n * @event core_form/fieldValidationFailed\n * @type {CustomEvent}\n * @property {HTMLElement} target The field that failed validation\n * @property {object} detail\n * @property {String} detail.message The message displayed upon failure\n */\n formFieldValidationFailed: 'core_form/fieldValidationFailed',\n\n /**\n * An event triggered when an upload is started\n *\n * @event core_form/uploadStarted\n * @type {CustomEvent}\n * @property {HTMLElement} target The location where the upload began\n */\n uploadStarted: 'core_form/uploadStarted',\n\n /**\n * An event triggered when an upload completes\n *\n * @event core_form/uploadCompleted\n * @type {CustomEvent}\n * @property {HTMLElement} target The location where the upload completed\n */\n uploadCompleted: 'core_form/uploadCompleted',\n\n /**\n * An event triggered when a file upload field has been changed.\n *\n * @event core_form/uploadChanged\n * @type {CustomEvent}\n * @property {HTMLElement} target The form field which was changed\n */\n uploadChanged: 'core_form/uploadChanged',\n};\n\n// These are only imported for legacy.\nimport jQuery from 'jquery';\nimport Y from 'core/yui';\n\n/**\n * Trigger an event to indicate that a form field contained an error.\n *\n * @method notifyFormError\n * @param {HTMLElement} field The form field causing the error\n * @returns {CustomEvent}\n * @fires formError\n */\nexport const notifyFormError = field => dispatchEvent(eventTypes.formError, {}, field);\n\n/**\n * Trigger an event to indiciate that a form was submitted by Javascript.\n *\n * @method\n * @param {HTMLElement} form The form that was submitted\n * @param {Boolean} skipValidation Submit the form without validation. E.g. \"Cancel\".\n * @param {Boolean} fallbackHandled The legacy YUI event has been handled\n * @returns {CustomEvent}\n * @fires formSubmittedByJavascript\n */\nexport const notifyFormSubmittedByJavascript = (form, skipValidation = false, fallbackHandled = false) => {\n if (skipValidation) {\n window.skipClientValidation = true;\n }\n\n const customEvent = dispatchEvent(\n eventTypes.formSubmittedByJavascript,\n {\n skipValidation,\n fallbackHandled,\n },\n form\n );\n\n if (skipValidation) {\n window.skipClientValidation = false;\n }\n\n return customEvent;\n};\n\n/**\n * Trigger an event to indicate that a form field contained an error.\n *\n * @method notifyFieldValidationFailure\n * @param {HTMLElement} field The field which failed validation\n * @param {String} message The message displayed\n * @returns {CustomEvent}\n * @fires formFieldValidationFailed\n */\nexport const notifyFieldValidationFailure = (field, message) => dispatchEvent(\n eventTypes.formFieldValidationFailed,\n {\n message,\n },\n field,\n {\n cancelable: true\n }\n);\n\n/**\n * Trigger an event to indicate that an upload was started.\n *\n * @method\n * @param {String} elementId The element which was uploaded to\n * @returns {CustomEvent}\n * @fires uploadStarted\n */\nexport const notifyUploadStarted = async elementId => {\n // Add an additional check for changes made.\n changesMadeString = await getString('changesmadereallygoaway', 'moodle');\n window.addEventListener('beforeunload', changesMadeCheck);\n\n return dispatchEvent(\n eventTypes.uploadStarted,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n );\n};\n\n/**\n * Trigger an event to indicate that an upload was completed.\n *\n * @method\n * @param {String} elementId The element which was uploaded to\n * @returns {CustomEvent}\n * @fires uploadCompleted\n */\nexport const notifyUploadCompleted = elementId => {\n // Remove the additional check for changes made.\n window.removeEventListener('beforeunload', changesMadeCheck);\n\n return dispatchEvent(\n eventTypes.uploadCompleted,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n );\n};\n\n/**\n * Trigger upload start event.\n *\n * @method\n * @param {String} elementId\n * @returns {CustomEvent}\n * @fires uploadStarted\n * @deprecated Since Moodle 4.0 See {@link module:core_form/events.notifyUploadStarted notifyUploadStarted}\n */\nexport const triggerUploadStarted = notifyUploadStarted;\n\n/**\n * Trigger upload complete event.\n *\n * @method\n * @param {String} elementId\n * @returns {CustomEvent}\n * @fires uploadCompleted\n * @deprecated Since Moodle 4.0 See {@link module:core_form/events.notifyUploadCompleted notifyUploadCompleted}\n */\nexport const triggerUploadCompleted = notifyUploadCompleted;\n\n/**\n * List of the events.\n *\n * @deprecated since Moodle 4.0. See {@link module:core_form/events.eventTypes eventTypes} instead.\n **/\nexport const types = {\n uploadStarted: 'core_form/uploadStarted',\n uploadCompleted: 'core_form/uploadCompleted',\n};\n\nlet legacyEventsRegistered = false;\nif (!legacyEventsRegistered) {\n // The following event triggers are legacy and will be removed in the future.\n // The following approach provides a backwards-compatability layer for the new events.\n // Code should be updated to make use of native events.\n Y.use('event', 'moodle-core-event', () => {\n\n // Watch for the new native formError event, and trigger the legacy YUI event.\n document.addEventListener(eventTypes.formError, e => {\n const element = Y.one(e.target);\n const formElement = Y.one(e.target.closest('form'));\n\n Y.Global.fire(\n M.core.globalEvents.FORM_ERROR,\n {\n formid: formElement.generateID(),\n elementid: element.generateID(),\n }\n );\n });\n\n // Watch for the new native formSubmittedByJavascript event, and trigger the legacy YUI event.\n document.addEventListener(eventTypes.formSubmittedByJavascript, e => {\n if (e.detail.fallbackHandled) {\n // This event was originally generated by a YUI event.\n // Do not generate another as this will recurse.\n return;\n }\n\n if (e.skipValidation) {\n window.skipClientValidation = true;\n }\n\n // Trigger the legacy YUI event.\n const form = Y.one(e.target);\n form.fire(\n M.core.event.FORM_SUBMIT_AJAX,\n {\n currentTarget: form,\n fallbackHandled: true,\n }\n );\n\n if (e.skipValidation) {\n window.skipClientValidation = false;\n }\n });\n });\n\n // Watch for the new native formFieldValidationFailed event, and trigger the legacy jQuery event.\n document.addEventListener(eventTypes.formFieldValidationFailed, e => {\n // Note: The \"core_form-field-validation\" event is hard-coded in core/event.\n // This is not included to prevent cyclic module dependencies.\n const legacyEvent = jQuery.Event(\"core_form-field-validation\");\n\n jQuery(e.target).trigger(legacyEvent, e.detail.message);\n });\n\n legacyEventsRegistered = true;\n}\n\n/**\n * Trigger an event to notify the file upload field has been changed.\n *\n * @method\n * @param {string} elementId The element which was changed\n * @returns {CustomEvent}\n * @fires uploadChanged\n */\nexport const notifyUploadChanged = elementId => dispatchEvent(\n eventTypes.uploadChanged,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n);\n"],"names":["changesMadeString","changesMadeCheck","e","returnValue","eventTypes","formError","formSubmittedByJavascript","formFieldValidationFailed","uploadStarted","uploadCompleted","uploadChanged","field","form","skipValidation","fallbackHandled","window","skipClientValidation","customEvent","message","cancelable","notifyUploadStarted","async","addEventListener","document","getElementById","elementId","bubbles","cancellable","notifyUploadCompleted","removeEventListener","triggerUploadStarted","triggerUploadCompleted","legacyEventsRegistered","use","element","Y","one","target","formElement","closest","Global","fire","M","core","globalEvents","FORM_ERROR","formid","generateID","elementid","detail","event","FORM_SUBMIT_AJAX","currentTarget","legacyEvent","jQuery","Event","trigger"],"mappings":";;;;;;;;;;;;;;;;SAmCIA,mcAMEC,iBAAmBC,IACjBA,IACAA,EAAEC,YAAcH,oBAaXI,WAAa,CAQtBC,UAAW,kBAYXC,0BAA2B,kCAW3BC,0BAA2B,kCAS3BC,cAAe,0BASfC,gBAAiB,4BASjBC,cAAe,mFAeYC,QAAS,mCAAcP,WAAWC,UAAW,GAAIM,gDAYjC,SAACC,UAAMC,uEAAwBC,wEACtED,iBACAE,OAAOC,sBAAuB,SAG5BC,aAAc,mCAChBb,WAAWE,0BACX,CACIO,eAAAA,eACAC,gBAAAA,iBAEJF,aAGAC,iBACAE,OAAOC,sBAAuB,GAG3BC,mDAYiC,CAACN,MAAOO,WAAY,mCAC5Dd,WAAWG,0BACX,CACIW,QAAAA,SAEJP,MACA,CACIQ,YAAY,UAYPC,oBAAsBC,MAAAA,YAE/BrB,wBAA0B,kBAAU,0BAA2B,UAC/De,OAAOO,iBAAiB,eAAgBrB,mBAEjC,mCACHG,WAAWI,cACX,GACAe,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa,4DAaZC,sBAAwBH,YAEjCV,OAAOc,oBAAoB,eAAgB5B,mBAEpC,mCACHG,WAAWK,gBACX,GACAc,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa,gEAcZG,qBAAuBV,6EAWvBW,uBAAyBH,4FAOjB,CACjBpB,cAAe,0BACfC,gBAAiB,iCAGjBuB,wBAAyB,EACxBA,sCAICC,IAAI,QAAS,qBAAqB,KAGhCV,SAASD,iBAAiBlB,WAAWC,WAAWH,UACtCgC,QAAUC,aAAEC,IAAIlC,EAAEmC,QAClBC,YAAcH,aAAEC,IAAIlC,EAAEmC,OAAOE,QAAQ,sBAEzCC,OAAOC,KACLC,EAAEC,KAAKC,aAAaC,WACpB,CACIC,OAAQR,YAAYS,aACpBC,UAAWd,QAAQa,kBAM/BxB,SAASD,iBAAiBlB,WAAWE,2BAA2BJ,OACxDA,EAAE+C,OAAOnC,uBAMTZ,EAAEW,iBACFE,OAAOC,sBAAuB,SAI5BJ,KAAOuB,aAAEC,IAAIlC,EAAEmC,QACrBzB,KAAK6B,KACDC,EAAEC,KAAKO,MAAMC,iBACb,CACIC,cAAexC,KACfE,iBAAiB,IAIrBZ,EAAEW,iBACFE,OAAOC,sBAAuB,SAM1CO,SAASD,iBAAiBlB,WAAWG,2BAA2BL,UAGtDmD,YAAcC,gBAAOC,MAAM,kDAE1BrD,EAAEmC,QAAQmB,QAAQH,YAAanD,EAAE+C,OAAO/B,YAGnDc,wBAAyB,gCAWMP,YAAa,mCAC5CrB,WAAWM,cACX,GACAa,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa"}
\ No newline at end of file
+{"version":3,"file":"events.min.js","sources":["../src/events.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript events for the `core_form` subsystem.\n *\n * @module core_form/events\n * @copyright 2021 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.10\n *\n * @example
Example of listening to a form event.
\n * import {eventTypes as formEventTypes} from 'core_form/events';\n *\n * document.addEventListener(formEventTypes.formSubmittedByJavascript, e => {\n * window.console.log(e.target); // The form that was submitted.\n * window.console.log(e.detail.skipValidation); // Whether form validation was skipped.\n * });\n */\n\nimport {getString} from 'core/str';\nimport {dispatchEvent} from 'core/event_dispatcher';\n\nlet changesMadeString;\n\n/**\n * Prevent user navigate away when upload progress still running.\n * @param {Event} e The event\n */\nconst changesMadeCheck = e => {\n if (e) {\n e.returnValue = changesMadeString;\n }\n};\n\n/**\n * Events for `core_form`.\n *\n * @constant\n * @property {String} formError See {@link event:core_form/error}\n * @property {String} formFieldValidationFailed See {@link event:core_form/fieldValidationFailed}\n * @property {String} formSubmittedByJavascript See {@link event:core_form/submittedByJavascript}\n * @property {String} uploadChanged See {@link event:core_form/uploadChanged}\n * @property {String} fieldStructureChanged See {@link event:core_form/fieldStructureChanged}\n */\nexport const eventTypes = {\n /**\n * An event triggered when a form contains an error\n *\n * @event formError\n * @type {CustomEvent}\n * @property {HTMLElement} target The form field which errored\n */\n formError: 'core_form/error',\n\n /**\n * An event triggered when an mform is about to be submitted via javascript.\n *\n * @event core_form/submittedByJavascript\n * @type {CustomEvent}\n * @property {HTMLElement} target The form that was submitted\n * @property {object} detail\n * @property {boolean} detail.skipValidation Whether the form was submitted without validation (i.e. via a Cancel button)\n * @property {boolean} detail.fallbackHandled Whether the legacy YUI event has been handled\n */\n formSubmittedByJavascript: 'core_form/submittedByJavascript',\n\n /**\n * An event triggered upon form field validation failure.\n *\n * @event core_form/fieldValidationFailed\n * @type {CustomEvent}\n * @property {HTMLElement} target The field that failed validation\n * @property {object} detail\n * @property {String} detail.message The message displayed upon failure\n */\n formFieldValidationFailed: 'core_form/fieldValidationFailed',\n\n /**\n * An event triggered when an upload is started\n *\n * @event core_form/uploadStarted\n * @type {CustomEvent}\n * @property {HTMLElement} target The location where the upload began\n */\n uploadStarted: 'core_form/uploadStarted',\n\n /**\n * An event triggered when an upload completes\n *\n * @event core_form/uploadCompleted\n * @type {CustomEvent}\n * @property {HTMLElement} target The location where the upload completed\n */\n uploadCompleted: 'core_form/uploadCompleted',\n\n /**\n * An event triggered when a file upload field has been changed.\n *\n * @event core_form/uploadChanged\n * @type {CustomEvent}\n * @property {HTMLElement} target The form field which was changed\n */\n uploadChanged: 'core_form/uploadChanged',\n\n /**\n * An event triggered when a form field structure has changed.\n *\n * @event core_form/fieldStructureChanged\n * @type {CustomEvent}\n * @property {HTMLElement} target The form field that has changed\n */\n fieldStructureChanged: 'core_form/fieldStructureChanged',\n};\n\n// These are only imported for legacy.\nimport jQuery from 'jquery';\nimport Y from 'core/yui';\n\n/**\n * Trigger an event to indicate that a form field contained an error.\n *\n * @method notifyFormError\n * @param {HTMLElement} field The form field causing the error\n * @returns {CustomEvent}\n * @fires formError\n */\nexport const notifyFormError = field => dispatchEvent(eventTypes.formError, {}, field);\n\n/**\n * Trigger an event to indiciate that a form was submitted by Javascript.\n *\n * @method\n * @param {HTMLElement} form The form that was submitted\n * @param {Boolean} skipValidation Submit the form without validation. E.g. \"Cancel\".\n * @param {Boolean} fallbackHandled The legacy YUI event has been handled\n * @returns {CustomEvent}\n * @fires formSubmittedByJavascript\n */\nexport const notifyFormSubmittedByJavascript = (form, skipValidation = false, fallbackHandled = false) => {\n if (skipValidation) {\n window.skipClientValidation = true;\n }\n\n const customEvent = dispatchEvent(\n eventTypes.formSubmittedByJavascript,\n {\n skipValidation,\n fallbackHandled,\n },\n form\n );\n\n if (skipValidation) {\n window.skipClientValidation = false;\n }\n\n return customEvent;\n};\n\n/**\n * Trigger an event to indicate that a form field contained an error.\n *\n * @method notifyFieldValidationFailure\n * @param {HTMLElement} field The field which failed validation\n * @param {String} message The message displayed\n * @returns {CustomEvent}\n * @fires formFieldValidationFailed\n */\nexport const notifyFieldValidationFailure = (field, message) => dispatchEvent(\n eventTypes.formFieldValidationFailed,\n {\n message,\n },\n field,\n {\n cancelable: true\n }\n);\n\n/**\n * Trigger an event to indicate that an upload was started.\n *\n * @method\n * @param {String} elementId The element which was uploaded to\n * @returns {CustomEvent}\n * @fires uploadStarted\n */\nexport const notifyUploadStarted = async elementId => {\n // Add an additional check for changes made.\n changesMadeString = await getString('changesmadereallygoaway', 'moodle');\n window.addEventListener('beforeunload', changesMadeCheck);\n\n return dispatchEvent(\n eventTypes.uploadStarted,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n );\n};\n\n/**\n * Trigger an event to indicate that an upload was completed.\n *\n * @method\n * @param {String} elementId The element which was uploaded to\n * @returns {CustomEvent}\n * @fires uploadCompleted\n */\nexport const notifyUploadCompleted = elementId => {\n // Remove the additional check for changes made.\n window.removeEventListener('beforeunload', changesMadeCheck);\n\n return dispatchEvent(\n eventTypes.uploadCompleted,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n );\n};\n\n/**\n * Trigger upload start event.\n *\n * @method\n * @param {String} elementId\n * @returns {CustomEvent}\n * @fires uploadStarted\n * @deprecated Since Moodle 4.0 See {@link module:core_form/events.notifyUploadStarted notifyUploadStarted}\n */\nexport const triggerUploadStarted = notifyUploadStarted;\n\n/**\n * Trigger upload complete event.\n *\n * @method\n * @param {String} elementId\n * @returns {CustomEvent}\n * @fires uploadCompleted\n * @deprecated Since Moodle 4.0 See {@link module:core_form/events.notifyUploadCompleted notifyUploadCompleted}\n */\nexport const triggerUploadCompleted = notifyUploadCompleted;\n\n/**\n * List of the events.\n *\n * @deprecated since Moodle 4.0. See {@link module:core_form/events.eventTypes eventTypes} instead.\n **/\nexport const types = {\n uploadStarted: 'core_form/uploadStarted',\n uploadCompleted: 'core_form/uploadCompleted',\n};\n\nlet legacyEventsRegistered = false;\nif (!legacyEventsRegistered) {\n // The following event triggers are legacy and will be removed in the future.\n // The following approach provides a backwards-compatability layer for the new events.\n // Code should be updated to make use of native events.\n Y.use('event', 'moodle-core-event', () => {\n\n // Watch for the new native formError event, and trigger the legacy YUI event.\n document.addEventListener(eventTypes.formError, e => {\n const element = Y.one(e.target);\n const formElement = Y.one(e.target.closest('form'));\n\n Y.Global.fire(\n M.core.globalEvents.FORM_ERROR,\n {\n formid: formElement.generateID(),\n elementid: element.generateID(),\n }\n );\n });\n\n // Watch for the new native formSubmittedByJavascript event, and trigger the legacy YUI event.\n document.addEventListener(eventTypes.formSubmittedByJavascript, e => {\n if (e.detail.fallbackHandled) {\n // This event was originally generated by a YUI event.\n // Do not generate another as this will recurse.\n return;\n }\n\n if (e.skipValidation) {\n window.skipClientValidation = true;\n }\n\n // Trigger the legacy YUI event.\n const form = Y.one(e.target);\n form.fire(\n M.core.event.FORM_SUBMIT_AJAX,\n {\n currentTarget: form,\n fallbackHandled: true,\n }\n );\n\n if (e.skipValidation) {\n window.skipClientValidation = false;\n }\n });\n });\n\n // Watch for the new native formFieldValidationFailed event, and trigger the legacy jQuery event.\n document.addEventListener(eventTypes.formFieldValidationFailed, e => {\n // Note: The \"core_form-field-validation\" event is hard-coded in core/event.\n // This is not included to prevent cyclic module dependencies.\n const legacyEvent = jQuery.Event(\"core_form-field-validation\");\n\n jQuery(e.target).trigger(legacyEvent, e.detail.message);\n });\n\n legacyEventsRegistered = true;\n}\n\n/**\n * Trigger an event to notify the file upload field has been changed.\n *\n * @method\n * @param {string} elementId The element which was changed\n * @returns {CustomEvent}\n * @fires uploadChanged\n */\nexport const notifyUploadChanged = elementId => dispatchEvent(\n eventTypes.uploadChanged,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n);\n\n/**\n * Trigger an event to notify the field structure has changed.\n *\n * @method\n * @param {string} elementId The element which was changed\n * @returns {CustomEvent}\n * @fires fieldStructureChanged\n */\nexport const notifyFieldStructureChanged = elementId => dispatchEvent(\n eventTypes.fieldStructureChanged,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n);\n"],"names":["changesMadeString","changesMadeCheck","e","returnValue","eventTypes","formError","formSubmittedByJavascript","formFieldValidationFailed","uploadStarted","uploadCompleted","uploadChanged","fieldStructureChanged","field","form","skipValidation","fallbackHandled","window","skipClientValidation","customEvent","message","cancelable","notifyUploadStarted","async","addEventListener","document","getElementById","elementId","bubbles","cancellable","notifyUploadCompleted","removeEventListener","triggerUploadStarted","triggerUploadCompleted","legacyEventsRegistered","use","element","Y","one","target","formElement","closest","Global","fire","M","core","globalEvents","FORM_ERROR","formid","generateID","elementid","detail","event","FORM_SUBMIT_AJAX","currentTarget","legacyEvent","jQuery","Event","trigger"],"mappings":";;;;;;;;;;;;;;;;SAmCIA,weAMEC,iBAAmBC,IACjBA,IACAA,EAAEC,YAAcH,oBAcXI,WAAa,CAQtBC,UAAW,kBAYXC,0BAA2B,kCAW3BC,0BAA2B,kCAS3BC,cAAe,0BASfC,gBAAiB,4BASjBC,cAAe,0BASfC,sBAAuB,2FAeIC,QAAS,mCAAcR,WAAWC,UAAW,GAAIO,gDAYjC,SAACC,UAAMC,uEAAwBC,wEACtED,iBACAE,OAAOC,sBAAuB,SAG5BC,aAAc,mCAChBd,WAAWE,0BACX,CACIQ,eAAAA,eACAC,gBAAAA,iBAEJF,aAGAC,iBACAE,OAAOC,sBAAuB,GAG3BC,mDAYiC,CAACN,MAAOO,WAAY,mCAC5Df,WAAWG,0BACX,CACIY,QAAAA,SAEJP,MACA,CACIQ,YAAY,UAYPC,oBAAsBC,MAAAA,YAE/BtB,wBAA0B,kBAAU,0BAA2B,UAC/DgB,OAAOO,iBAAiB,eAAgBtB,mBAEjC,mCACHG,WAAWI,cACX,GACAgB,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa,4DAaZC,sBAAwBH,YAEjCV,OAAOc,oBAAoB,eAAgB7B,mBAEpC,mCACHG,WAAWK,gBACX,GACAe,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa,gEAcZG,qBAAuBV,6EAWvBW,uBAAyBH,4FAOjB,CACjBrB,cAAe,0BACfC,gBAAiB,iCAGjBwB,wBAAyB,EACxBA,sCAICC,IAAI,QAAS,qBAAqB,KAGhCV,SAASD,iBAAiBnB,WAAWC,WAAWH,UACtCiC,QAAUC,aAAEC,IAAInC,EAAEoC,QAClBC,YAAcH,aAAEC,IAAInC,EAAEoC,OAAOE,QAAQ,sBAEzCC,OAAOC,KACLC,EAAEC,KAAKC,aAAaC,WACpB,CACIC,OAAQR,YAAYS,aACpBC,UAAWd,QAAQa,kBAM/BxB,SAASD,iBAAiBnB,WAAWE,2BAA2BJ,OACxDA,EAAEgD,OAAOnC,uBAMTb,EAAEY,iBACFE,OAAOC,sBAAuB,SAI5BJ,KAAOuB,aAAEC,IAAInC,EAAEoC,QACrBzB,KAAK6B,KACDC,EAAEC,KAAKO,MAAMC,iBACb,CACIC,cAAexC,KACfE,iBAAiB,IAIrBb,EAAEY,iBACFE,OAAOC,sBAAuB,SAM1CO,SAASD,iBAAiBnB,WAAWG,2BAA2BL,UAGtDoD,YAAcC,gBAAOC,MAAM,kDAE1BtD,EAAEoC,QAAQmB,QAAQH,YAAapD,EAAEgD,OAAO/B,YAGnDc,wBAAyB,gCAWMP,YAAa,mCAC5CtB,WAAWM,cACX,GACAc,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa,yCAYsBF,YAAa,mCACpDtB,WAAWO,sBACX,GACAa,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa"}
\ No newline at end of file
diff --git a/lib/form/amd/src/events.js b/lib/form/amd/src/events.js
index 2cbedb241e04..b5c3b4df82da 100644
--- a/lib/form/amd/src/events.js
+++ b/lib/form/amd/src/events.js
@@ -53,6 +53,7 @@ const changesMadeCheck = e => {
* @property {String} formFieldValidationFailed See {@link event:core_form/fieldValidationFailed}
* @property {String} formSubmittedByJavascript See {@link event:core_form/submittedByJavascript}
* @property {String} uploadChanged See {@link event:core_form/uploadChanged}
+ * @property {String} fieldStructureChanged See {@link event:core_form/fieldStructureChanged}
*/
export const eventTypes = {
/**
@@ -113,6 +114,15 @@ export const eventTypes = {
* @property {HTMLElement} target The form field which was changed
*/
uploadChanged: 'core_form/uploadChanged',
+
+ /**
+ * An event triggered when a form field structure has changed.
+ *
+ * @event core_form/fieldStructureChanged
+ * @type {CustomEvent}
+ * @property {HTMLElement} target The form field that has changed
+ */
+ fieldStructureChanged: 'core_form/fieldStructureChanged',
};
// These are only imported for legacy.
@@ -337,3 +347,21 @@ export const notifyUploadChanged = elementId => dispatchEvent(
cancellable: false,
}
);
+
+/**
+ * Trigger an event to notify the field structure has changed.
+ *
+ * @method
+ * @param {string} elementId The element which was changed
+ * @returns {CustomEvent}
+ * @fires fieldStructureChanged
+ */
+export const notifyFieldStructureChanged = elementId => dispatchEvent(
+ eventTypes.fieldStructureChanged,
+ {},
+ document.getElementById(elementId),
+ {
+ bubbles: true,
+ cancellable: false,
+ }
+);
diff --git a/lib/form/filepicker.php b/lib/form/filepicker.php
index e10fd46bf096..8fee6b48acaf 100644
--- a/lib/form/filepicker.php
+++ b/lib/form/filepicker.php
@@ -184,11 +184,10 @@ function toHtml() {
$html .= "";
$html .= '';
- if (!empty($options->accepted_types) && $options->accepted_types != '*') {
+ if (!empty($args->accepted_types) && $args->accepted_types != '*') {
$html .= html_writer::tag('p', get_string('filesofthesetypes', 'form'));
$util = new \core_form\filetypes_util();
- $filetypes = $options->accepted_types;
- $filetypedescriptions = $util->describe_file_types($filetypes);
+ $filetypedescriptions = $util->describe_file_types($args->accepted_types);
$html .= $OUTPUT->render_from_template('core_form/filetypes-descriptions', $filetypedescriptions);
}
diff --git a/lib/form/templates/element-group.mustache b/lib/form/templates/element-group.mustache
index 67d7866eeed0..208dd6d0d14a 100644
--- a/lib/form/templates/element-group.mustache
+++ b/lib/form/templates/element-group.mustache
@@ -7,17 +7,27 @@
{{/element.hiddenlabel}}
{{/label}}
{{$element}}
-