Compare commits
331 Commits
v4.3.0-rc2
..
v4.2.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c989335be | |||
| d4937c4527 | |||
| 62e7dc94d9 | |||
| cf40395830 | |||
| ab62e5f23f | |||
| a29056941b | |||
| 78db6582ba | |||
| b1ccbfc24d | |||
| 8c9545ca78 | |||
| 5b48a61484 | |||
| ef3eb09347 | |||
| abff2a6570 | |||
| 15afb64771 | |||
| c8631653cd | |||
| 30add0c159 | |||
| 2fbb766149 | |||
| 3fa41951f3 | |||
| 3d02f36f87 | |||
| dcd20bec34 | |||
| fec48e90ac | |||
| 1a469cda51 | |||
| f98b725610 | |||
| cc9f2527a8 | |||
| 8e5f9ca9d4 | |||
| d247ea08e9 | |||
| eab902354f | |||
| d3e4957556 | |||
| 40b68fd88f | |||
| c180b1babd | |||
| a1e281a31d | |||
| ab12596a7b | |||
| fd5585777f | |||
| 5132a27822 | |||
| 9f6fbc11dd | |||
| a801a741b9 | |||
| 685be3d41b | |||
| 0e504f73ee | |||
| 7dfcc7e3f5 | |||
| 35500db40c | |||
| cfb5b76ba7 | |||
| ff68353e39 | |||
| 0f410c087a | |||
| e160cdd8a7 | |||
| d25ad8aaf9 | |||
| c938c41de8 | |||
| 04996f2cf8 | |||
| 5481c31fe6 | |||
| 79a9167a1e | |||
| 4d035d0f80 | |||
| cd885856f3 | |||
| 5f67d77aae | |||
| d59a10108c | |||
| b4cf5c50bf | |||
| 71440dc236 | |||
| 75264720ac | |||
| 735c2c6b47 | |||
| 319d3954f8 | |||
| 0fc6e59121 | |||
| ace6e8db3d | |||
| 2970f0f433 | |||
| 4899d8c11a | |||
| 20302d4f86 | |||
| d1053fe035 | |||
| 5d361ee332 | |||
| a43b2b2998 | |||
| cf46e93304 | |||
| bb7b0f996d | |||
| 9c5e63cf17 | |||
| 5d89ce0058 | |||
| 6143ad4b1b | |||
| d54edef0f7 | |||
| 02d2e80bae | |||
| 5cf5134a12 | |||
| 5112c89929 | |||
| fab3b2ccbc | |||
| 56f75d7aea | |||
| 2f10bf1a1f | |||
| 0384f8dfa0 | |||
| e05576d74c | |||
| 01b577ee65 | |||
| 0f5a1a61f7 | |||
| b4479d7981 | |||
| 2a2badacb2 | |||
| eb0585ea72 | |||
| 7faf41dce5 | |||
| 6aa360ae83 | |||
| 804e8b62da | |||
| 1092a998ae | |||
| 027e3c6660 | |||
| 2b407d891f | |||
| 1b284001ac | |||
| b3350a0ea7 | |||
| 0ffed15ee4 | |||
| d20cf16533 | |||
| 3e13847324 | |||
| 24f646038c | |||
| 928760f865 | |||
| 9a3f097da5 | |||
| 1198d57f71 | |||
| 6b8884e13b | |||
| 7edbca66f9 | |||
| e0c8854480 | |||
| 7d5b30290f | |||
| 3e2bf77656 | |||
| 15b0cd25e6 | |||
| e99fcecdf9 | |||
| 5feb510035 | |||
| cae92e5a92 | |||
| 1342f28224 | |||
| b0b214bbf2 | |||
| 1ff32127d4 | |||
| a443a29b79 | |||
| f92c748a2d | |||
| af0f37405f | |||
| fb71a7a8c7 | |||
| b10afcdd4c | |||
| 93c35a89bb | |||
| 43fdf37a96 | |||
| b490a0ae08 | |||
| 80410a354b | |||
| b1b0c2d59b | |||
| aa7aec1088 | |||
| 7bae6c8ca6 | |||
| 7a5806d3cb | |||
| 279cc50e5c | |||
| dc4ff6a2f5 | |||
| fb343534d0 | |||
| b4935649b3 | |||
| 0d426e571a | |||
| b938b53096 | |||
| 525b69dc69 | |||
| 5630f86d81 | |||
| 30ac87781a | |||
| 2b9a9286d0 | |||
| 2e6d8b72b1 | |||
| 2724eb6041 | |||
| df8413ade0 | |||
| 414f0df046 | |||
| 29a7e00f9c | |||
| 81b9a51fb7 | |||
| 03c461ab87 | |||
| c2fbb10a52 | |||
| 4781b41631 | |||
| caf4da762c | |||
| 0ab5bf01f0 | |||
| 078782e656 | |||
| 2b6456c1d0 | |||
| a37ce627a8 | |||
| 26b885edb6 | |||
| b514f0bb1d | |||
| 12dc12c954 | |||
| ec7b3cab86 | |||
| 6808c8f3b2 | |||
| 109a0ffeb9 | |||
| 4a04cda71b | |||
| a0920d8b8d | |||
| 11bf54289f | |||
| 666708b561 | |||
| a1162e3943 | |||
| 9de9651809 | |||
| dcb3ce31ce | |||
| 8b641a1b0d | |||
| 8fa53a336e | |||
| 5a22258f42 | |||
| 92cba2c5ba | |||
| 7d8a40fe3e | |||
| 2de2d6bc30 | |||
| beb55edffc | |||
| ae8466162d | |||
| b5f98e022d | |||
| b9d21ee2ad | |||
| 04fb9beb20 | |||
| 3be559b763 | |||
| 88a1d4d4c2 | |||
| e0045688b3 | |||
| c645df564a | |||
| 8bac8a2da7 | |||
| 2e339446d8 | |||
| 1c9379ab09 | |||
| 24ad6848aa | |||
| da43ea4ef7 | |||
| f49f24c516 | |||
| 473cfc369d | |||
| 0ba9466281 | |||
| 9e6f6c0e7e | |||
| b87a75110b | |||
| 52bcdf9e06 | |||
| f113d4c116 | |||
| 16bac432fd | |||
| 4e28613a16 | |||
| 1df40c823e | |||
| 5dfec00bb1 | |||
| c00c6dd4cf | |||
| 0f687a9028 | |||
| 1d2b0ade40 | |||
| a5f2c1d591 | |||
| 5e59ad2b6e | |||
| 441003231f | |||
| 54c8336373 | |||
| e3ac233307 | |||
| 4d263b0505 | |||
| 25953f9c7f | |||
| b112cee58c | |||
| bc7dacecb6 | |||
| d1fcfd1de2 | |||
| 32bc50a135 | |||
| 02e893a575 | |||
| 59c75c928d | |||
| c2a74815c0 | |||
| 9ac38f5db6 | |||
| 04b35cb3db | |||
| c6cc0449ed | |||
| 30f1f0778f | |||
| f9edf5c1be | |||
| c4f7a44824 | |||
| 26dbb8466a | |||
| 2fb84af337 | |||
| 717c74a448 | |||
| 4a2e621012 | |||
| 732dc4f334 | |||
| c348119685 | |||
| ced8835b5f | |||
| a5cf13cd90 | |||
| 10f9d0d51a | |||
| 9bdfec812d | |||
| 78d90e3c16 | |||
| d5ec3594cc | |||
| 5303c032bb | |||
| b2cca9ef62 | |||
| 87736d9a0b | |||
| b1496fa5df | |||
| 411dc66fd9 | |||
| c58d3b4759 | |||
| 39a930f762 | |||
| 3493d9ebc3 | |||
| eff51c6001 | |||
| 7365bc38b2 | |||
| 856803faf8 | |||
| 97d935b337 | |||
| f46e5fc229 | |||
| 8a6c536b29 | |||
| 84da51dafd | |||
| 98448477d9 | |||
| 62076a191e | |||
| b1a7ae63c3 | |||
| 929ad63114 | |||
| 29a21ee986 | |||
| c721cc6803 | |||
| 2ccc6a2346 | |||
| cd3643a149 | |||
| 2138619b01 | |||
| 97f6672420 | |||
| f6afe82978 | |||
| 16f91dfdb3 | |||
| da46551bea | |||
| 861ce57a8a | |||
| 048070e25f | |||
| 223b1afabf | |||
| 92a57c95be | |||
| 680644b593 | |||
| bdaed5ec3c | |||
| 812219fcb2 | |||
| 514865575c | |||
| 1b1c1a56b1 | |||
| 33f62c3309 | |||
| 0f66c8fe5c | |||
| a56ca931aa | |||
| 453ea97395 | |||
| 4e9be8c131 | |||
| a7055da32d | |||
| bd85500e2a | |||
| e0e94dbf84 | |||
| 9de24c27c6 | |||
| 89215b79fb | |||
| 4065904ad1 | |||
| 3862ec015d | |||
| c516a6fc14 | |||
| fb14c67dec | |||
| b297347f12 | |||
| b89351f084 | |||
| b78a8983ed | |||
| 84ddb8c655 | |||
| cc3828c85a | |||
| 7af8bddad7 | |||
| 3bdfc594b6 | |||
| c6ff4c551e | |||
| b6531bf613 | |||
| 7c4fc1725f | |||
| 4f625c1e2e | |||
| 99e38b7118 | |||
| 5650cab0d6 | |||
| 4b23b98e16 | |||
| c7595a7169 | |||
| b97ffab51a | |||
| f1633ba0f8 | |||
| 3f4b46b16a | |||
| 32df1530ff | |||
| 20e1d18c29 | |||
| 01fd68f06d | |||
| a8a3855c6d | |||
| 950aa78611 | |||
| b2e36b6baa | |||
| 85662b721b | |||
| eb6c618fd4 | |||
| d43dc80d65 | |||
| 8e1583455e | |||
| 4bfce15818 | |||
| 6b8aeb5c90 | |||
| d9f71f0666 | |||
| 9e0d12e5ae | |||
| 86fd45f0de | |||
| ffd32bacba | |||
| 3ee04ecf78 | |||
| c675170c4e | |||
| 0c74bbfa06 | |||
| 4f7ccd0432 | |||
| 4806324231 | |||
| 9c779fefc7 | |||
| b82cc59782 | |||
| e38a933fa2 | |||
| 9ef5ed8527 | |||
| f1afcf6616 | |||
| 0a05336551 | |||
| a9c5734f04 | |||
| 1e81424bdd | |||
| 4aaaaa5f57 | |||
| 963b56cf7e | |||
| f3368a55b5 | |||
| 37564d61d5 | |||
| 94a87bc47e | |||
| e6615e587f |
@@ -1,12 +1,8 @@
|
||||
{
|
||||
'plugins': [
|
||||
'@babel',
|
||||
'babel',
|
||||
'promise',
|
||||
'jsdoc'
|
||||
],
|
||||
'extends': [
|
||||
'eslint:recommended',
|
||||
'plugin:promise/recommended'
|
||||
'jsdoc',
|
||||
],
|
||||
'env': {
|
||||
'browser': true,
|
||||
@@ -20,19 +16,42 @@
|
||||
'M': true,
|
||||
'Y': true
|
||||
},
|
||||
// Warn about unused eslint-disable statements.
|
||||
'reportUnusedDisableDirectives': true,
|
||||
'rules': {
|
||||
// See http://eslint.org/docs/rules/ for all rules and explanations of all
|
||||
// rules.
|
||||
|
||||
// === Possible Errors ===
|
||||
'comma-dangle': 'off',
|
||||
'no-compare-neg-zero': 'error',
|
||||
'no-cond-assign': 'error',
|
||||
'no-console': 'error',
|
||||
'no-constant-condition': 'error',
|
||||
'no-control-regex': 'error',
|
||||
'no-debugger': 'error',
|
||||
'no-dupe-args': 'error',
|
||||
'no-dupe-keys': 'error',
|
||||
'no-duplicate-case': 'error',
|
||||
'no-empty': 'warn',
|
||||
'no-empty-character-class': 'error',
|
||||
'no-ex-assign': 'error',
|
||||
'no-extra-boolean-cast': 'error',
|
||||
'no-extra-parens': 'off',
|
||||
'no-extra-semi': 'error',
|
||||
'no-func-assign': 'error',
|
||||
'no-inner-declarations': 'error',
|
||||
'no-invalid-regexp': 'error',
|
||||
'no-irregular-whitespace': 'error',
|
||||
'no-obj-calls': 'error',
|
||||
'no-prototype-builtins': 'off',
|
||||
'no-regex-spaces': 'error',
|
||||
'no-sparse-arrays': 'error',
|
||||
'no-unexpected-multiline': 'error',
|
||||
'no-unreachable': 'warn',
|
||||
'no-unsafe-finally': 'error',
|
||||
'no-unsafe-negation': 'error',
|
||||
'use-isnan': 'error',
|
||||
'valid-jsdoc': ['warn', { 'requireReturn': false, 'requireParamDescription': false, 'requireReturnDescription': false }],
|
||||
'valid-typeof': 'error',
|
||||
|
||||
// === Best Practices ===
|
||||
// (these mostly match our jshint config)
|
||||
@@ -44,12 +63,15 @@
|
||||
'dot-notation': 'warn',
|
||||
'no-alert': 'warn',
|
||||
'no-caller': 'error',
|
||||
'no-case-declarations': 'error',
|
||||
'no-div-regex': 'error',
|
||||
'no-empty-pattern': 'error',
|
||||
'no-empty-function': 'warn',
|
||||
'no-eq-null': 'error',
|
||||
'no-eval': 'error',
|
||||
'no-extend-native': 'error',
|
||||
'no-extra-bind': 'warn',
|
||||
'no-fallthrough': 'error',
|
||||
'no-floating-decimal': 'warn',
|
||||
'no-global-assign': 'warn',
|
||||
'no-implied-eval': 'error',
|
||||
@@ -61,22 +83,28 @@
|
||||
'no-multi-str': 'error',
|
||||
'no-new-func': 'error',
|
||||
'no-new-wrappers': 'error',
|
||||
'no-octal': 'error',
|
||||
'no-octal-escape': 'error',
|
||||
'no-proto': 'error',
|
||||
'no-redeclare': 'warn',
|
||||
'no-restricted-globals': ['error', { 'name': 'Notification' }],
|
||||
'no-return-assign': 'error',
|
||||
'no-script-url': 'error',
|
||||
'no-self-assign': 'error',
|
||||
'no-self-compare': 'error',
|
||||
'no-sequences': 'warn',
|
||||
'no-throw-literal': 'warn',
|
||||
'no-unmodified-loop-condition': 'error',
|
||||
'no-unused-expressions': 'error',
|
||||
'no-unused-labels': 'error',
|
||||
'no-useless-call': 'warn',
|
||||
'no-useless-escape': 'warn',
|
||||
'no-with': 'error',
|
||||
'wrap-iife': ['error', 'any'],
|
||||
|
||||
// === Variables ===
|
||||
'no-delete-var': 'error',
|
||||
'no-undef': 'error',
|
||||
'no-undef-init': 'error',
|
||||
'no-unused-vars': ['error', { 'caughtErrors': 'none' }],
|
||||
|
||||
@@ -109,6 +137,8 @@
|
||||
'max-statements-per-line': ['warn', { max: 2 }],
|
||||
'new-cap': ['warn', { 'properties': false }],
|
||||
'new-parens': 'warn',
|
||||
'newline-after-var': 'off',
|
||||
'newline-before-return': 'off',
|
||||
'newline-per-chained-call': 'off',
|
||||
'no-array-constructor': 'off',
|
||||
'no-bitwise': 'error',
|
||||
@@ -116,6 +146,7 @@
|
||||
'no-inline-comments': 'off',
|
||||
'no-lonely-if': 'off',
|
||||
'no-mixed-operators': 'off',
|
||||
'no-mixed-spaces-and-tabs': 'error',
|
||||
'no-multiple-empty-lines': 'warn',
|
||||
'no-negated-condition': 'off',
|
||||
'no-nested-ternary': 'warn',
|
||||
@@ -137,6 +168,7 @@
|
||||
'padded-blocks': 'off',
|
||||
'quote-props': ['warn', 'as-needed', {'unnecessary': false, 'keywords': true, 'numbers': true}],
|
||||
'quotes': 'off',
|
||||
'require-jsdoc': 'warn',
|
||||
'semi': 'error',
|
||||
'semi-spacing': ['warn', {'before': false, 'after': true}],
|
||||
'sort-vars': 'off',
|
||||
@@ -149,19 +181,21 @@
|
||||
'unicode-bom': 'error',
|
||||
'wrap-regex': 'off',
|
||||
|
||||
// === Promises (override plugin:promise/recommended) ===
|
||||
// === Promises ===
|
||||
'promise/always-return': 'warn',
|
||||
'promise/no-return-wrap': 'warn',
|
||||
'promise/param-names': 'warn',
|
||||
'promise/catch-or-return': ['warn', {terminationMethod: ['catch', 'fail', 'always'], allowFinally: true}],
|
||||
'promise/catch-or-return': ['warn', {terminationMethod: ['catch', 'fail']}],
|
||||
'promise/no-native': 'warn',
|
||||
'promise/no-promise-in-callback': 'warn',
|
||||
'promise/no-callback-in-promise': 'warn',
|
||||
'promise/avoid-new': 'warn',
|
||||
|
||||
// === Deprecations ===
|
||||
"no-restricted-properties": ['warn', {
|
||||
'object': 'M',
|
||||
'property': 'str',
|
||||
'message': 'Use "core/str" module or M.util.get_string()'
|
||||
'message': 'Use AMD module "core/str" or M.util.get_string()'
|
||||
}],
|
||||
},
|
||||
overrides: [
|
||||
@@ -201,6 +235,7 @@
|
||||
parser: '@babel/eslint-parser',
|
||||
// Check AMD with some slightly stricter rules.
|
||||
rules: {
|
||||
'no-unused-vars': 'error',
|
||||
'no-implicit-globals': 'error',
|
||||
// Disable all of the rules that have babel versions.
|
||||
'new-cap': 'off',
|
||||
@@ -212,37 +247,65 @@
|
||||
'semi': 'off',
|
||||
'no-unused-expressions': 'off',
|
||||
// Enable all of the babel version of these rules.
|
||||
'@babel/new-cap': ['warn', { 'properties': false }],
|
||||
'babel/new-cap': ['warn', { 'properties': false }],
|
||||
// Not using this rule for the time being because it isn't
|
||||
// compatible with jQuery and ES6.
|
||||
'@babel/no-invalid-this': 'off',
|
||||
'@babel/object-curly-spacing': 'warn',
|
||||
'@babel/semi': 'error',
|
||||
'@babel/no-unused-expressions': 'error',
|
||||
'babel/no-invalid-this': 'off',
|
||||
'babel/object-curly-spacing': 'warn',
|
||||
// This is off in the original style int.
|
||||
'babel/quotes': 'off',
|
||||
'babel/semi': 'error',
|
||||
'babel/no-unused-expressions': 'error',
|
||||
// === Promises ===
|
||||
// We have Promise now that we're using ES6.
|
||||
'promise/no-native': 'off',
|
||||
'promise/avoid-new': 'off',
|
||||
|
||||
// === JSDocs ===
|
||||
'jsdoc/check-access': 'error',
|
||||
'jsdoc/check-alignment': 1, // Recommended.
|
||||
'jsdoc/check-param-names': 'error',
|
||||
'jsdoc/check-property-names': 'error',
|
||||
'jsdoc/empty-tags': 'error',
|
||||
'jsdoc/implements-on-classes': 'error',
|
||||
'jsdoc/multiline-blocks': 'error',
|
||||
'jsdoc/require-jsdoc': 'error',
|
||||
'jsdoc/require-param': 'error',
|
||||
'jsdoc/require-param-name': 'error',
|
||||
'jsdoc/require-param-type': 'error',
|
||||
'jsdoc/require-property': 'error',
|
||||
'jsdoc/require-property-name': 'error',
|
||||
'jsdoc/require-property-type': 'error'
|
||||
"jsdoc/check-access": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/check-alignment": 1, // Recommended.
|
||||
"jsdoc/check-param-names": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/check-property-names": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/empty-tags": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/implements-on-classes": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/multiline-blocks": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-jsdoc": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-param": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-param-name": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-param-type": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-property": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-property-name": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-property-type": [
|
||||
'error',
|
||||
],
|
||||
},
|
||||
parserOptions: {
|
||||
'sourceType': 'module',
|
||||
'requireConfigFile': false
|
||||
'requireConfigFile': false,
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -9,7 +9,7 @@ on:
|
||||
- v[0-9]+.[0-9]+.[0-9]+*
|
||||
|
||||
env:
|
||||
php: 8.2
|
||||
php: 8.1
|
||||
|
||||
jobs:
|
||||
Grunt:
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
db: mysqli
|
||||
# PostgreSQL builds always run with the highest PHP supported version.
|
||||
- os: ubuntu-22.04
|
||||
php: 8.2
|
||||
php: 8.1
|
||||
db: pgsql
|
||||
|
||||
steps:
|
||||
|
||||
@@ -3,7 +3,7 @@ name: Windows Testing
|
||||
on:
|
||||
workflow_dispatch
|
||||
env:
|
||||
php: 8.2
|
||||
php: 8.1
|
||||
|
||||
jobs:
|
||||
Grunt:
|
||||
@@ -46,13 +46,13 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-latest
|
||||
php: 8.2
|
||||
php: 8.1
|
||||
# Ideally we should use mysql/mariadb, but they are 4x slower without tweaks and configuration
|
||||
# so let's run only postgres (1.5h vs 6h) only, If some day we want to improve the mysql runs,
|
||||
# this is the place to enable them.
|
||||
# db: mysqli
|
||||
db: pgsql
|
||||
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium, zip
|
||||
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium
|
||||
- os: windows-latest
|
||||
php: 8.0
|
||||
db: pgsql
|
||||
|
||||
@@ -16,4 +16,4 @@ Moodle - the world's open source learning platform
|
||||
This generated documentation includes API documentation for JavaScript written in the AMD and ES2015 module formats within Moodle.
|
||||
|
||||
## Related information
|
||||
See [https://moodledev.io](https://moodledev.io) for other related Developer Documentation.
|
||||
See [https://docs.moodle.org/dev](https://docs.moodle.org/dev) for other related Developer Documentation.
|
||||
|
||||
@@ -114,7 +114,7 @@ module.exports = {
|
||||
],
|
||||
"menu": {
|
||||
"Developer Docs": {
|
||||
href: "https://moodledev.io",
|
||||
href: "https://docs.moodle.org/dev",
|
||||
target: "_blank",
|
||||
"class": "menu-item",
|
||||
id: "devdocs"
|
||||
|
||||
@@ -151,7 +151,11 @@ module.exports = grunt => {
|
||||
//
|
||||
// It also adds the Moodle plugin name to the AMD module definition
|
||||
// so that it can be imported as expected in other modules.
|
||||
path.resolve('.grunt/babel-plugin-add-module-to-define.js')
|
||||
path.resolve('.grunt/babel-plugin-add-module-to-define.js'),
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
'@babel/plugin-syntax-import-meta',
|
||||
['@babel/plugin-proposal-class-properties', {'loose': false}],
|
||||
'@babel/plugin-proposal-json-strings'
|
||||
],
|
||||
presets: [
|
||||
['@babel/preset-env', {
|
||||
|
||||
@@ -6,7 +6,7 @@ of developers, designers, teachers, testers, translators and other users. We
|
||||
work in universities, schools, companies and other places. You are very welcome
|
||||
to join us and contribute to the project.
|
||||
|
||||
See <https://moodledev.io/general/community/contribute> for the many ways you
|
||||
See <https://docs.moodle.org/dev/Contributing_to_Moodle> for the many ways you
|
||||
can help, not only with coding.
|
||||
|
||||
Moodle is open to community contributions to core, though all code must go
|
||||
@@ -35,7 +35,7 @@ submitted patches has evolved.
|
||||
* New features are developed on the master branch. Bug fixes are also
|
||||
backported to currently supported maintenance (stable) branches.
|
||||
|
||||
For further details, see <https://moodledev.io/general/development/process>.
|
||||
For further details, see <https://docs.moodle.org/dev/Process>.
|
||||
|
||||
Moodle plugins
|
||||
--------------
|
||||
@@ -53,4 +53,4 @@ be easily installed and updated via the Moodle administration interface.
|
||||
the plugins directory. We do not pull from your code repository; you must do
|
||||
it explicitly.
|
||||
|
||||
For further details, see <https://moodledev.io/general/community/plugincontribution>.
|
||||
For further details, see <https://docs.moodle.org/dev/Plugin_contribution>.
|
||||
|
||||
@@ -20,7 +20,7 @@ Moodle is widely used around the world by universities, schools, companies and
|
||||
all manner of organisations and individuals.
|
||||
|
||||
Moodle is provided freely as open source software, under the GNU General Public
|
||||
License <https://moodledev.io/general/license>.
|
||||
License <https://docs.moodle.org/dev/License>.
|
||||
|
||||
Moodle is written in PHP and JavaScript and uses an SQL database for storing
|
||||
the data.
|
||||
|
||||
@@ -131,7 +131,8 @@ if ($savebutton) {
|
||||
$outputhtml .= html_writer::end_tag('div');
|
||||
}
|
||||
|
||||
$PAGE->set_title(implode(moodle_page::TITLE_SEPARATOR, $settingspage->visiblepath));
|
||||
$visiblepathtosection = array_reverse($settingspage->visiblepath);
|
||||
$PAGE->set_title("$SITE->shortname: " . implode(": ",$visiblepathtosection));
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
if ($buttons) {
|
||||
$PAGE->set_button($buttons);
|
||||
|
||||
@@ -78,17 +78,6 @@ class task_logs extends datasource {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column sorting that will be added to the report upon creation
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public function get_default_column_sorting(): array {
|
||||
return [
|
||||
'task_log:starttime' => SORT_DESC,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filters that will be added to the report upon creation
|
||||
*
|
||||
|
||||
@@ -35,29 +35,28 @@ class block_management_table extends \core_admin\table\plugin_management_table {
|
||||
/** @var stdClass[] A list of basic block data */
|
||||
protected array $blockdata;
|
||||
|
||||
/** @var array<string,int> A list of course counts */
|
||||
protected array $courseblocks;
|
||||
|
||||
public function __construct() {
|
||||
global $DB;
|
||||
parent::__construct();
|
||||
$this->undeletableblocktypes = \block_manager::get_undeletable_block_types();
|
||||
|
||||
$sql = 'SELECT b.name,
|
||||
b.id,
|
||||
COUNT(DISTINCT binst.id) as totalcount
|
||||
FROM {block} b
|
||||
LEFT JOIN {block_instances} binst ON binst.blockname = b.name
|
||||
GROUP BY b.id,
|
||||
b.name
|
||||
ORDER BY b.name ASC';
|
||||
$this->blockdata = $DB->get_records_sql($sql);
|
||||
$sql = <<<EOF
|
||||
SELECT
|
||||
b.name,
|
||||
b.id,
|
||||
b.name,
|
||||
COUNT(DISTINCT binst.id) as totalcount,
|
||||
COUNT(DISTINCT bcinst.id) as courseviewcount
|
||||
FROM {block} b
|
||||
LEFT JOIN {block_instances} binst ON binst.blockname = b.name
|
||||
LEFT JOIN {block_instances} bcinst ON
|
||||
bcinst.blockname = b.name AND
|
||||
bcinst.pagetypepattern = 'course-view-*'
|
||||
GROUP BY b.id, b.name, b.visible, binst.blockname, bcinst.blockname
|
||||
ORDER BY b.name ASC
|
||||
EOF;
|
||||
|
||||
$sql = "SELECT blockname
|
||||
FROM {block_instances}
|
||||
WHERE pagetypepattern = 'course-view-*'
|
||||
GROUP BY blockname";
|
||||
$this->courseblocks = $DB->get_records_sql($sql);
|
||||
$this->blockdata = $DB->get_records_sql($sql);
|
||||
}
|
||||
|
||||
protected function get_plugintype(): string {
|
||||
@@ -103,10 +102,11 @@ class block_management_table extends \core_admin\table\plugin_management_table {
|
||||
*/
|
||||
protected function col_instances(stdClass $row): string {
|
||||
$blockdata = $this->blockdata[$row->plugininfo->name];
|
||||
if (array_key_exists($blockdata->name, $this->courseblocks)) {
|
||||
if ($blockdata->courseviewcount > 0) {
|
||||
return html_writer::link(
|
||||
new moodle_url('/course/search.php', [
|
||||
'blocklist' => $blockdata->id,
|
||||
'blocklist' => $row->plugininfo->name,
|
||||
'sesskey' => sesskey(),
|
||||
]),
|
||||
$blockdata->totalcount,
|
||||
);
|
||||
|
||||
@@ -1,285 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core_admin\table;
|
||||
|
||||
use core_plugin_manager;
|
||||
use flexible_table;
|
||||
use html_writer;
|
||||
use stdClass;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once("{$CFG->libdir}/tablelib.php");
|
||||
|
||||
/**
|
||||
* Plugin Management table.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class hook_list_table extends flexible_table {
|
||||
|
||||
/** @var \core\plugininfo\base[] The plugin list */
|
||||
protected array $plugins = [];
|
||||
|
||||
/** @var int The number of enabled plugins of this type */
|
||||
protected int $enabledplugincount = 0;
|
||||
|
||||
/** @var core_plugin_manager */
|
||||
protected core_plugin_manager $pluginmanager;
|
||||
|
||||
/** @var string The plugininfo class for this plugintype */
|
||||
protected string $plugininfoclass;
|
||||
|
||||
/** @var stdClass[] The list of emitted hooks with metadata */
|
||||
protected array $emitters;
|
||||
|
||||
public function __construct() {
|
||||
global $CFG;
|
||||
|
||||
$this->define_baseurl('/admin/hooks.php');
|
||||
parent::__construct('core_admin-hook_list_table');
|
||||
|
||||
// Add emitted hooks.
|
||||
$this->emitters = \core\hook\manager::discover_known_hooks();
|
||||
|
||||
$this->setup_column_configuration();
|
||||
$this->setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the column configuration for this table.
|
||||
*/
|
||||
protected function setup_column_configuration(): void {
|
||||
$columnlist = [
|
||||
'details' => get_string('hookname', 'core_admin'),
|
||||
'callbacks' => get_string('hookcallbacks', 'core_admin'),
|
||||
'deprecates' => get_string('hookdeprecates', 'core_admin'),
|
||||
];
|
||||
$this->define_columns(array_keys($columnlist));
|
||||
$this->define_headers(array_values($columnlist));
|
||||
|
||||
$columnswithhelp = [
|
||||
'callbacks' => new \help_icon('hookcallbacks', 'admin'),
|
||||
];
|
||||
$columnhelp = array_map(function (string $column) use ($columnswithhelp): ?\renderable {
|
||||
if (array_key_exists($column, $columnswithhelp)) {
|
||||
return $columnswithhelp[$column];
|
||||
}
|
||||
|
||||
return null;
|
||||
}, array_keys($columnlist));
|
||||
$this->define_help_for_headers($columnhelp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the table.
|
||||
*/
|
||||
public function out(): void {
|
||||
// All hook consumers referenced from the db/hooks.php files.
|
||||
$hookmanager = \core\hook\manager::get_instance();
|
||||
$allhooks = (array)$hookmanager->get_all_callbacks();
|
||||
|
||||
// Add any unused hooks.
|
||||
foreach (array_keys($this->emitters) as $classname) {
|
||||
if (isset($allhooks[$classname])) {
|
||||
continue;
|
||||
}
|
||||
$allhooks[$classname] = [];
|
||||
}
|
||||
|
||||
// Order rows by hook name, putting core first.
|
||||
\core_collator::ksort($allhooks);
|
||||
$corehooks = [];
|
||||
foreach ($allhooks as $classname => $consumers) {
|
||||
if (str_starts_with($classname, 'core\\')) {
|
||||
$corehooks[$classname] = $consumers;
|
||||
unset($allhooks[$classname]);
|
||||
}
|
||||
}
|
||||
$allhooks = array_merge($corehooks, $allhooks);
|
||||
|
||||
foreach ($allhooks as $classname => $consumers) {
|
||||
$this->add_data_keyed(
|
||||
$this->format_row((object) [
|
||||
'classname' => $classname,
|
||||
'callbacks' => $consumers,
|
||||
]),
|
||||
$this->get_row_class($classname),
|
||||
);
|
||||
}
|
||||
|
||||
$this->finish_output(false);
|
||||
}
|
||||
|
||||
protected function col_details(stdClass $row): string {
|
||||
return $row->classname .
|
||||
$this->get_description($row) .
|
||||
html_writer::div($this->get_tags_for_row($row));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the name column content.
|
||||
*
|
||||
* @param stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
protected function get_description(stdClass $row): string {
|
||||
if (!array_key_exists($row->classname, $this->emitters)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return html_writer::tag(
|
||||
'small',
|
||||
clean_text(markdown_to_html($this->emitters[$row->classname]['description']), FORMAT_HTML),
|
||||
);
|
||||
}
|
||||
|
||||
protected function col_deprecates(stdClass $row): string {
|
||||
if (!class_exists($row->classname)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$rc = new \ReflectionClass($row->classname);
|
||||
if (!$rc->implementsInterface(\core\hook\deprecated_callback_replacement::class)) {
|
||||
return '';
|
||||
}
|
||||
$deprecates = call_user_func([$row->classname, 'get_deprecated_plugin_callbacks']);
|
||||
if (count($deprecates) === 0) {
|
||||
return '';
|
||||
}
|
||||
$content = html_writer::start_tag('ul');
|
||||
|
||||
foreach ($deprecates as $deprecatedmethod) {
|
||||
$content .= html_writer::tag('li', $deprecatedmethod);
|
||||
}
|
||||
$content .= html_writer::end_tag('ul');
|
||||
return $content;
|
||||
}
|
||||
|
||||
protected function col_callbacks(stdClass $row): string {
|
||||
global $CFG;
|
||||
|
||||
$hookclass = $row->classname;
|
||||
$cbinfo = [];
|
||||
foreach ($row->callbacks as $definition) {
|
||||
$iscallable = is_callable($definition['callback'], false, $callbackname);
|
||||
$isoverridden = isset($CFG->hooks_callback_overrides[$hookclass][$definition['callback']]);
|
||||
$info = "{$callbackname} ({$definition['priority']})";
|
||||
if (!$iscallable) {
|
||||
$info .= ' ';
|
||||
$info .= $this->get_tag(
|
||||
get_string('error'),
|
||||
'danger',
|
||||
get_string('hookcallbacknotcallable', 'core_admin', $callbackname),
|
||||
);
|
||||
}
|
||||
if ($isoverridden) {
|
||||
// The lang string meaning should be close enough here.
|
||||
$info .= $this->get_tag(
|
||||
get_string('hookconfigoverride', 'core_admin'),
|
||||
'warning',
|
||||
get_string('hookconfigoverride_help', 'core_admin'),
|
||||
);
|
||||
}
|
||||
|
||||
$cbinfo[] = $info;
|
||||
}
|
||||
|
||||
if ($cbinfo) {
|
||||
$output = html_writer::start_tag('ol');
|
||||
foreach ($cbinfo as $callback) {
|
||||
$class = '';
|
||||
if ($definition['disabled']) {
|
||||
$class = 'dimmed_text';
|
||||
}
|
||||
$output .= html_writer::tag('li', $callback, ['class' => $class]);
|
||||
}
|
||||
$output .= html_writer::end_tag('ol');
|
||||
return $output;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML to display the badge with tooltip.
|
||||
*
|
||||
* @param string $tag The main text to display
|
||||
* @param null|string $type The pill type
|
||||
* @param null|string $tooltip The content of the tooltip
|
||||
* @return string
|
||||
*/
|
||||
protected function get_tag(
|
||||
string $tag,
|
||||
?string $type = null,
|
||||
?string $tooltip = null,
|
||||
): string {
|
||||
$attributes = [];
|
||||
|
||||
if ($type === null) {
|
||||
$type = 'info';
|
||||
}
|
||||
|
||||
if ($tooltip) {
|
||||
$attributes['data-toggle'] = 'tooltip';
|
||||
$attributes['title'] = $tooltip;
|
||||
}
|
||||
return html_writer::span($tag, "badge badge-{$type}", $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the code to display a set of tags for this table row.
|
||||
*
|
||||
* @param stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
protected function get_tags_for_row(stdClass $row): string {
|
||||
if (!array_key_exists($row->classname, $this->emitters)) {
|
||||
// This hook has been defined in the db/hooks.php file
|
||||
// but does not refer to a hook in this version of Moodle.
|
||||
return $this->get_tag(
|
||||
get_string('hookunknown', 'core_admin'),
|
||||
'warning',
|
||||
get_string('hookunknown_desc', 'core_admin'),
|
||||
);
|
||||
}
|
||||
|
||||
if (!class_exists($row->classname)) {
|
||||
// This hook has been defined in a hook discovery agent, but the class it refers to could not be found.
|
||||
return $this->get_tag(
|
||||
get_string('hookclassmissing', 'core_admin'),
|
||||
'warning',
|
||||
get_string('hookclassmissing_desc', 'core_admin'),
|
||||
);
|
||||
}
|
||||
|
||||
$tags = $this->emitters[$row->classname]['tags'] ?? [];
|
||||
$taglist = array_map(function($tag): string {
|
||||
if (is_array($tag)) {
|
||||
return $this->get_tag(...$tag);
|
||||
}
|
||||
return $this->get_tag($tag, 'badge badge-info');
|
||||
}, $tags);
|
||||
|
||||
return implode("\n", $taglist);
|
||||
}
|
||||
|
||||
protected function get_row_class(string $classname): string {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,8 @@ if ($unrecognized) {
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
// TODO: MDL-71421 - Remove the openssl alternative once sodium becomes a requirement in Moodle 4.2.
|
||||
|
||||
if ($options['help']) {
|
||||
echo "Generate secure key
|
||||
|
||||
@@ -52,7 +54,9 @@ may be manually installed on multiple servers.
|
||||
|
||||
Options:
|
||||
-h, --help Print out this help
|
||||
--method <method> Generate key for specified encryption method instead of default (sodium)
|
||||
--method <method> Generate key for specified encryption method instead of default.
|
||||
* sodium
|
||||
* openssl-aes-256-ctr
|
||||
|
||||
Example:
|
||||
php admin/cli/generate_key.php
|
||||
|
||||
@@ -57,7 +57,6 @@ Options:
|
||||
--fullname=STRING Name of the site
|
||||
--shortname=STRING Name of the site
|
||||
--summary=STRING The summary to be displayed on the front page
|
||||
--supportemail=STRING Email address for support and help.
|
||||
-h, --help Print out this help
|
||||
|
||||
Example:
|
||||
@@ -99,7 +98,6 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'fullname' => '',
|
||||
'shortname' => '',
|
||||
'summary' => '',
|
||||
'supportemail' => '',
|
||||
'agree-license' => false,
|
||||
'help' => false
|
||||
),
|
||||
@@ -138,15 +136,6 @@ if (!empty($options['adminemail']) && !validate_email($options['adminemail'])) {
|
||||
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
|
||||
}
|
||||
|
||||
// Validate that the supportemail provided was an e-mail address.
|
||||
if (!empty($options['supportemail']) && !validate_email($options['supportemail'])) {
|
||||
$a = (object) [
|
||||
'option' => 'supportemail',
|
||||
'value' => $options['supportemail']
|
||||
];
|
||||
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
|
||||
}
|
||||
|
||||
$options['lang'] = clean_param($options['lang'], PARAM_SAFEDIR);
|
||||
if (!file_exists($CFG->dirroot.'/install/lang/'.$options['lang'])) {
|
||||
$options['lang'] = 'en';
|
||||
|
||||
@@ -36,8 +36,6 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'showsql' => false,
|
||||
'showdebugging' => false,
|
||||
'force' => false,
|
||||
'disable' => false,
|
||||
'enable' => false,
|
||||
], [
|
||||
'h' => 'help',
|
||||
'f' => 'force',
|
||||
@@ -49,15 +47,11 @@ if ($unrecognized) {
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
$commands = ['list', 'execute', 'disable', 'enable'];
|
||||
$hascommand = count(array_filter($commands, fn($command) => $options[$command])) > 0;
|
||||
if ($options['help'] || !$hascommand) {
|
||||
if ($options['help'] or (!$options['list'] and !$options['execute'])) {
|
||||
$help =
|
||||
"Scheduled cron tasks.
|
||||
|
||||
Options:
|
||||
--disable=\\some\\task Disable scheduled task
|
||||
--enable=\\some\\task Enable scheduled task
|
||||
--execute=\\some\\task Execute scheduled task manually
|
||||
--list List all scheduled tasks
|
||||
--showsql Show sql queries before they are executed
|
||||
@@ -125,43 +119,17 @@ if ($options['list']) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (moodle_needs_upgrading()) {
|
||||
mtrace("Moodle upgrade pending, cannot manage tasks.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ($disable = $options['disable']) {
|
||||
if (!$task = \core\task\manager::get_scheduled_task($disable)) {
|
||||
mtrace("Task '$disable' not found");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
$task->disable();
|
||||
mtrace("Disabled '$disable'");
|
||||
} catch (Exception $e) {
|
||||
mtrace("$e->getMessage()");
|
||||
exit(1);
|
||||
}
|
||||
} else if ($enable = $options['enable']) {
|
||||
if (!$task = \core\task\manager::get_scheduled_task($enable)) {
|
||||
mtrace("Task '$enable' not found");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
$task->enable();
|
||||
mtrace("Enabled '$enable'");
|
||||
} catch (Exception $e) {
|
||||
mtrace("$e->getMessage()");
|
||||
exit(1);
|
||||
}
|
||||
} else if ($execute = $options['execute']) {
|
||||
if ($execute = $options['execute']) {
|
||||
if (!$task = \core\task\manager::get_scheduled_task($execute)) {
|
||||
mtrace("Task '$execute' not found");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (moodle_needs_upgrading()) {
|
||||
mtrace("Moodle upgrade pending, cannot execute tasks.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!get_config('core', 'cron_enabled') && !$options['force']) {
|
||||
mtrace('Cron is disabled. Use --force to override.');
|
||||
exit(1);
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Communication and its plugins settings.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage communication
|
||||
* @copyright 2023 Huong Nguyen <huongnv13@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once('../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
$action = required_param('action', PARAM_ALPHANUMEXT);
|
||||
$name = required_param('name', PARAM_PLUGIN);
|
||||
|
||||
$syscontext = context_system::instance();
|
||||
$PAGE->set_url('/admin/communication.php');
|
||||
$PAGE->set_context($syscontext);
|
||||
|
||||
require_admin();
|
||||
require_sesskey();
|
||||
|
||||
$return = new moodle_url('/admin/settings.php', ['section' => 'managecommunicationproviders']);
|
||||
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('communication');
|
||||
$sortorder = array_flip(array_keys($plugins));
|
||||
|
||||
if (!isset($plugins[$name])) {
|
||||
throw new moodle_exception('communicationprovidernotfound', 'core_communication', $return, $name);
|
||||
}
|
||||
|
||||
$plugintypename = $plugins[$name]->type . '_' . $plugins[$name]->name;
|
||||
|
||||
switch ($action) {
|
||||
case 'disable':
|
||||
if ($plugins[$name]->is_enabled()) {
|
||||
$class = core_plugin_manager::resolve_plugininfo_class('communication');
|
||||
$class::enable_plugin($name, false);
|
||||
}
|
||||
break;
|
||||
case 'enable':
|
||||
if (!$plugins[$name]->is_enabled()) {
|
||||
$class = core_plugin_manager::resolve_plugininfo_class('communication');
|
||||
$class::enable_plugin($name, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
redirect($return);
|
||||
@@ -4114,195 +4114,4 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.3" requires="3.11.8">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.6.7" />
|
||||
<VENDOR name="mysql" version="8.0" />
|
||||
<VENDOR name="postgres" version="13" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.0.0" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="sixtyfourbitsrequired" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Hooks overview page.
|
||||
*
|
||||
* @package core
|
||||
* @author Petr Skoda
|
||||
* @copyright 2022 Open LMS
|
||||
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
|
||||
admin_externalpage_setup('hooksoverview');
|
||||
require_capability('moodle/site:config', \core\context\system::instance());
|
||||
|
||||
$hookmanager = \core\hook\manager::get_instance();
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('hooksoverview', 'core_admin'));
|
||||
|
||||
$table = new \core_admin\table\hook_list_table();
|
||||
$table->out();
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
@@ -224,7 +224,7 @@ if (!core_tables_exist()) {
|
||||
$strlicense = get_string('license');
|
||||
|
||||
$PAGE->navbar->add($strlicense);
|
||||
$PAGE->set_title($strinstallation . moodle_page::TITLE_SEPARATOR . 'Moodle ' . $CFG->target_release, false);
|
||||
$PAGE->set_title($strinstallation.' - Moodle '.$CFG->target_release);
|
||||
$PAGE->set_heading($strinstallation);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
@@ -267,7 +267,7 @@ if (!core_tables_exist()) {
|
||||
upgrade_init_javascript();
|
||||
|
||||
$PAGE->navbar->add($strdatabasesetup);
|
||||
$PAGE->set_title($strinstallation . moodle_page::TITLE_SEPARATOR . $CFG->target_release, false);
|
||||
$PAGE->set_title($strinstallation.' - Moodle '.$CFG->target_release);
|
||||
$PAGE->set_heading($strinstallation);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
@@ -818,7 +818,7 @@ $context = context_system::instance();
|
||||
|
||||
if (!has_capability('moodle/site:config', $context)) {
|
||||
// Do not throw exception display an empty page with administration menu if visible for current user.
|
||||
$PAGE->set_title(get_string('home'));
|
||||
$PAGE->set_title($SITE->fullname);
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
@@ -96,16 +96,20 @@ function core_admin_pluginfile($course, $cm, $context, $filearea, $args, $forced
|
||||
send_file_not_found();
|
||||
}
|
||||
|
||||
// Check whether width/height are specified, and we can resize the image (some types such as ICO cannot be resized).
|
||||
if (($maxwidth === 0 && $maxheight === 0) ||
|
||||
!$filedata = $file->resize_image($maxwidth, $maxheight)) {
|
||||
|
||||
// No need for resizing, but if the file should be cached we save it so we can serve it fast next time.
|
||||
if (empty($maxwidth) && empty($maxheight)) {
|
||||
if ($lifetime) {
|
||||
file_safe_save_content($file->get_content(), $candidate);
|
||||
}
|
||||
send_stored_file($file, $lifetime, 0, false, $options);
|
||||
}
|
||||
|
||||
// Proceed with the resizing.
|
||||
$filedata = $file->resize_image($maxwidth, $maxheight);
|
||||
if (!$filedata) {
|
||||
send_file_not_found();
|
||||
}
|
||||
|
||||
// If we don't want to cached the file, serve now and quit.
|
||||
if (!$lifetime) {
|
||||
send_content_uncached($filedata, $filename);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* Displays the list of found local plugins, their version (if found) and
|
||||
* a link to delete the local plugin.
|
||||
*
|
||||
* @see https://moodledev.io/docs/apis/plugintypes/local
|
||||
* @see http://docs.moodle.org/dev/Local_customisation
|
||||
* @package admin
|
||||
* @copyright 2010 David Mudrak <david.mudrak@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* Displays the list of found plagiarism plugins, their version (if found) and
|
||||
* a link to uninstall the plagiarism plugin.
|
||||
*
|
||||
* @see https://moodledev.io/docs/apis/subsystems/plagiarism
|
||||
* @see http://docs.moodle.org/dev/Plagiarism_API
|
||||
* @package admin
|
||||
* @copyright 2012 Dan Marsden <dan@danmarsden.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
@@ -26,8 +26,34 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_configmultiselect extends adminpresets_setting {
|
||||
|
||||
/** @var \admin_setting_configmultiselect $settingdata */
|
||||
protected $settingdata;
|
||||
/**
|
||||
* Ensure that the $value values are setting choices.
|
||||
*
|
||||
* @param mixed $value Setting value
|
||||
* @return mixed Returns false if wrong param value
|
||||
*/
|
||||
protected function set_value($value) {
|
||||
if ($value) {
|
||||
$options = explode(',', $value);
|
||||
foreach ($options as $option) {
|
||||
|
||||
foreach ($this->settingdata->choices as $key => $choice) {
|
||||
|
||||
if ($key == $option) {
|
||||
$this->value = $option;
|
||||
$this->set_visiblevalue();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$value = implode(',', $options);
|
||||
}
|
||||
$this->value = $value;
|
||||
$this->set_visiblevalue();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function set_visiblevalue() {
|
||||
$values = explode(',', $this->value);
|
||||
@@ -35,8 +61,7 @@ class adminpresets_admin_setting_configmultiselect extends adminpresets_setting
|
||||
|
||||
foreach ($values as $value) {
|
||||
|
||||
// Ensure that each value exists as a setting choice.
|
||||
if (array_key_exists($value, $this->settingdata->choices)) {
|
||||
if (!empty($this->settingdata->choices[$value])) {
|
||||
$visiblevalues[] = $this->settingdata->choices[$value];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,9 +26,6 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_configselect extends adminpresets_setting {
|
||||
|
||||
/** @var \admin_setting_configselect $settingdata */
|
||||
protected $settingdata;
|
||||
|
||||
/**
|
||||
* Sets the setting value cleaning it.
|
||||
*
|
||||
|
||||
@@ -26,9 +26,6 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_configtime extends adminpresets_setting {
|
||||
|
||||
/** @var \admin_setting_configtime $settingdata */
|
||||
protected $settingdata;
|
||||
|
||||
/**
|
||||
* To check that the value is one of the options
|
||||
*
|
||||
|
||||
@@ -19,8 +19,6 @@ namespace core_adminpresets\local\setting;
|
||||
/**
|
||||
* Reimplementation to allow human friendly view of the selected regexps.
|
||||
*
|
||||
* @deprecated Moodle 4.3 MDL-78468 - No longer used since the devicedetectregex was removed.
|
||||
* @todo Final deprecation on Moodle 4.7 MDL-79052
|
||||
* @package core_adminpresets
|
||||
* @copyright 2021 Pimenko <support@pimenko.com><pimenko.com>
|
||||
* @author Jordan Kesraoui | Sylvain Revenu | Pimenko based on David Monllaó <david.monllao@urv.cat> code
|
||||
@@ -28,16 +26,7 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_devicedetectregex extends adminpresets_admin_setting_configtext {
|
||||
|
||||
/**
|
||||
* @deprecated Moodle 4.3 MDL-78468 - No longer used since the devicedetectregex was removed.
|
||||
* @todo Final deprecation on Moodle 4.7 MDL-79052
|
||||
*/
|
||||
public function set_visiblevalue() {
|
||||
debugging(
|
||||
__FUNCTION__ . '() is deprecated.' .
|
||||
'All functions associated with devicedetectregex theme setting are being removed.',
|
||||
DEBUG_DEVELOPER
|
||||
);
|
||||
$values = json_decode($this->get_value());
|
||||
|
||||
if (!$values) {
|
||||
|
||||
@@ -28,9 +28,6 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_special_backupdays extends adminpresets_setting {
|
||||
|
||||
/** @var \admin_setting_special_backupdays $settingdata */
|
||||
protected $settingdata;
|
||||
|
||||
protected function set_value($value) {
|
||||
$this->value = clean_param($value, PARAM_SEQUENCE);
|
||||
$this->set_visiblevalue();
|
||||
|
||||
@@ -26,9 +26,6 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_users_with_capability extends adminpresets_admin_setting_configmultiselect {
|
||||
|
||||
/** @var \admin_setting_configmultiselect $settingdata */
|
||||
protected $settingdata;
|
||||
|
||||
protected function set_behaviors() {
|
||||
$this->behaviors['loadchoices'] = &$this->settingdata;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,7 @@
|
||||
require_once('../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
|
||||
use core\event\qbank_plugin_enabled;
|
||||
use core\event\qbank_plugin_disabled;
|
||||
use qbank_columnsortorder\column_manager;
|
||||
|
||||
$action = required_param('action', PARAM_ALPHANUMEXT);
|
||||
$name = required_param('name', PARAM_PLUGIN);
|
||||
@@ -50,11 +49,12 @@ if (!isset($plugins[$name])) {
|
||||
}
|
||||
|
||||
$plugintypename = $plugins[$name]->type . '_' . $plugins[$name]->name;
|
||||
$columnsortordermanager = new column_manager();
|
||||
|
||||
switch ($action) {
|
||||
case 'disable':
|
||||
if ($plugins[$name]->is_enabled()) {
|
||||
qbank_plugin_disabled::create_for_plugin($plugintypename)->trigger();
|
||||
$columnsortordermanager->disable_columns($plugintypename);
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('qbank');
|
||||
$class::enable_plugin($name, false);
|
||||
set_config('disabled', 1, 'qbank_'. $name);
|
||||
@@ -62,7 +62,7 @@ switch ($action) {
|
||||
break;
|
||||
case 'enable':
|
||||
if (!$plugins[$name]->is_enabled()) {
|
||||
qbank_plugin_enabled::create_for_plugin($plugintypename)->trigger();
|
||||
$columnsortordermanager->enable_columns($plugintypename);
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('qbank');
|
||||
$class::enable_plugin($name, true);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$output .= $this->heading(get_string('copyrightnotice'));
|
||||
$output .= $this->box($copyrightnotice, 'copyrightnotice');
|
||||
$output .= html_writer::empty_tag('br');
|
||||
$output .= $this->confirm(get_string('doyouagree'), $continue, "https://moodledev.io/general/license");
|
||||
$output .= $this->confirm(get_string('doyouagree'), $continue, "http://docs.moodle.org/dev/License");
|
||||
$output .= $this->footer();
|
||||
|
||||
return $output;
|
||||
@@ -745,10 +745,10 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//// IT IS ILLEGAL AND A VIOLATION OF THE GPL TO HIDE, REMOVE OR MODIFY THIS COPYRIGHT NOTICE ///
|
||||
$copyrighttext = '<a href="http://moodle.org/">Moodle</a> '.
|
||||
'<a href="https://moodledev.io/general/releases" title="'.$CFG->version.'">'.$CFG->release.'</a><br />'.
|
||||
'<a href="http://docs.moodle.org/dev/Releases" title="'.$CFG->version.'">'.$CFG->release.'</a><br />'.
|
||||
'Copyright © 1999 onwards, Martin Dougiamas<br />'.
|
||||
'and <a href="http://moodle.org/dev">many other contributors</a>.<br />'.
|
||||
'<a href="https://moodledev.io/general/license">GNU Public License</a>';
|
||||
'<a href="http://docs.moodle.org/dev/License">GNU Public License</a>';
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
return $this->box($copyrighttext, 'copyright');
|
||||
@@ -897,8 +897,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$url = "https://campaign.moodle.org/current/lms/{$lang}/install/";
|
||||
$params = [
|
||||
'url' => $url,
|
||||
'iframeid' => 'campaign-content',
|
||||
'title' => get_string('campaign', 'admin'),
|
||||
'iframeid' => 'campaign-content'
|
||||
];
|
||||
|
||||
return $this->render_from_template('core/external_content_banner', $params);
|
||||
@@ -919,8 +918,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$url = "https://campaign.moodle.org/current/lms/{$lang}/servicesandsupport/";
|
||||
$params = [
|
||||
'url' => $url,
|
||||
'iframeid' => 'services-support-content',
|
||||
'title' => get_string('supportandservices', 'admin'),
|
||||
'iframeid' => 'services-support-content'
|
||||
];
|
||||
|
||||
return $this->render_from_template('core/external_content_banner', $params);
|
||||
@@ -992,7 +990,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
protected function release_notes_link() {
|
||||
$releasenoteslink = get_string('releasenoteslink', 'admin', 'https://moodledev.io/general/releases');
|
||||
$releasenoteslink = get_string('releasenoteslink', 'admin', 'http://docs.moodle.org/dev/Releases');
|
||||
$releasenoteslink = str_replace('target="_blank"', 'onclick="this.target=\'_blank\'"', $releasenoteslink); // extremely ugly validation hack
|
||||
return $this->box($releasenoteslink, 'generalbox alert alert-info');
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@ abstract class core_role_allow_role_page {
|
||||
$table->cellspacing = 0;
|
||||
$table->width = '90%';
|
||||
$table->align = array('left');
|
||||
$table->rotateheaders = true;
|
||||
$table->head = array(' ');
|
||||
$table->colclasses = array('');
|
||||
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core_role\reportbuilder\local\entities;
|
||||
|
||||
use context;
|
||||
use context_helper;
|
||||
use lang_string;
|
||||
use stdClass;
|
||||
use core_reportbuilder\local\entities\base;
|
||||
use core_reportbuilder\local\filters\select;
|
||||
use core_reportbuilder\local\report\{column, filter};
|
||||
|
||||
/**
|
||||
* Role entity
|
||||
*
|
||||
* @package core_role
|
||||
* @copyright 2023 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class role extends base {
|
||||
|
||||
/**
|
||||
* Database tables that this entity uses and their default aliases
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_default_table_aliases(): array {
|
||||
return [
|
||||
'context' => 'rctx',
|
||||
'role' => 'r',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The default title for this entity
|
||||
*
|
||||
* @return lang_string
|
||||
*/
|
||||
protected function get_default_entity_title(): lang_string {
|
||||
return new lang_string('role');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the entity
|
||||
*
|
||||
* @return base
|
||||
*/
|
||||
public function initialise(): base {
|
||||
$columns = $this->get_all_columns();
|
||||
foreach ($columns as $column) {
|
||||
$this->add_column($column);
|
||||
}
|
||||
|
||||
// All the filters defined by the entity can also be used as conditions.
|
||||
$filters = $this->get_all_filters();
|
||||
foreach ($filters as $filter) {
|
||||
$this
|
||||
->add_filter($filter)
|
||||
->add_condition($filter);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of all available columns
|
||||
*
|
||||
* @return column[]
|
||||
*/
|
||||
protected function get_all_columns(): array {
|
||||
global $DB;
|
||||
|
||||
$contextalias = $this->get_table_alias('context');
|
||||
$rolealias = $this->get_table_alias('role');
|
||||
|
||||
// Name column.
|
||||
$columns[] = (new column(
|
||||
'name',
|
||||
new lang_string('rolefullname', 'core_role'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_fields("{$rolealias}.name, {$rolealias}.shortname, {$rolealias}.id, {$contextalias}.id AS contextid")
|
||||
->add_fields(context_helper::get_preload_record_columns_sql($contextalias))
|
||||
->set_is_sortable(true)
|
||||
->set_callback(static function($name, stdClass $role): string {
|
||||
if ($name === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
context_helper::preload_from_record($role);
|
||||
$context = context::instance_by_id($role->contextid);
|
||||
|
||||
return role_get_name($role, $context, ROLENAME_BOTH);
|
||||
});
|
||||
|
||||
// Short name column.
|
||||
$columns[] = (new column(
|
||||
'shortname',
|
||||
new lang_string('roleshortname', 'core_role'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_fields("{$rolealias}.shortname")
|
||||
->set_is_sortable(true);
|
||||
|
||||
// Description column.
|
||||
$descriptionfieldsql = "{$rolealias}.description";
|
||||
if ($DB->get_dbfamily() === 'oracle') {
|
||||
$descriptionfieldsql = $DB->sql_order_by_text($descriptionfieldsql, 1024);
|
||||
}
|
||||
$columns[] = (new column(
|
||||
'description',
|
||||
new lang_string('description'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_LONGTEXT)
|
||||
->add_field($descriptionfieldsql, 'description')
|
||||
->add_field("{$rolealias}.shortname")
|
||||
->set_callback(static function($description, stdClass $role): string {
|
||||
if ($description === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return role_get_description($role);
|
||||
});
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of all available filters
|
||||
*
|
||||
* @return filter[]
|
||||
*/
|
||||
protected function get_all_filters(): array {
|
||||
$rolealias = $this->get_table_alias('role');
|
||||
|
||||
// Name filter.
|
||||
$filters[] = (new filter(
|
||||
select::class,
|
||||
'name',
|
||||
new lang_string('rolefullname', 'core_role'),
|
||||
$this->get_entity_name(),
|
||||
"{$rolealias}.id"
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_options_callback(static function(): array {
|
||||
return role_get_names(null, ROLENAME_ORIGINAL, true);
|
||||
});
|
||||
|
||||
return $filters;
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ require_once($CFG->libdir . '/adminlib.php');
|
||||
admin_externalpage_setup('searchareas', '', null, (new moodle_url('/admin/searchreindex.php'))->out(false));
|
||||
|
||||
// Get area parameter and check it exists.
|
||||
$areaid = required_param('areaid', PARAM_ALPHANUMEXT);
|
||||
$areaid = required_param('areaid', PARAM_ALPHAEXT);
|
||||
$area = \core_search\manager::get_search_area($areaid);
|
||||
if ($area === false) {
|
||||
throw new moodle_exception('invalidrequest');
|
||||
@@ -44,7 +44,7 @@ $PAGE->set_secondary_active_tab('modules');
|
||||
|
||||
// Start page output.
|
||||
$heading = get_string('gradualreindex', 'search', '');
|
||||
$PAGE->set_title($areaname . ' - ' . get_string('gradualreindex', 'search', ''));
|
||||
$PAGE->set_title($PAGE->title . ': ' . $heading);
|
||||
$PAGE->navbar->add($heading);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($heading);
|
||||
|
||||
@@ -129,7 +129,9 @@ if (empty($SITE->fullname)) {
|
||||
$PAGE->set_button($buttons);
|
||||
}
|
||||
|
||||
$PAGE->set_title(implode(moodle_page::TITLE_SEPARATOR, $settingspage->visiblepath));
|
||||
$visiblepathtosection = array_reverse($settingspage->visiblepath);
|
||||
|
||||
$PAGE->set_title("$SITE->shortname: " . implode(": ",$visiblepathtosection));
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ reports,core_reportbuilder|/reportbuilder/index.php',
|
||||
'50',
|
||||
'10'
|
||||
));
|
||||
$temp->add(new admin_setting_configcheckbox('enabledevicedetection', new lang_string('enabledevicedetection', 'admin'), new lang_string('configenabledevicedetection', 'admin'), 1));
|
||||
$temp->add(new admin_setting_devicedetectregex('devicedetectregex', new lang_string('devicedetectregex', 'admin'), new lang_string('devicedetectregex_desc', 'admin'), ''));
|
||||
$ADMIN->add('themes', $temp);
|
||||
$ADMIN->add('themes', new admin_externalpage('themeselector', new lang_string('themeselector','admin'), $CFG->wwwroot . '/theme/index.php'));
|
||||
|
||||
@@ -242,18 +244,6 @@ reports,core_reportbuilder|/reportbuilder/index.php',
|
||||
|
||||
// "htmlsettings" settingpage
|
||||
$temp = new admin_settingpage('htmlsettings', new lang_string('htmlsettings', 'admin'));
|
||||
$sitenameintitleoptions = [
|
||||
'shortname' => new lang_string('shortname'),
|
||||
'fullname' => new lang_string('fullname'),
|
||||
];
|
||||
$sitenameintitleconfig = new admin_setting_configselect(
|
||||
'sitenameintitle',
|
||||
new lang_string('sitenameintitle', 'admin'),
|
||||
new lang_string('sitenameintitle_help', 'admin'),
|
||||
'shortname',
|
||||
$sitenameintitleoptions
|
||||
);
|
||||
$temp->add($sitenameintitleconfig);
|
||||
$temp->add(new admin_setting_configcheckbox('formatstringstriptags', new lang_string('stripalltitletags', 'admin'), new lang_string('configstripalltitletags', 'admin'), 1));
|
||||
$temp->add(new admin_setting_emoticons());
|
||||
$ADMIN->add('appearance', $temp);
|
||||
|
||||
@@ -43,6 +43,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
array('moodle/category:manage', 'moodle/course:create')
|
||||
)
|
||||
);
|
||||
$ADMIN->add('courses',
|
||||
new admin_externalpage('course_customfield', new lang_string('course_customfield', 'admin'),
|
||||
$CFG->wwwroot . '/course/customfield.php',
|
||||
array('moodle/course:configurecustomfields')
|
||||
)
|
||||
);
|
||||
$ADMIN->add('courses',
|
||||
new admin_externalpage('addcategory', new lang_string('addcategory', 'admin'),
|
||||
new moodle_url('/course/editcategory.php', array('parent' => 0)),
|
||||
@@ -62,49 +68,6 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
)
|
||||
);
|
||||
|
||||
// Download course content.
|
||||
$downloadcoursedefaulturl = new moodle_url('/admin/settings.php', ['section' => 'coursesettings']);
|
||||
$temp = new admin_settingpage('downloadcoursecontent', new lang_string('downloadcoursecontent', 'course'));
|
||||
$temp->add(new admin_setting_configcheckbox('downloadcoursecontentallowed',
|
||||
new lang_string('downloadcoursecontentallowed', 'admin'),
|
||||
new lang_string('downloadcoursecontentallowed_desc', 'admin', $downloadcoursedefaulturl->out()), 0));
|
||||
|
||||
// 50MB default maximum size per file when downloading course content.
|
||||
$defaultmaxdownloadsize = 50 * filesize::UNIT_MB;
|
||||
$temp->add(new filesize('maxsizeperdownloadcoursefile', new lang_string('maxsizeperdownloadcoursefile', 'admin'),
|
||||
new lang_string('maxsizeperdownloadcoursefile_desc', 'admin'), $defaultmaxdownloadsize, filesize::UNIT_MB));
|
||||
$temp->hide_if('maxsizeperdownloadcoursefile', 'downloadcoursecontentallowed');
|
||||
|
||||
$ADMIN->add('courses', $temp);
|
||||
|
||||
// "courserequests" settingpage.
|
||||
$temp = new admin_settingpage('courserequest', new lang_string('courserequest'));
|
||||
$temp->add(new admin_setting_configcheckbox('enablecourserequests',
|
||||
new lang_string('enablecourserequests', 'admin'),
|
||||
new lang_string('configenablecourserequests', 'admin'), 1));
|
||||
$temp->add(new admin_settings_coursecat_select('defaultrequestcategory',
|
||||
new lang_string('defaultrequestcategory', 'admin'),
|
||||
new lang_string('configdefaultrequestcategory', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('lockrequestcategory',
|
||||
new lang_string('lockrequestcategory', 'admin'),
|
||||
new lang_string('configlockrequestcategory', 'admin'), 0));
|
||||
$temp->add(new admin_setting_users_with_capability(
|
||||
'courserequestnotify',
|
||||
new lang_string('courserequestnotify', 'admin'),
|
||||
new lang_string('configcourserequestnotify2', 'admin'),
|
||||
[],
|
||||
'moodle/site:approvecourse'
|
||||
));
|
||||
$ADMIN->add('courses', $temp);
|
||||
|
||||
// Pending course requests.
|
||||
if (!empty($CFG->enablecourserequests)) {
|
||||
$ADMIN->add('courses', new admin_externalpage('coursespending', new lang_string('pendingrequests'),
|
||||
$CFG->wwwroot . '/course/pending.php', array('moodle/site:approvecourse')));
|
||||
}
|
||||
|
||||
// Add a category for the course Default settings.
|
||||
$ADMIN->add('courses', new admin_category('coursedefaultsettings', new lang_string('defaultsettingscategory', 'course')));
|
||||
// Course Default Settings Page.
|
||||
// NOTE: these settings must be applied after all other settings because they depend on them.
|
||||
|
||||
@@ -251,73 +214,42 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$temp->add(new admin_setting_configselect('moodlecourse/groupmode', new lang_string('groupmode'), '', key($choices),$choices));
|
||||
$temp->add(new admin_setting_configselect('moodlecourse/groupmodeforce', new lang_string('force'), new lang_string('coursehelpforce'), 0,array(0 => new lang_string('no'), 1 => new lang_string('yes'))));
|
||||
|
||||
// Communication.
|
||||
$temp->add(new admin_setting_heading('communication',
|
||||
new lang_string('communication', 'core_communication'), ''));
|
||||
$ADMIN->add('courses', $temp);
|
||||
|
||||
list($communicationproviders, $defaulprovider) = \core_communication\api::
|
||||
get_enabled_providers_and_default();
|
||||
// Download course content.
|
||||
$downloadcoursedefaulturl = new moodle_url('/admin/settings.php', ['section' => 'coursesettings']);
|
||||
$temp = new admin_settingpage('downloadcoursecontent', new lang_string('downloadcoursecontent', 'course'));
|
||||
$temp->add(new admin_setting_configcheckbox('downloadcoursecontentallowed',
|
||||
new lang_string('downloadcoursecontentallowed', 'admin'),
|
||||
new lang_string('downloadcoursecontentallowed_desc', 'admin', $downloadcoursedefaulturl->out()), 0));
|
||||
|
||||
$temp->add(new admin_setting_configselect('moodlecourse/coursecommunicationprovider',
|
||||
new lang_string('selectcommunicationprovider', 'communication'),
|
||||
new lang_string('coursecommunication_desc', 'course'),
|
||||
$defaulprovider, $communicationproviders));
|
||||
// 50MB default maximum size per file when downloading course content.
|
||||
$defaultmaxdownloadsize = 50 * filesize::UNIT_MB;
|
||||
$temp->add(new filesize('maxsizeperdownloadcoursefile', new lang_string('maxsizeperdownloadcoursefile', 'admin'),
|
||||
new lang_string('maxsizeperdownloadcoursefile_desc', 'admin'), $defaultmaxdownloadsize, filesize::UNIT_MB));
|
||||
$temp->hide_if('maxsizeperdownloadcoursefile', 'downloadcoursecontentallowed');
|
||||
|
||||
$ADMIN->add('coursedefaultsettings', $temp);
|
||||
if (!empty($CFG->enablecompletion)) {
|
||||
$ADMIN->add('coursedefaultsettings', new admin_externalpage(
|
||||
'sitedefaultcompletion',
|
||||
new lang_string('defaultcompletion', 'completion'),
|
||||
new moodle_url('/course/defaultcompletion.php', ['id' => $SITE->id]),
|
||||
['moodle/course:manageactivities'])
|
||||
);
|
||||
$ADMIN->add('courses', $temp);
|
||||
|
||||
// "courserequests" settingpage.
|
||||
$temp = new admin_settingpage('courserequest', new lang_string('courserequest'));
|
||||
$temp->add(new admin_setting_configcheckbox('enablecourserequests',
|
||||
new lang_string('enablecourserequests', 'admin'),
|
||||
new lang_string('configenablecourserequests', 'admin'), 1));
|
||||
$temp->add(new admin_settings_coursecat_select('defaultrequestcategory',
|
||||
new lang_string('defaultrequestcategory', 'admin'),
|
||||
new lang_string('configdefaultrequestcategory', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('lockrequestcategory',
|
||||
new lang_string('lockrequestcategory', 'admin'),
|
||||
new lang_string('configlockrequestcategory', 'admin'), 0));
|
||||
$temp->add(new admin_setting_users_with_capability('courserequestnotify', new lang_string('courserequestnotify', 'admin'), new lang_string('configcourserequestnotify2', 'admin'), array(), 'moodle/site:approvecourse'));
|
||||
$ADMIN->add('courses', $temp);
|
||||
|
||||
// Pending course requests.
|
||||
if (!empty($CFG->enablecourserequests)) {
|
||||
$ADMIN->add('courses', new admin_externalpage('coursespending', new lang_string('pendingrequests'),
|
||||
$CFG->wwwroot . '/course/pending.php', array('moodle/site:approvecourse')));
|
||||
}
|
||||
$ADMIN->add('coursedefaultsettings', new admin_externalpage(
|
||||
'course_customfield',
|
||||
new lang_string('course_customfield', 'admin'),
|
||||
$CFG->wwwroot . '/course/customfield.php',
|
||||
['moodle/course:configurecustomfields'])
|
||||
);
|
||||
|
||||
$temp = new admin_settingpage('activitychoosersettings', new lang_string('activitychoosersettings', 'course'));
|
||||
// Tab mode for the activity chooser.
|
||||
$temp->add(
|
||||
new admin_setting_configselect(
|
||||
'activitychoosertabmode',
|
||||
new lang_string('activitychoosertabmode', 'course'),
|
||||
new lang_string('activitychoosertabmode_desc', 'course'),
|
||||
3,
|
||||
[
|
||||
3 => new lang_string('activitychoosertabmodefour', 'course'),
|
||||
4 => new lang_string('activitychoosertabmodefive', 'course'),
|
||||
5 => new lang_string('activitychoosertabmodesix', 'course'),
|
||||
0 => new lang_string('activitychoosertabmodeone', 'course'),
|
||||
1 => new lang_string('activitychoosertabmodetwo', 'course'),
|
||||
2 => new lang_string('activitychoosertabmodethree', 'course'),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
// Add a category for the Groups.
|
||||
$ADMIN->add('courses', new admin_category('groups', new lang_string('groups')));
|
||||
$ADMIN->add(
|
||||
'groups',
|
||||
new admin_externalpage(
|
||||
'group_customfield',
|
||||
new lang_string('group_customfield', 'admin'),
|
||||
$CFG->wwwroot . '/group/customfield.php',
|
||||
['moodle/group:configurecustomfields']
|
||||
)
|
||||
);
|
||||
$ADMIN->add(
|
||||
'groups',
|
||||
new admin_externalpage(
|
||||
'grouping_customfield',
|
||||
new lang_string('grouping_customfield', 'admin'),
|
||||
$CFG->wwwroot . '/group/grouping_customfield.php',
|
||||
['moodle/group:configurecustomfields']
|
||||
)
|
||||
);
|
||||
|
||||
// Add a category for the Activity Chooser.
|
||||
$ADMIN->add('courses', new admin_category('activitychooser', new lang_string('activitychoosercategory', 'course')));
|
||||
|
||||
@@ -38,11 +38,6 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
new lang_string('enablesharingtomoodlenet', 'core_admin'),
|
||||
new lang_string('enablesharingtomoodlenet_desc', 'core_admin'), 0));
|
||||
|
||||
// New communication subsystem setting.
|
||||
$temp->add(new admin_setting_configcheckbox('enablecommunicationsubsystem',
|
||||
new lang_string('enablecommunicationsubsystem', 'core_admin'),
|
||||
new lang_string('enablecommunicationsubsystem_desc', 'core_admin'), 0));
|
||||
|
||||
$ADMIN->add('experimental', $temp);
|
||||
|
||||
// "debugging" settingpage
|
||||
@@ -121,7 +116,4 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
"$CFG->wwwroot/$CFG->admin/purgecaches.php"));
|
||||
|
||||
$ADMIN->add('development', new admin_externalpage('thirdpartylibs', new lang_string('thirdpartylibs','admin'), "$CFG->wwwroot/$CFG->admin/thirdpartylibs.php"));
|
||||
|
||||
$ADMIN->add('development', new admin_externalpage('hooksoverview',
|
||||
new lang_string('hooksoverview', 'admin'), "$CFG->wwwroot/$CFG->admin/hooks.php"));
|
||||
} // end of speedup
|
||||
|
||||
@@ -116,17 +116,6 @@ if ($hassiteconfig) {
|
||||
$temp->add($setting);
|
||||
$temp->add(new admin_setting_configcheckbox('verifychangedemail', new lang_string('verifychangedemail', 'admin'), new lang_string('configverifychangedemail', 'admin'), 1));
|
||||
|
||||
// ReCaptcha.
|
||||
$temp->add(new admin_setting_configselect('enableloginrecaptcha',
|
||||
new lang_string('auth_loginrecaptcha', 'auth'),
|
||||
new lang_string('auth_loginrecaptcha_desc', 'auth'),
|
||||
0,
|
||||
[
|
||||
new lang_string('no'),
|
||||
new lang_string('yes'),
|
||||
],
|
||||
));
|
||||
|
||||
$setting = new admin_setting_configtext('recaptchapublickey', new lang_string('recaptchapublickey', 'admin'), new lang_string('configrecaptchapublickey', 'admin'), '', PARAM_NOTAGS);
|
||||
$setting->set_force_ltr(true);
|
||||
$temp->add($setting);
|
||||
@@ -792,20 +781,6 @@ if ($hassiteconfig) {
|
||||
}
|
||||
}
|
||||
|
||||
// Communication plugins.
|
||||
if ($hassiteconfig && core_communication\api::is_available()) {
|
||||
$ADMIN->add('modules', new admin_category('communicationsettings', new lang_string('communication', 'core_communication')));
|
||||
$temp = new admin_settingpage('managecommunicationproviders',
|
||||
new lang_string('managecommunicationproviders', 'core_communication'));
|
||||
$temp->add(new \core_communication\admin\manage_communication_providers_page());
|
||||
$ADMIN->add('communicationsettings', $temp);
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('communication');
|
||||
foreach ($plugins as $plugin) {
|
||||
/** @var \core\plugininfo\communication $plugin */
|
||||
$plugin->load_settings($ADMIN, 'communicationsettings', $hassiteconfig);
|
||||
}
|
||||
}
|
||||
|
||||
// Content bank content types.
|
||||
if ($hassiteconfig) {
|
||||
$ADMIN->add('modules', new admin_category('contentbanksettings', new lang_string('contentbank')));
|
||||
|
||||
@@ -145,7 +145,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$temp->add(new admin_setting_heading('adminpresets', new lang_string('siteadminpresetspluginname', 'core_adminpresets'), ''));
|
||||
$sensiblesettingsdefault = 'recaptchapublickey@@none, recaptchaprivatekey@@none, googlemapkey3@@none, ';
|
||||
$sensiblesettingsdefault .= 'secretphrase@@url, cronremotepassword@@none, smtpuser@@none, ';
|
||||
$sensiblesettingsdefault .= 'smtppass@@none, proxypassword@@none, quizpassword@@quiz, allowedip@@none, blockedip@@none, ';
|
||||
$sensiblesettingsdefault .= 'smtppass@none, proxypassword@@none, quizpassword@@quiz, allowedip@@none, blockedip@@none, ';
|
||||
$sensiblesettingsdefault .= 'dbpass@@logstore_database, messageinbound_hostpass@@none, ';
|
||||
$sensiblesettingsdefault .= 'bind_pw@@auth_cas, pass@@auth_db, bind_pw@@auth_ldap, ';
|
||||
$sensiblesettingsdefault .= 'dbpass@@enrol_database, bind_pw@@enrol_ldap, ';
|
||||
@@ -164,6 +164,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$temp = new admin_settingpage('httpsecurity', new lang_string('httpsecurity', 'admin'));
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('cookiesecure', new lang_string('cookiesecure', 'admin'), new lang_string('configcookiesecure', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('cookiehttponly', new lang_string('cookiehttponly', 'admin'), new lang_string('configcookiehttponly', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('allowframembedding', new lang_string('allowframembedding', 'admin'), new lang_string('allowframembedding_help', 'admin'), 0));
|
||||
|
||||
// Settings elements used by the \core\files\curl_security_helper class.
|
||||
|
||||
@@ -453,12 +453,6 @@ if ($hassiteconfig) {
|
||||
// Outgoing mail configuration.
|
||||
$temp = new admin_settingpage('outgoingmailconfig', new lang_string('outgoingmailconfig', 'admin'));
|
||||
|
||||
if (!empty($CFG->noemailever)) {
|
||||
$noemaileverwarning = new \core\output\notification(get_string('noemaileverwarning', 'admin'),
|
||||
\core\output\notification::NOTIFY_ERROR);
|
||||
$temp->add(new admin_setting_heading('outgoingmaildisabled', '', $OUTPUT->render($noemaileverwarning)));
|
||||
}
|
||||
|
||||
$temp->add(new admin_setting_heading('smtpheading', new lang_string('smtp', 'admin'),
|
||||
new lang_string('smtpdetail', 'admin')));
|
||||
|
||||
@@ -522,12 +516,8 @@ if ($hassiteconfig) {
|
||||
$temp->add(new admin_setting_heading('noreplydomainheading', new lang_string('noreplydomain', 'admin'),
|
||||
new lang_string('noreplydomaindetail', 'admin')));
|
||||
|
||||
$default = clean_param('noreply@' . get_host_from_url($CFG->wwwroot), PARAM_EMAIL);
|
||||
if (!$default) {
|
||||
$default = null;
|
||||
}
|
||||
$temp->add(new admin_setting_configtext('noreplyaddress', new lang_string('noreplyaddress', 'admin'),
|
||||
new lang_string('confignoreplyaddress', 'admin'), $default, PARAM_EMAIL));
|
||||
new lang_string('confignoreplyaddress', 'admin'), 'noreply@' . get_host_from_url($CFG->wwwroot), PARAM_EMAIL));
|
||||
|
||||
$temp->add(new admin_setting_configtextarea('allowedemaildomains',
|
||||
new lang_string('allowedemaildomains', 'admin'),
|
||||
|
||||
@@ -31,6 +31,8 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
1 => get_string('completionactivitydefault', 'completion'),
|
||||
0 => get_string('completion_none', 'completion')
|
||||
);
|
||||
$optionalsubsystems->add(new admin_setting_configselect('completiondefault', new lang_string('completiondefault', 'completion'),
|
||||
new lang_string('configcompletiondefault', 'completion'), 1, $options));
|
||||
|
||||
$optionalsubsystems->add($checkbox = new admin_setting_configcheckbox('enableavailability',
|
||||
new lang_string('enableavailability', 'availability'),
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@deprecated since Moodle 4.3
|
||||
@todo Final deprecation on Moodle 4.7 MDL-79052
|
||||
@template core_admin/setting_devicedetectregex
|
||||
|
||||
Admin devicedetectregex setting template.
|
||||
|
||||
@@ -1,47 +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 <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_admin/webservice_token_new
|
||||
|
||||
This is the template for displaying the newly created webservice token.
|
||||
|
||||
Context variable required for this template:
|
||||
* token - Token value
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"token": "ef9ee4d0c6eed5eab8453a63b93b5b8b"
|
||||
}
|
||||
}}
|
||||
|
||||
<div class="d-inline-block">
|
||||
<div class="alert alert-warning">
|
||||
<div class="lead">{{#str}}tokennewmessage, webservice{{/str}}</div>
|
||||
</div>
|
||||
<div class="alert alert-primary">
|
||||
<div class="lead">{{tokenname}}</div>
|
||||
<div class="d-flex justify-content-start align-middle">
|
||||
<div class="lead text-break pt-1" id="copytoclipboardtoken">{{token}}</div>
|
||||
<button class="btn btn-primary ml-2" data-action="copytoclipboard" data-clipboard-target="#copytoclipboardtoken" data-clipboard-success-message="{{#str}}tokencopied, webservice{{/str}}">
|
||||
{{#pix}}t/copy, core {{/pix}}{{#str}}copytoclipboard{{/str}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#js}}
|
||||
require(['core/copy_to_clipboard']);
|
||||
{{/js}}
|
||||
@@ -40,12 +40,6 @@ if ($form->is_cancelled()) {
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($headingtitle);
|
||||
|
||||
// Displaying noemailever warning.
|
||||
if (!empty($CFG->noemailever)) {
|
||||
$msg = get_string('noemaileverwarning', 'admin');
|
||||
echo $OUTPUT->notification($msg, \core\output\notification::NOTIFY_ERROR);
|
||||
}
|
||||
|
||||
$data = $form->get_data();
|
||||
if ($data) {
|
||||
$emailuser = new stdClass();
|
||||
|
||||
@@ -56,7 +56,7 @@ Feature: Staff can assign user roles
|
||||
Scenario: Enrol at activity level using custom field search
|
||||
When I am on the "page1" "Activity" page logged in as "admin"
|
||||
And I navigate to "Permissions" in current page administration
|
||||
And I set the field "Participants tertiary navigation" to "Locally assigned roles"
|
||||
And I select "Locally assigned roles" from the "jump" singleselect
|
||||
And I follow "Teacher"
|
||||
And I set the field "addselect_searchtext" to "Kermit"
|
||||
# The Behat 'I should see' step doesn't work for optgroup labels.
|
||||
@@ -72,7 +72,7 @@ Feature: Staff can assign user roles
|
||||
| user1 | editingteacher | Activity module | page1 |
|
||||
When I am on the "page1" "Activity" page logged in as "admin"
|
||||
And I navigate to "Permissions" in current page administration
|
||||
And I set the field "Participants tertiary navigation" to "Locally assigned roles"
|
||||
And I select "Locally assigned roles" from the "jump" singleselect
|
||||
And I follow "Teacher"
|
||||
And I set the field "removeselect_searchtext" to "Kermit"
|
||||
# The Behat 'I should see' step doesn't work for optgroup labels.
|
||||
|
||||
@@ -28,7 +28,7 @@ Feature: Staff can check user permissions
|
||||
@javascript
|
||||
Scenario: Search for a user (enrolled on the course) by custom field and select them to see permissions
|
||||
When I am on the "C1" "permissions" page logged in as "admin"
|
||||
And I set the field "Participants tertiary navigation" to "Check permissions"
|
||||
And I select "Check permissions" from the "jump" singleselect
|
||||
And I set the field "Search" to "Kermit"
|
||||
# The Behat 'I should see' step doesn't work for optgroup labels.
|
||||
Then "optgroup[label='Matching enrolled users (1)']" "css_element" should exist
|
||||
@@ -42,7 +42,7 @@ Feature: Staff can check user permissions
|
||||
@javascript
|
||||
Scenario: Search for a user (not enrolled on the course) by custom field and select them to see permissions
|
||||
When I am on the "C1" "permissions" page logged in as "admin"
|
||||
And I set the field "Participants tertiary navigation" to "Check permissions"
|
||||
And I select "Check permissions" from the "jump" singleselect
|
||||
And I set the field "Search" to "Kermit"
|
||||
# The Behat 'I should see' step doesn't work for optgroup labels.
|
||||
Then "optgroup[label*='Potential users matching'][label*=' (1)']" "css_element" should exist
|
||||
|
||||
@@ -19,32 +19,19 @@ Feature: Manage external services tokens
|
||||
And I am on site homepage
|
||||
And I navigate to "Server > Web services > Manage tokens" in site administration
|
||||
And I press "Create token"
|
||||
And I set the field "Name" to "Webservice1"
|
||||
And I set the field "User" to "Firstname1 Lastname1"
|
||||
And I set the field "Service" to "Moodle mobile web service"
|
||||
And I set the field "IP restriction" to "127.0.0.1"
|
||||
When I press "Save changes"
|
||||
Then the following should exist in the "generaltable" table:
|
||||
| Name | First name | Service | IP restriction | Last access |
|
||||
| Webservice1 | Firstname1 Lastname1 | Moodle mobile web service | 127.0.0.1 | Never |
|
||||
|
||||
# Verify the message and the "Copy to clipboard" button.
|
||||
And I should see "Copy the token now. It won't be shown again once you leave this page."
|
||||
And "Copy to clipboard" "button" should exist
|
||||
|
||||
# New token can only read once.
|
||||
And I reload the page
|
||||
And I should not see "Copy the token now. It won't be shown again once you leave this page."
|
||||
And "Copy to clipboard" "button" should not exist
|
||||
|
||||
# Delete token.
|
||||
And I click on "Delete" "link" in the "Webservice1" "table_row"
|
||||
Then I should see "Moodle mobile web service" in the "Firstname1 Lastname1" "table_row"
|
||||
And I should see "127.0.0.1" in the "Firstname1 Lastname1" "table_row"
|
||||
And I click on "Delete" "link" in the "Firstname1 Lastname1" "table_row"
|
||||
And I should see "Do you really want to delete this web service token for Firstname1 Lastname1 on the service Moodle mobile web service?"
|
||||
And I press "Delete"
|
||||
And "Webservice1" "table_row" should not exist
|
||||
And "Firstname1 Lastname1" "table_row" should not exist
|
||||
|
||||
@javascript @skip_chrome_zerosize
|
||||
Scenario: Tokens can be filtered by name (case-insensitive), by user and by service
|
||||
Scenario: Tokens can be filtered by user and by service
|
||||
Given the following "core_webservice > Service" exists:
|
||||
| name | Site information |
|
||||
| shortname | siteinfo |
|
||||
@@ -53,10 +40,10 @@ Feature: Manage external services tokens
|
||||
| service | siteinfo |
|
||||
| functions | core_webservice_get_site_info |
|
||||
And the following "core_webservice > Tokens" exist:
|
||||
| user | service | name |
|
||||
| user2 | siteinfo | WEBservice1 |
|
||||
| user3 | moodle_mobile_app | webservicE3 |
|
||||
| user4 | siteinfo | New service2 |
|
||||
| user | service |
|
||||
| user2 | siteinfo |
|
||||
| user3 | moodle_mobile_app |
|
||||
| user4 | siteinfo |
|
||||
When I log in as "admin"
|
||||
And I navigate to "Server > Web services > Manage tokens" in site administration
|
||||
|
||||
@@ -66,20 +53,6 @@ Feature: Manage external services tokens
|
||||
And I should see "Moodle mobile web service" in the "Firstname3 Lastname3" "table_row"
|
||||
And I should see "Site information" in the "Firstname4 Lastname4" "table_row"
|
||||
|
||||
# Filter tokens by by name (case-insensitive).
|
||||
And I click on "Tokens filter" "link"
|
||||
And I set the field "Name" to "webservice"
|
||||
And I press "Show only matching tokens"
|
||||
And I should see "Site information" in the "Firstname2 Lastname2" "table_row"
|
||||
And I should see "Moodle mobile web service" in the "Firstname3 Lastname3" "table_row"
|
||||
And "Firstname4 Lastname4" "table_row" should not exist
|
||||
|
||||
# Reset the filter.
|
||||
And I press "Show all tokens"
|
||||
And I should see "Site information" in the "Firstname2 Lastname2" "table_row"
|
||||
And I should see "Moodle mobile web service" in the "Firstname3 Lastname3" "table_row"
|
||||
And I should see "Site information" in the "Firstname4 Lastname4" "table_row"
|
||||
|
||||
# Filter tokens by user (note we can select the user by the identity field here).
|
||||
When I click on "Tokens filter" "link"
|
||||
And I set the field "User" to "user2@example.com"
|
||||
|
||||
@@ -73,35 +73,27 @@ class set_plugin_order_test extends \externallib_advanced_testcase {
|
||||
* @return array
|
||||
*/
|
||||
public function execute_editor_provider(): array {
|
||||
$pluginmanager = \core_plugin_manager::instance();
|
||||
$allplugins = array_keys($pluginmanager->get_plugins_of_type('editor'));
|
||||
|
||||
// Disabled editors are listed alphabetically at the end.
|
||||
$getorder = function (array $plugins) use ($allplugins) {
|
||||
return array_merge(
|
||||
$plugins,
|
||||
array_diff($allplugins, array_values($plugins)),
|
||||
);
|
||||
};
|
||||
return [
|
||||
[
|
||||
'initialstate' => 'textarea,tiny',
|
||||
'pluginname' => 'editor_textarea',
|
||||
'direction' => 1, // DOWN.
|
||||
'expected' => $getorder([
|
||||
'expected' => [
|
||||
'tiny',
|
||||
'textarea',
|
||||
]),
|
||||
'atto',
|
||||
],
|
||||
'newtexteditors' => 'tiny,textarea',
|
||||
],
|
||||
[
|
||||
'initialstate' => 'textarea,tiny',
|
||||
'pluginname' => 'editor_textarea',
|
||||
'direction' => -1, // UP.
|
||||
'expected' => $getorder([
|
||||
'expected' => [
|
||||
'textarea',
|
||||
'tiny',
|
||||
]),
|
||||
'atto',
|
||||
],
|
||||
'newtexteditors' => 'textarea,tiny',
|
||||
],
|
||||
[
|
||||
@@ -109,10 +101,11 @@ class set_plugin_order_test extends \externallib_advanced_testcase {
|
||||
'pluginname' => 'editor_tiny',
|
||||
'direction' => 1, // DOWN.
|
||||
// Tiny is already at the bottom of the list of enabled plugins.
|
||||
'expected' => $getorder([
|
||||
'expected' => [
|
||||
'textarea',
|
||||
'tiny',
|
||||
]),
|
||||
'atto',
|
||||
],
|
||||
'newtexteditors' => 'textarea,tiny',
|
||||
],
|
||||
[
|
||||
@@ -120,10 +113,11 @@ class set_plugin_order_test extends \externallib_advanced_testcase {
|
||||
'pluginname' => 'editor_atto',
|
||||
'direction' => 1, // DOWN.
|
||||
// Atto is not enabled. Disabled editors are listed lexically after enabled editors.
|
||||
'expected' => $getorder([
|
||||
'expected' => [
|
||||
'textarea',
|
||||
'tiny',
|
||||
]),
|
||||
'atto',
|
||||
],
|
||||
'newtexteditors' => 'textarea,tiny',
|
||||
],
|
||||
];
|
||||
|
||||
@@ -46,24 +46,17 @@ class task_logs_test extends core_reportbuilder_testcase {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->generate_task_log_data(true, 3, 2, 1654038000, 1654038060);
|
||||
$this->generate_task_log_data(false, 5, 1, 1654556400, 1654556700);
|
||||
|
||||
/** @var core_reportbuilder_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
|
||||
$report = $generator->create_report(['name' => 'Tasks', 'source' => task_logs::class, 'default' => 1]);
|
||||
|
||||
$content = $this->get_custom_report_content($report->get('id'));
|
||||
$this->assertCount(2, $content);
|
||||
$this->assertCount(1, $content);
|
||||
|
||||
// Default columns are name, start time, duration, result. Sorted by start time descending.
|
||||
// Default columns are name, starttime, duration, result.
|
||||
[$name, $timestart, $duration, $result] = array_values($content[0]);
|
||||
$this->assertStringContainsString(send_schedules::class, $name);
|
||||
$this->assertEquals('7/06/22, 07:00:00', $timestart);
|
||||
$this->assertEquals('5 mins', $duration);
|
||||
$this->assertEquals('Fail', $result);
|
||||
|
||||
[$name, $timestart, $duration, $result] = array_values($content[1]);
|
||||
$this->assertStringContainsString(send_schedules::class, $name);
|
||||
$this->assertEquals('1/06/22, 07:00:00', $timestart);
|
||||
$this->assertEquals('1 min', $duration);
|
||||
$this->assertEquals('Success', $result);
|
||||
|
||||
@@ -42,8 +42,8 @@ class import_form extends moodleform {
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
|
||||
// File upload.
|
||||
$mform->addElement('filepicker', 'xmlfile', get_string('selectfile', 'tool_admin_presets'), null,
|
||||
['accepted_types' => ['.xml']]);
|
||||
$mform->addElement('filepicker', 'xmlfile',
|
||||
get_string('selectfile', 'tool_admin_presets'));
|
||||
$mform->addRule('xmlfile', null, 'required');
|
||||
|
||||
$this->add_action_buttons(true, get_string('import', 'tool_admin_presets'));
|
||||
|
||||
@@ -26,5 +26,5 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'tool_admin_presets';
|
||||
$plugin->version = 2023100900;
|
||||
$plugin->requires = 2023100400;
|
||||
$plugin->version = 2023042400;
|
||||
$plugin->requires = 2023041800;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
define("tool_analytics/log_info",["exports","core/modal","core/str"],(function(_exports,_modal,_str){var obj;
|
||||
/**
|
||||
* Shows a dialogue with info about this logs.
|
||||
*
|
||||
* @module tool_analytics/log_info
|
||||
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.loadInfo=void 0,_modal=(obj=_modal)&&obj.__esModule?obj:{default:obj};_exports.loadInfo=(id,info)=>{document.addEventListener("click",(e=>{if(!e.target.closest('[data-model-log-id="'.concat(id,'"]')))return;e.preventDefault();const bodyInfo=document.createElement("ul");info.forEach((item=>{const li=document.createElement("li");li.innerHTML=item,bodyInfo.append(li)})),_modal.default.create({title:(0,_str.get_string)("loginfo","tool_analytics"),body:bodyInfo.outerHTML,large:!0,show:!0,removeOnClose:!0})}))}}));
|
||||
* Shows a dialogue with info about this logs.
|
||||
*
|
||||
* @module tool_analytics/log_info
|
||||
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define("tool_analytics/log_info",["jquery","core/str","core/modal_factory","core/notification"],(function($,str,ModalFactory,Notification){return{loadInfo:function(id,info){var link=$('[data-model-log-id="'+id+'"]');str.get_string("loginfo","tool_analytics").then((function(langString){var bodyInfo=$("<ul>");return info.forEach((function(item){bodyInfo.append("<li>"+item+"</li>")})),bodyInfo.append("</ul>"),ModalFactory.create({title:langString,body:bodyInfo.html(),large:!0},link)})).catch(Notification.exception)}}}));
|
||||
|
||||
//# sourceMappingURL=log_info.min.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"log_info.min.js","sources":["../src/log_info.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Shows a dialogue with info about this logs.\n *\n * @module tool_analytics/log_info\n * @copyright 2017 David Monllao {@link http://www.davidmonllao.com}\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport Modal from 'core/modal';\nimport {get_string as getString} from 'core/str';\n\n/**\n * Prepares a modal info for a log's results.\n *\n * @param {Number} id\n * @param {string[]} info\n */\nexport const loadInfo = (id, info) => {\n document.addEventListener('click', (e) => {\n const link = e.target.closest(`[data-model-log-id=\"${id}\"]`);\n if (!link) {\n return;\n }\n e.preventDefault();\n const bodyInfo = document.createElement('ul');\n info.forEach((item) => {\n const li = document.createElement('li');\n li.innerHTML = item;\n bodyInfo.append(li);\n });\n\n Modal.create({\n title: getString('loginfo', 'tool_analytics'),\n body: bodyInfo.outerHTML,\n large: true,\n show: true,\n removeOnClose: true,\n });\n });\n};\n"],"names":["id","info","document","addEventListener","e","target","closest","preventDefault","bodyInfo","createElement","forEach","item","li","innerHTML","append","create","title","body","outerHTML","large","show","removeOnClose"],"mappings":";;;;;;;8JA+BwB,CAACA,GAAIC,QACzBC,SAASC,iBAAiB,SAAUC,QACnBA,EAAEC,OAAOC,sCAA+BN,iBAIrDI,EAAEG,uBACIC,SAAWN,SAASO,cAAc,MACxCR,KAAKS,SAASC,aACJC,GAAKV,SAASO,cAAc,MAClCG,GAAGC,UAAYF,KACfH,SAASM,OAAOF,sBAGdG,OAAO,CACTC,OAAO,mBAAU,UAAW,kBAC5BC,KAAMT,SAASU,UACfC,OAAO,EACPC,MAAM,EACNC,eAAe"}
|
||||
{"version":3,"file":"log_info.min.js","sources":["../src/log_info.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Shows a dialogue with info about this logs.\n *\n * @module tool_analytics/log_info\n * @copyright 2017 David Monllao {@link http://www.davidmonllao.com}\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/str', 'core/modal_factory', 'core/notification'], function($, str, ModalFactory, Notification) {\n\n return /** @alias module:tool_analytics/log_info */ {\n\n /**\n * Prepares a modal info for a log's results.\n *\n * @method loadInfo\n * @param {int} id\n * @param {string[]} info\n */\n loadInfo: function(id, info) {\n\n var link = $('[data-model-log-id=\"' + id + '\"]');\n str.get_string('loginfo', 'tool_analytics').then(function(langString) {\n\n var bodyInfo = $(\"<ul>\");\n info.forEach(function(item) {\n bodyInfo.append('<li>' + item + '</li>');\n });\n bodyInfo.append(\"</ul>\");\n\n return ModalFactory.create({\n title: langString,\n body: bodyInfo.html(),\n large: true,\n }, link);\n\n }).catch(Notification.exception);\n }\n };\n});\n"],"names":["define","$","str","ModalFactory","Notification","loadInfo","id","info","link","get_string","then","langString","bodyInfo","forEach","item","append","create","title","body","html","large","catch","exception"],"mappings":";;;;;;;AAsBAA,iCAAO,CAAC,SAAU,WAAY,qBAAsB,sBAAsB,SAASC,EAAGC,IAAKC,aAAcC,oBAEjD,CAShDC,SAAU,SAASC,GAAIC,UAEfC,KAAOP,EAAE,uBAAyBK,GAAK,MAC3CJ,IAAIO,WAAW,UAAW,kBAAkBC,MAAK,SAASC,gBAElDC,SAAWX,EAAE,eACjBM,KAAKM,SAAQ,SAASC,MAClBF,SAASG,OAAO,OAASD,KAAO,YAEpCF,SAASG,OAAO,SAETZ,aAAaa,OAAO,CACvBC,MAAON,WACPO,KAAMN,SAASO,OACfC,OAAO,GACRZ,SAEJa,MAAMjB,aAAakB"}
|
||||
@@ -5,6 +5,6 @@
|
||||
* @copyright 2017 David Monllao
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define("tool_analytics/model",["jquery","core/str","core/log","core/notification","core/modal_save_cancel","core/modal_cancel","core/modal_events","core/templates"],(function($,Str,log,Notification,ModalSaveCancel,ModalCancel,ModalEvents,Templates){var actionsList={clear:{title:{key:"clearpredictions",component:"tool_analytics"},body:{key:"clearmodelpredictions",component:"tool_analytics"}},delete:{title:{key:"delete",component:"tool_analytics"},body:{key:"deletemodelconfirmation",component:"tool_analytics"}}};return{confirmAction:function(actionId,actionType){$('[data-action-id="'+actionId+'"]').on("click",(function(ev){ev.preventDefault();var a=$(ev.currentTarget);if(void 0!==actionsList[actionType]){var wrap,reqStrings=[actionsList[actionType].title,actionsList[actionType].body];reqStrings[1].param=(wrap=$(a).closest("[data-model-name]")).length?wrap.attr("data-model-name"):(log.error("Unexpected DOM error - unable to obtain the model name"),"");var stringsPromise=Str.get_strings(reqStrings),modalPromise=ModalSaveCancel.create({});$.when(stringsPromise,modalPromise).then((function(strings,modal){return modal.setTitle(strings[0]),modal.setBody(strings[1]),modal.setSaveButtonText(strings[0]),modal.getRoot().on(ModalEvents.save,(function(){window.location.href=a.attr("href")})),modal.show(),modal})).fail(Notification.exception)}else log.error('Action "'+actionType+'" is not allowed.')}))},selectEvaluationOptions:function(actionId,trainedOnlyExternally){$('[data-action-id="'+actionId+'"]').on("click",(function(ev){ev.preventDefault();var a=$(ev.currentTarget),timeSplittingMethods=$(this).attr("data-timesplitting-methods");ModalSaveCancel.create({title:Str.get_string("evaluatemodel","tool_analytics"),body:Templates.render("tool_analytics/evaluation_options",{trainedexternally:trainedOnlyExternally,timesplittingmethods:JSON.parse(timeSplittingMethods)}),removeOnClose:!0,buttons:{save:Str.get_string("evaluate","tool_analytics")},show:!0}).then((modal=>(modal.getRoot().on(ModalEvents.save,(function(){"trainedmodel"==$("input[name='evaluationmode']:checked").val()&&a.attr("href",a.attr("href")+"&mode=trainedmodel");var timeSplittingMethod=$("#id-evaluation-timesplitting").val();a.attr("href",a.attr("href")+"×plitting="+timeSplittingMethod),window.location.href=a.attr("href")})),modal))).catch(Notification.exception)}))},selectExportOptions:function(actionId,isTrained){$('[data-action-id="'+actionId+'"]').on("click",(function(ev){ev.preventDefault();var a=$(ev.currentTarget);if(!isTrained)return a.attr("href",a.attr("href")+"&action=exportmodel&includeweights=0"),void(window.location.href=a.attr("href"));var stringsPromise=Str.get_strings([{key:"export",component:"tool_analytics"}]),modalPromise=ModalSaveCancel.create({body:Templates.render("tool_analytics/export_options",{}),removeOnClose:!0});$.when(stringsPromise,modalPromise).then((function(strings,modal){return modal.setTitle(strings[0]),modal.setSaveButtonText(strings[0]),modal.getRoot().on(ModalEvents.save,(function(){"exportdata"==$("input[name='exportoption']:checked").val()?a.attr("href",a.attr("href")+"&action=exportdata"):(a.attr("href",a.attr("href")+"&action=exportmodel"),$("#id-includeweights").is(":checked")?a.attr("href",a.attr("href")+"&includeweights=1"):a.attr("href",a.attr("href")+"&includeweights=0")),window.location.href=a.attr("href")})),modal.show(),modal})).fail(Notification.exception)}))}}}));
|
||||
define("tool_analytics/model",["jquery","core/str","core/log","core/notification","core/modal_factory","core/modal_events","core/templates"],(function($,Str,log,Notification,ModalFactory,ModalEvents,Templates){var actionsList={clear:{title:{key:"clearpredictions",component:"tool_analytics"},body:{key:"clearmodelpredictions",component:"tool_analytics"}},delete:{title:{key:"delete",component:"tool_analytics"},body:{key:"deletemodelconfirmation",component:"tool_analytics"}}};return{confirmAction:function(actionId,actionType){$('[data-action-id="'+actionId+'"]').on("click",(function(ev){ev.preventDefault();var a=$(ev.currentTarget);if(void 0!==actionsList[actionType]){var wrap,reqStrings=[actionsList[actionType].title,actionsList[actionType].body];reqStrings[1].param=(wrap=$(a).closest("[data-model-name]")).length?wrap.attr("data-model-name"):(log.error("Unexpected DOM error - unable to obtain the model name"),"");var stringsPromise=Str.get_strings(reqStrings),modalPromise=ModalFactory.create({type:ModalFactory.types.SAVE_CANCEL});$.when(stringsPromise,modalPromise).then((function(strings,modal){return modal.setTitle(strings[0]),modal.setBody(strings[1]),modal.setSaveButtonText(strings[0]),modal.getRoot().on(ModalEvents.save,(function(){window.location.href=a.attr("href")})),modal.show(),modal})).fail(Notification.exception)}else log.error('Action "'+actionType+'" is not allowed.')}))},selectEvaluationOptions:function(actionId,trainedOnlyExternally){$('[data-action-id="'+actionId+'"]').on("click",(function(ev){ev.preventDefault();var a=$(ev.currentTarget),timeSplittingMethods=$(this).attr("data-timesplitting-methods"),stringsPromise=Str.get_strings([{key:"evaluatemodel",component:"tool_analytics"},{key:"evaluate",component:"tool_analytics"}]),modalPromise=ModalFactory.create({type:ModalFactory.types.SAVE_CANCEL}),bodyPromise=Templates.render("tool_analytics/evaluation_options",{trainedexternally:trainedOnlyExternally,timesplittingmethods:JSON.parse(timeSplittingMethods)});$.when(stringsPromise,modalPromise).then((function(strings,modal){return modal.getRoot().on(ModalEvents.hidden,modal.destroy.bind(modal)),modal.setTitle(strings[0]),modal.setSaveButtonText(strings[1]),modal.setBody(bodyPromise),modal.getRoot().on(ModalEvents.save,(function(){"trainedmodel"==$("input[name='evaluationmode']:checked").val()&&a.attr("href",a.attr("href")+"&mode=trainedmodel");var timeSplittingMethod=$("#id-evaluation-timesplitting").val();a.attr("href",a.attr("href")+"×plitting="+timeSplittingMethod),window.location.href=a.attr("href")})),modal.show(),modal})).fail(Notification.exception)}))},selectExportOptions:function(actionId,isTrained){$('[data-action-id="'+actionId+'"]').on("click",(function(ev){ev.preventDefault();var a=$(ev.currentTarget);if(!isTrained)return a.attr("href",a.attr("href")+"&action=exportmodel&includeweights=0"),void(window.location.href=a.attr("href"));var stringsPromise=Str.get_strings([{key:"export",component:"tool_analytics"}]),modalPromise=ModalFactory.create({type:ModalFactory.types.SAVE_CANCEL}),bodyPromise=Templates.render("tool_analytics/export_options",{});$.when(stringsPromise,modalPromise).then((function(strings,modal){return modal.getRoot().on(ModalEvents.hidden,modal.destroy.bind(modal)),modal.setTitle(strings[0]),modal.setSaveButtonText(strings[0]),modal.setBody(bodyPromise),modal.getRoot().on(ModalEvents.save,(function(){"exportdata"==$("input[name='exportoption']:checked").val()?a.attr("href",a.attr("href")+"&action=exportdata"):(a.attr("href",a.attr("href")+"&action=exportmodel"),$("#id-includeweights").is(":checked")?a.attr("href",a.attr("href")+"&includeweights=1"):a.attr("href",a.attr("href")+"&includeweights=0")),window.location.href=a.attr("href")})),modal.show(),modal})).fail(Notification.exception)}))}}}));
|
||||
|
||||
//# sourceMappingURL=model.min.js.map
|
||||
@@ -20,35 +20,35 @@
|
||||
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
import Modal from 'core/modal';
|
||||
import {get_string as getString} from 'core/str';
|
||||
define(['jquery', 'core/str', 'core/modal_factory', 'core/notification'], function($, str, ModalFactory, Notification) {
|
||||
|
||||
/**
|
||||
* Prepares a modal info for a log's results.
|
||||
*
|
||||
* @param {Number} id
|
||||
* @param {string[]} info
|
||||
*/
|
||||
export const loadInfo = (id, info) => {
|
||||
document.addEventListener('click', (e) => {
|
||||
const link = e.target.closest(`[data-model-log-id="${id}"]`);
|
||||
if (!link) {
|
||||
return;
|
||||
return /** @alias module:tool_analytics/log_info */ {
|
||||
|
||||
/**
|
||||
* Prepares a modal info for a log's results.
|
||||
*
|
||||
* @method loadInfo
|
||||
* @param {int} id
|
||||
* @param {string[]} info
|
||||
*/
|
||||
loadInfo: function(id, info) {
|
||||
|
||||
var link = $('[data-model-log-id="' + id + '"]');
|
||||
str.get_string('loginfo', 'tool_analytics').then(function(langString) {
|
||||
|
||||
var bodyInfo = $("<ul>");
|
||||
info.forEach(function(item) {
|
||||
bodyInfo.append('<li>' + item + '</li>');
|
||||
});
|
||||
bodyInfo.append("</ul>");
|
||||
|
||||
return ModalFactory.create({
|
||||
title: langString,
|
||||
body: bodyInfo.html(),
|
||||
large: true,
|
||||
}, link);
|
||||
|
||||
}).catch(Notification.exception);
|
||||
}
|
||||
e.preventDefault();
|
||||
const bodyInfo = document.createElement('ul');
|
||||
info.forEach((item) => {
|
||||
const li = document.createElement('li');
|
||||
li.innerHTML = item;
|
||||
bodyInfo.append(li);
|
||||
});
|
||||
|
||||
Modal.create({
|
||||
title: getString('loginfo', 'tool_analytics'),
|
||||
body: bodyInfo.outerHTML,
|
||||
large: true,
|
||||
show: true,
|
||||
removeOnClose: true,
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
@@ -20,10 +20,8 @@
|
||||
* @copyright 2017 David Monllao
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define([
|
||||
'jquery', 'core/str', 'core/log', 'core/notification', 'core/modal_save_cancel',
|
||||
'core/modal_cancel', 'core/modal_events', 'core/templates'],
|
||||
function($, Str, log, Notification, ModalSaveCancel, ModalCancel, ModalEvents, Templates) {
|
||||
define(['jquery', 'core/str', 'core/log', 'core/notification', 'core/modal_factory', 'core/modal_events', 'core/templates'],
|
||||
function($, Str, log, Notification, ModalFactory, ModalEvents, Templates) {
|
||||
|
||||
/**
|
||||
* List of actions that require confirmation and confirmation message.
|
||||
@@ -95,7 +93,7 @@ define([
|
||||
reqStrings[1].param = getModelName(a);
|
||||
|
||||
var stringsPromise = Str.get_strings(reqStrings);
|
||||
var modalPromise = ModalSaveCancel.create({});
|
||||
var modalPromise = ModalFactory.create({type: ModalFactory.types.SAVE_CANCEL});
|
||||
|
||||
$.when(stringsPromise, modalPromise).then(function(strings, modal) {
|
||||
modal.setTitle(strings[0]);
|
||||
@@ -124,20 +122,32 @@ define([
|
||||
|
||||
var timeSplittingMethods = $(this).attr('data-timesplitting-methods');
|
||||
|
||||
ModalSaveCancel.create({
|
||||
title: Str.get_string('evaluatemodel', 'tool_analytics'),
|
||||
body: Templates.render('tool_analytics/evaluation_options', {
|
||||
trainedexternally: trainedOnlyExternally,
|
||||
timesplittingmethods: JSON.parse(timeSplittingMethods)
|
||||
}),
|
||||
removeOnClose: true,
|
||||
buttons: {
|
||||
save: Str.get_string('evaluate', 'tool_analytics'),
|
||||
},
|
||||
show: true,
|
||||
})
|
||||
.then((modal) => {
|
||||
var stringsPromise = Str.get_strings([
|
||||
{
|
||||
key: 'evaluatemodel',
|
||||
component: 'tool_analytics'
|
||||
}, {
|
||||
key: 'evaluate',
|
||||
component: 'tool_analytics'
|
||||
}
|
||||
]);
|
||||
var modalPromise = ModalFactory.create({type: ModalFactory.types.SAVE_CANCEL});
|
||||
var bodyPromise = Templates.render('tool_analytics/evaluation_options', {
|
||||
trainedexternally: trainedOnlyExternally,
|
||||
timesplittingmethods: JSON.parse(timeSplittingMethods)
|
||||
});
|
||||
|
||||
$.when(stringsPromise, modalPromise).then(function(strings, modal) {
|
||||
|
||||
|
||||
modal.getRoot().on(ModalEvents.hidden, modal.destroy.bind(modal));
|
||||
|
||||
modal.setTitle(strings[0]);
|
||||
modal.setSaveButtonText(strings[1]);
|
||||
modal.setBody(bodyPromise);
|
||||
|
||||
modal.getRoot().on(ModalEvents.save, function() {
|
||||
|
||||
// Evaluation mode.
|
||||
var evaluationMode = $("input[name='evaluationmode']:checked").val();
|
||||
if (evaluationMode == 'trainedmodel') {
|
||||
@@ -152,8 +162,9 @@ define([
|
||||
return;
|
||||
});
|
||||
|
||||
modal.show();
|
||||
return modal;
|
||||
}).catch(Notification.exception);
|
||||
}).fail(Notification.exception);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -185,14 +196,16 @@ define([
|
||||
component: 'tool_analytics'
|
||||
}
|
||||
]);
|
||||
var modalPromise = ModalSaveCancel.create({
|
||||
body: Templates.render('tool_analytics/export_options', {}),
|
||||
removeOnClose: true,
|
||||
});
|
||||
var modalPromise = ModalFactory.create({type: ModalFactory.types.SAVE_CANCEL});
|
||||
var bodyPromise = Templates.render('tool_analytics/export_options', {});
|
||||
|
||||
$.when(stringsPromise, modalPromise).then(function(strings, modal) {
|
||||
|
||||
modal.getRoot().on(ModalEvents.hidden, modal.destroy.bind(modal));
|
||||
|
||||
modal.setTitle(strings[0]);
|
||||
modal.setSaveButtonText(strings[0]);
|
||||
modal.setBody(bodyPromise);
|
||||
|
||||
modal.getRoot().on(ModalEvents.save, function() {
|
||||
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2023100900; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023100400; // Requires this Moodle version.
|
||||
$plugin->version = 2023042400; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023041800; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_analytics'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -34,11 +34,8 @@ Feature: Manage availability conditions
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | topics |
|
||||
And the following "activity" exists:
|
||||
| activity | page |
|
||||
| course | C1 |
|
||||
| name | P1 |
|
||||
And I log in as "admin"
|
||||
And I am on site homepage
|
||||
When I navigate to "Plugins > Availability restrictions > Manage restrictions" in site administration
|
||||
|
||||
# Check the icon is there (it should be a Hide icon, meaning is currently visible).
|
||||
@@ -54,7 +51,8 @@ Feature: Manage availability conditions
|
||||
|
||||
# OK, toggling works. Set the grade one to Hide and we'll go see if it actually worked.
|
||||
And I click on "Hide" "icon" in the "Restriction by grade" "table_row"
|
||||
And I am on the "P1" "page activity editing" page
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Page" to section "1"
|
||||
And I expand all fieldsets
|
||||
And I click on "Add restriction..." "button"
|
||||
And "Add restriction..." "dialogue" should be visible
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2023100900;
|
||||
$plugin->requires = 2023100400;
|
||||
$plugin->version = 2023042400;
|
||||
$plugin->requires = 2023041800;
|
||||
$plugin->component = 'tool_availabilityconditions';
|
||||
|
||||
@@ -58,7 +58,7 @@ Feature: Set up contextual data for tests
|
||||
And I am on the "Course 1" "groups" page
|
||||
Then I should see "Group 1"
|
||||
And I should see "Group 2"
|
||||
And I set the field "Participants tertiary navigation" to "Groupings"
|
||||
And I select "Groupings" from the "jump" singleselect
|
||||
And I should see "Grouping 1"
|
||||
And I should see "Grouping 2"
|
||||
|
||||
@@ -100,7 +100,8 @@ Feature: Set up contextual data for tests
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
When I am on the "Course 1" course page logged in as student1
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I should see "Topic 1"
|
||||
|
||||
Scenario: Add role assigns
|
||||
@@ -134,11 +135,17 @@ Feature: Set up contextual data for tests
|
||||
When I log in as "user1"
|
||||
And I am on site homepage
|
||||
Then edit mode should be available on the current page
|
||||
And I am on the "Course 1" course page logged in as user2
|
||||
And I log out
|
||||
And I log in as "user2"
|
||||
And I am on "Course 1" course homepage
|
||||
Then edit mode should be available on the current page
|
||||
And I am on the "Course 1" course page logged in as user3
|
||||
And I log out
|
||||
And I log in as "user3"
|
||||
And I am on "Course 1" course homepage
|
||||
Then edit mode should be available on the current page
|
||||
And I am on the "Course 1" course page logged in as user4
|
||||
And I log out
|
||||
And I log in as "user4"
|
||||
And I am on "Course 1" course homepage
|
||||
Then edit mode should be available on the current page
|
||||
And I log out
|
||||
And I log in as "user5"
|
||||
@@ -179,7 +186,8 @@ Feature: Set up contextual data for tests
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | grade |
|
||||
| assign | Test assignment name with scale | Test assignment description | C1 | assign1 | Test Scale 1 |
|
||||
When I am on the "Course 1" course page logged in as admin
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I should see "Test assignment name"
|
||||
# Assignment 2.2 module type is disabled by default
|
||||
# And I should see "Test assignment22 name"
|
||||
@@ -295,7 +303,9 @@ Feature: Set up contextual data for tests
|
||||
And the following "grade categories" exist:
|
||||
| fullname | course | gradecategory |
|
||||
| Grade sub category 2 | C1 | Grade category 1 |
|
||||
When I am on the "Course 1" "grades > Grader report > View" page logged in as "admin"
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
Then I should see "Grade category 1"
|
||||
And I should see "Grade sub category 2"
|
||||
|
||||
@@ -316,27 +326,29 @@ Feature: Set up contextual data for tests
|
||||
| itemname | course | gradecategory |
|
||||
| Test Grade Item 2 | C1 | Grade category 1 |
|
||||
| Test Grade Item 3 | C1 | Grade sub category 2 |
|
||||
When I am on the "Course 1" "grades > gradebook setup" page logged in as "admin"
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Setup > Gradebook setup" in the course gradebook
|
||||
Then I should see "Test Grade Item 1"
|
||||
And I click on grade item menu "Test Grade Item 1" of type "gradeitem" on "setup" page
|
||||
And I choose "Edit grade item" in the open action menu
|
||||
And I expand all fieldsets
|
||||
And I should see "Course 1"
|
||||
And I click on "Cancel" "button" in the "Edit grade item" "dialogue"
|
||||
And I press "Cancel"
|
||||
And I should see "Grade category 1"
|
||||
And I should see "Test Grade Item 2"
|
||||
And I click on grade item menu "Test Grade Item 2" of type "gradeitem" on "setup" page
|
||||
And I choose "Edit grade item" in the open action menu
|
||||
And I expand all fieldsets
|
||||
And I should see "Grade category 1"
|
||||
And I click on "Cancel" "button" in the "Edit grade item" "dialogue"
|
||||
And I press "Cancel"
|
||||
And I should see "Grade sub category 2"
|
||||
And I should see "Test Grade Item 3"
|
||||
And I click on grade item menu "Test Grade Item 3" of type "gradeitem" on "setup" page
|
||||
And I choose "Edit grade item" in the open action menu
|
||||
And I expand all fieldsets
|
||||
And I should see "Grade sub category 2"
|
||||
And I click on "Cancel" "button" in the "Edit grade item" "dialogue"
|
||||
And I press "Cancel"
|
||||
|
||||
Scenario: Add a bunch of scales
|
||||
Given the following "courses" exist:
|
||||
@@ -345,7 +357,9 @@ Feature: Set up contextual data for tests
|
||||
And the following "scales" exist:
|
||||
| name | scale |
|
||||
| Test Scale 1 | Disappointing, Good, Very good, Excellent |
|
||||
When I am on the "Course 1" "grades > scales" page logged in as admin
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Scales" in the course gradebook
|
||||
Then I should see "Test Scale 1"
|
||||
And I should see "Disappointing, Good, Very good, Excellent"
|
||||
|
||||
@@ -364,7 +378,9 @@ Feature: Set up contextual data for tests
|
||||
| Grade outcome 2 | OT2 | C1 | Test Scale 1 |
|
||||
And the following config values are set as admin:
|
||||
| enableoutcomes | 1 |
|
||||
When I am on the "Course 1" "grades > outcomes" page logged in as admin
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "More > Outcomes" in the course gradebook
|
||||
Then I should see "Grade outcome 1" in the "#addoutcomes" "css_element"
|
||||
And I should see "Grade outcome 2" in the "#removeoutcomes" "css_element"
|
||||
And I press "Manage outcomes"
|
||||
@@ -390,12 +406,14 @@ Feature: Set up contextual data for tests
|
||||
| Test Outcome Grade Item 1 | C1 | OT1 | Grade category 1 |
|
||||
And the following config values are set as admin:
|
||||
| enableoutcomes | 1 |
|
||||
When I am on the "Course 1" "grades > gradebook setup" page logged in as "admin"
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Setup > Gradebook setup" in the course gradebook
|
||||
Then I should see "Test Outcome Grade Item 1"
|
||||
And I click on grade item menu "Test Outcome Grade Item 1" of type "gradeitem" on "setup" page
|
||||
And I choose "Edit grade item" in the open action menu
|
||||
And I click on "Show more..." "link" in the "Edit outcome item" "dialogue"
|
||||
And the field "Outcome" matches value "Grade outcome 1"
|
||||
And I expand all fieldsets
|
||||
And I should see "Grade category 1" in the "Grade category" "form_row"
|
||||
And I press "Cancel"
|
||||
|
||||
@@ -406,5 +424,6 @@ Feature: Set up contextual data for tests
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| online_users | Course | C1 | course-view-* | site-pre |
|
||||
When I am on the "Course 1" course page logged in as admin
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I should see "Online users"
|
||||
|
||||
@@ -21,15 +21,12 @@ Feature: Edit capabilities
|
||||
|
||||
Scenario: Default system capabilities modification
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Users > Permissions > Define roles" in site administration
|
||||
And I click on "Edit Teacher role" "link"
|
||||
And I fill the capabilities form with the following permissions:
|
||||
And I set the following system permissions of "Teacher" role:
|
||||
| capability | permission |
|
||||
| block/mnet_hosts:myaddinstance | Allow |
|
||||
| moodle/site:messageanyuser | Inherit |
|
||||
| moodle/grade:managesharedforms | Prevent |
|
||||
| moodle/course:request | Prohibit |
|
||||
And I press "Save changes"
|
||||
When I follow "Edit Teacher role"
|
||||
Then "block/mnet_hosts:myaddinstance" capability has "Allow" permission
|
||||
And "moodle/site:messageanyuser" capability has "Not set" permission
|
||||
@@ -51,12 +48,16 @@ Feature: Edit capabilities
|
||||
And "mod/forum:addquestion" capability has "Allow" permission
|
||||
|
||||
Scenario: Module capabilities overrides
|
||||
Given the following "activity" exists:
|
||||
Given I log in as "teacher1"
|
||||
And the following "activity" exists:
|
||||
| activity | forum |
|
||||
| course | C1 |
|
||||
| idnumber | 00001 |
|
||||
| name | I'm the name |
|
||||
And I am on the "I'm the name" "forum activity" page logged in as teacher1
|
||||
| intro | I'm the introduction |
|
||||
| section | 1 |
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "I'm the name"
|
||||
And I navigate to "Permissions" in current page administration
|
||||
And I override the system permissions of "Student" role with:
|
||||
| mod/forum:deleteanypost | Prohibit |
|
||||
@@ -70,12 +71,13 @@ Feature: Edit capabilities
|
||||
|
||||
@javascript
|
||||
Scenario: Edit permissions escapes role names correctly
|
||||
When I am on the "Course 1" "renameroles" page logged in as "admin"
|
||||
When I am on the "C1" "Course" page logged in as "admin"
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Your word for 'Teacher' | Teacher >= editing |
|
||||
| Your word for 'Non-editing teacher' | Teacher < "editing" |
|
||||
| Your word for 'Student' | Studier & 'learner' |
|
||||
And I press "Save"
|
||||
And I press "Save and display"
|
||||
And I navigate to course participants
|
||||
Then I should see "Teacher >= editing (Teacher)" in the "Teacher 1" "table_row"
|
||||
And I should see "Teacher < \"editing\" (Non-editing teacher)" in the "Teaching Assistant" "table_row"
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
This files describes API changes in the tool_behat code.
|
||||
|
||||
=== 4.3 ===
|
||||
* The goutte behat mink driver has been replaced by the browserkit one because the former has been abandoned. The change should
|
||||
be completely transparent for (near) everybody. Only if you are using some custom-generated behat.yml file or other configuration
|
||||
alternatives different from the Moodle default one, then, any "goutte" browser occurrence needs to be changed to "browserkit_http"
|
||||
when configuring the behat mink extension. See MDL-78934 for more details and changes applied.
|
||||
|
||||
=== 4.2 ===
|
||||
=== 4.2.1 ===
|
||||
* Behat is initialised with Axe accessibility tests enabled by default, if you want to disable them please use the --no-axe option.
|
||||
|
||||
=== 3.7 ===
|
||||
* Behat will now look for behat step definitions in the current
|
||||
theme and any parents the theme may have.
|
||||
|
||||
=== 2.7 ===
|
||||
* Constants behat_base::cap_allow, behat_base::cap_prevent and
|
||||
behat_base::cap_prohibit have been removed in favour of the
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2023100900; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023100400; // Requires this Moodle version.
|
||||
$plugin->version = 2023042401; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023041800; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_behat'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -379,61 +379,19 @@ class brickfield_accessibility_test {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the newwindowphrases for all enabled language packs.
|
||||
* @return array of the newwindowphrases for all enabled language packs.
|
||||
*/
|
||||
public static function get_all_newwindowphrases(): array {
|
||||
// Need to process all enabled lang versions of newwindowphrases.
|
||||
return static::get_all_phrases('newwindowphrases');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the invalidlinkphrases for all enabled language packs.
|
||||
* @return array of the invalidlinkphrases for all enabled language packs.
|
||||
*/
|
||||
public static function get_all_invalidlinkphrases(): array {
|
||||
// Need to process all enabled lang versions of invalidlinkphrases.
|
||||
return static::get_all_phrases('invalidlinkphrases');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the relevant phrases for all enabled language packs.
|
||||
* @param string $stringname the language string identifier you want get the phrases for.
|
||||
* @return array of the invalidlinkphrases for all enabled language packs.
|
||||
*/
|
||||
protected static function get_all_phrases(string $stringname): array {
|
||||
$stringmgr = get_string_manager();
|
||||
$allstrings = [];
|
||||
|
||||
// Somehow, an invalid string was requested. Add exception handling for this in the future.
|
||||
if (!$stringmgr->string_exists($stringname, manager::PLUGINNAME)) {
|
||||
return $allstrings;
|
||||
}
|
||||
|
||||
// Need to process all enabled lang versions of invalidlinkphrases.
|
||||
$enabledlangs = $stringmgr->get_list_of_translations();
|
||||
$enabledlangs = get_string_manager()->get_list_of_translations();
|
||||
foreach ($enabledlangs as $lang => $value) {
|
||||
$tmpstring = (string)new \lang_string($stringname, manager::PLUGINNAME, null, $lang);
|
||||
$tmpstring = (string)new \lang_string('invalidlinkphrases', manager::PLUGINNAME, null, $lang);
|
||||
$tmplangarray = explode('|', $tmpstring);
|
||||
$allstrings = array_merge($allstrings, $tmplangarray);
|
||||
}
|
||||
// Removing duplicates if a lang is enabled, yet using default 'en' due to no relevant lang file.
|
||||
$allstrings = array_unique($allstrings);
|
||||
return $allstrings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assesses whether a string contains any readable text, which is text that
|
||||
* contains any characters other than whitespace characters.
|
||||
*
|
||||
* @param string $text
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_text_readable(string $text): bool {
|
||||
// These characters in order are a space, tab, line feed, carriage return,
|
||||
// NUL-byte, vertical tab and non-breaking space unicode character \xc2\xa0.
|
||||
$emptycharacters = " \t\n\r\0\x0B\xc2\xa0";
|
||||
return trim($text, $emptycharacters) != '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,27 +39,9 @@ class a_links_dont_open_new_window extends brickfield_accessibility_test {
|
||||
* The main check function. This is called by the parent class to actually check content.
|
||||
*/
|
||||
public function check(): void {
|
||||
|
||||
// Need to process all enabled lang versions of newwindowphrases.
|
||||
$text = brickfield_accessibility_test::get_all_newwindowphrases();
|
||||
|
||||
foreach ($this->get_all_elements('a') as $a) {
|
||||
if ($a->hasAttribute('target') && !in_array($a->getAttribute('target'), $this->allowedtargets)) {
|
||||
$phrasefound = false;
|
||||
foreach ($text as $phrase) {
|
||||
// Sanity check for readable text.
|
||||
if (!brickfield_accessibility_test::is_text_readable($phrase)) {
|
||||
break;
|
||||
}
|
||||
$pos = stripos($a->nodeValue, $phrase);
|
||||
if ($pos !== false) {
|
||||
$phrasefound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$phrasefound) {
|
||||
$this->add_report($a);
|
||||
}
|
||||
$this->add_report($a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,26 +39,9 @@ class area_dont_open_new_window extends brickfield_accessibility_test {
|
||||
* The main check function. This is called by the parent class to actually check content
|
||||
*/
|
||||
public function check(): void {
|
||||
// Need to process all enabled lang versions of newwindowphrases.
|
||||
$text = brickfield_accessibility_test::get_all_newwindowphrases();
|
||||
|
||||
foreach ($this->get_all_elements('area') as $area) {
|
||||
if ($area->hasAttribute('target') && !in_array($area->getAttribute('target'), $this->allowedtargets)) {
|
||||
$phrasefound = false;
|
||||
foreach ($text as $phrase) {
|
||||
// Sanity check for readable text.
|
||||
if (!brickfield_accessibility_test::is_text_readable($phrase)) {
|
||||
break;
|
||||
}
|
||||
$pos = stripos($area->getAttribute('alt'), $phrase);
|
||||
if ($pos !== false) {
|
||||
$phrasefound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$phrasefound) {
|
||||
$this->add_report($area);
|
||||
}
|
||||
$this->add_report($area);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ class renderer extends plugin_renderer_base {
|
||||
$label = $tool->get_toolshortname();
|
||||
}
|
||||
$tab = new tabobject($idprefix . $toolname, $link, $label);
|
||||
$tab->extraclass = isset($extraclass[$toolname]) ? $extraclass[$toolname] : null;
|
||||
$tabs[] = $tab;
|
||||
}
|
||||
return $this->render(new tabtree($tabs, $idprefix . $filter->tab));
|
||||
|
||||
@@ -93,7 +93,6 @@ $string['invalidcourseid'] = 'Invalid course, please check your input';
|
||||
$string['invalidlinkphrases'] = 'click|click here|here|more|more here|info|info here|information|information here|read more|read more here|further information|further information here|further details|further details here';
|
||||
$string['module'] = 'Module';
|
||||
$string['modulename'] = 'Name';
|
||||
$string['newwindowphrases'] = 'new window|new-window|new_window';
|
||||
$string['noerrorsfound'] = 'No common accessibility errors were found for your search parameters. Congratulations!';
|
||||
$string['norecords'] = 'No relevant records were found for your search parameters.';
|
||||
$string['notregistered'] = 'Your accessibility toolkit needs to be registered.';
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM288 96a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zM256 416c35.3 0 64-28.7 64-64c0-17.4-6.9-33.1-18.1-44.6L366 161.7c5.3-12.1-.2-26.3-12.3-31.6s-26.3 .2-31.6 12.3L257.9 288c-.6 0-1.3 0-1.9 0c-35.3 0-64 28.7-64 64s28.7 64 64 64zM176 144a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zM96 288a32 32 0 1 0 0-64 32 32 0 1 0 0 64zm352-32a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"/></svg>
|
||||
|
Before Width: | Height: | Size: 694 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-111 111-47-47c-9.4-9.4-24.6-9.4-33.9 0s-9.4 24.6 0 33.9l64 64c9.4 9.4 24.6 9.4 33.9 0L369 209z"/></svg>
|
||||
|
Before Width: | Height: | Size: 539 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 448 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M64 80c-8.8 0-16 7.2-16 16V416c0 8.8 7.2 16 16 16H384c8.8 0 16-7.2 16-16V96c0-8.8-7.2-16-16-16H64zM0 96C0 60.7 28.7 32 64 32H384c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96zM337 209L209 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L303 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/></svg>
|
||||
|
Before Width: | Height: | Size: 646 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"/></svg>
|
||||
|
Before Width: | Height: | Size: 625 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M32 32c17.7 0 32 14.3 32 32V400c0 8.8 7.2 16 16 16H480c17.7 0 32 14.3 32 32s-14.3 32-32 32H80c-44.2 0-80-35.8-80-80V64C0 46.3 14.3 32 32 32zM160 224c17.7 0 32 14.3 32 32v64c0 17.7-14.3 32-32 32s-32-14.3-32-32V256c0-17.7 14.3-32 32-32zm128-64V320c0 17.7-14.3 32-32 32s-32-14.3-32-32V160c0-17.7 14.3-32 32-32s32 14.3 32 32zm64 32c17.7 0 32 14.3 32 32v96c0 17.7-14.3 32-32 32s-32-14.3-32-32V224c0-17.7 14.3-32 32-32zM480 96V320c0 17.7-14.3 32-32 32s-32-14.3-32-32V96c0-17.7 14.3-32 32-32s32 14.3 32 32z"/></svg>
|
||||
|
Before Width: | Height: | Size: 798 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M441 58.9L453.1 71c9.4 9.4 9.4 24.6 0 33.9L424 134.1 377.9 88 407 58.9c9.4-9.4 24.6-9.4 33.9 0zM209.8 256.2L344 121.9 390.1 168 255.8 302.2c-2.9 2.9-6.5 5-10.4 6.1l-58.5 16.7 16.7-58.5c1.1-3.9 3.2-7.5 6.1-10.4zM373.1 25L175.8 222.2c-8.7 8.7-15 19.4-18.3 31.1l-28.6 100c-2.4 8.4-.1 17.4 6.1 23.6s15.2 8.5 23.6 6.1l100-28.6c11.8-3.4 22.5-9.7 31.1-18.3L487 138.9c28.1-28.1 28.1-73.7 0-101.8L474.9 25C446.8-3.1 401.2-3.1 373.1 25zM88 64C39.4 64 0 103.4 0 152V424c0 48.6 39.4 88 88 88H360c48.6 0 88-39.4 88-88V312c0-13.3-10.7-24-24-24s-24 10.7-24 24V424c0 22.1-17.9 40-40 40H88c-22.1 0-40-17.9-40-40V152c0-22.1 17.9-40 40-40H200c13.3 0 24-10.7 24-24s-10.7-24-24-24H88z"/></svg>
|
||||
|
Before Width: | Height: | Size: 962 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M448 80c8.8 0 16 7.2 16 16V415.8l-5-6.5-136-176c-4.5-5.9-11.6-9.3-19-9.3s-14.4 3.4-19 9.3L202 340.7l-30.5-42.7C167 291.7 159.8 288 152 288s-15 3.7-19.5 10.1l-80 112L48 416.3l0-.3V96c0-8.8 7.2-16 16-16H448zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zm80 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>
|
||||
|
Before Width: | Height: | Size: 650 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M448 96V224H288V96H448zm0 192V416H288V288H448zM224 224H64V96H224V224zM64 288H224V416H64V288zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64z"/></svg>
|
||||
|
Before Width: | Height: | Size: 495 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 640 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M579.8 267.7c56.5-56.5 56.5-148 0-204.5c-50-50-128.8-56.5-186.3-15.4l-1.6 1.1c-14.4 10.3-17.7 30.3-7.4 44.6s30.3 17.7 44.6 7.4l1.6-1.1c32.1-22.9 76-19.3 103.8 8.6c31.5 31.5 31.5 82.5 0 114L422.3 334.8c-31.5 31.5-82.5 31.5-114 0c-27.9-27.9-31.5-71.8-8.6-103.8l1.1-1.6c10.3-14.4 6.9-34.4-7.4-44.6s-34.4-6.9-44.6 7.4l-1.1 1.6C206.5 251.2 213 330 263 380c56.5 56.5 148 56.5 204.5 0L579.8 267.7zM60.2 244.3c-56.5 56.5-56.5 148 0 204.5c50 50 128.8 56.5 186.3 15.4l1.6-1.1c14.4-10.3 17.7-30.3 7.4-44.6s-30.3-17.7-44.6-7.4l-1.6 1.1c-32.1 22.9-76 19.3-103.8-8.6C74 372 74 321 105.5 289.5L217.7 177.2c31.5-31.5 82.5-31.5 114 0c27.9 27.9 31.5 71.8 8.6 103.9l-1.1 1.6c-10.3 14.4-6.9 34.4 7.4 44.6s34.4 6.9 44.6-7.4l1.1-1.6C433.5 260.8 427 182 377 132c-56.5-56.5-148-56.5-204.5 0L60.2 244.3z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM188.3 147.1c7.6-4.2 16.8-4.1 24.3 .5l144 88c7.1 4.4 11.5 12.1 11.5 20.5s-4.4 16.1-11.5 20.5l-144 88c-7.4 4.5-16.7 4.7-24.3 .5s-12.3-12.2-12.3-20.9V168c0-8.7 4.7-16.7 12.3-20.9z"/></svg>
|
||||
|
Before Width: | Height: | Size: 573 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M64 256V160H224v96H64zm0 64H224v96H64V320zm224 96V320H448v96H288zM448 256H288V160H448v96zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64z"/></svg>
|
||||
|
Before Width: | Height: | Size: 492 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 448 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M254 52.8C249.3 40.3 237.3 32 224 32s-25.3 8.3-30 20.8L57.8 416H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h96c17.7 0 32-14.3 32-32s-14.3-32-32-32h-1.8l18-48H303.8l18 48H320c-17.7 0-32 14.3-32 32s14.3 32 32 32h96c17.7 0 32-14.3 32-32s-14.3-32-32-32H390.2L254 52.8zM279.8 304H168.2L224 155.1 279.8 304z"/></svg>
|
||||
|
Before Width: | Height: | Size: 595 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 384 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64H64zM96 64H288c17.7 0 32 14.3 32 32v32c0 17.7-14.3 32-32 32H96c-17.7 0-32-14.3-32-32V96c0-17.7 14.3-32 32-32zm32 160a32 32 0 1 1 -64 0 32 32 0 1 1 64 0zM96 352a32 32 0 1 1 0-64 32 32 0 1 1 0 64zM64 416c0-17.7 14.3-32 32-32h96c17.7 0 32 14.3 32 32s-14.3 32-32 32H96c-17.7 0-32-14.3-32-32zM192 256a32 32 0 1 1 0-64 32 32 0 1 1 0 64zm32 64a32 32 0 1 1 -64 0 32 32 0 1 1 64 0zm64-64a32 32 0 1 1 0-64 32 32 0 1 1 0 64zm32 64a32 32 0 1 1 -64 0 32 32 0 1 1 64 0zM288 448a32 32 0 1 1 0-64 32 32 0 1 1 0 64z"/></svg>
|
||||
|
Before Width: | Height: | Size: 895 B |
@@ -87,19 +87,6 @@ EOD;
|
||||
</html>
|
||||
EOD;
|
||||
|
||||
/** @var string Html pass 4 */
|
||||
private $htmlpass4 = <<<EOD
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>A link can indicate that it will open in a new window</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="www.youtube.com" target="_blank">This is youtube (opens in a new window)</a>
|
||||
</body>
|
||||
</html>
|
||||
EOD;
|
||||
|
||||
/**
|
||||
* Test for links opening a new tab or window
|
||||
*/
|
||||
@@ -115,8 +102,5 @@ EOD;
|
||||
|
||||
$results = $this->get_checker_results($this->htmlpass3);
|
||||
$this->assertEmpty($results);
|
||||
|
||||
$results = $this->get_checker_results($this->htmlpass4);
|
||||
$this->assertEmpty($results);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,19 +87,6 @@ EOD;
|
||||
</html>
|
||||
EOD;
|
||||
|
||||
/** @var string Html pass 4 */
|
||||
private $htmlpass4 = <<<EOD
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>A link can indicate that it will open in a new window</title>
|
||||
</head>
|
||||
<body>
|
||||
<area target="_blank" alt="(opens in a new window)"></area>
|
||||
</body>
|
||||
</html>
|
||||
EOD;
|
||||
|
||||
/**
|
||||
* Test Area tags opening new window without warning
|
||||
*/
|
||||
@@ -115,8 +102,5 @@ EOD;
|
||||
|
||||
$results = $this->get_checker_results($this->htmlpass3);
|
||||
$this->assertEmpty($results);
|
||||
|
||||
$results = $this->get_checker_results($this->htmlpass4);
|
||||
$this->assertEmpty($results);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'tool_brickfield';
|
||||
$plugin->version = 2023100900;
|
||||
$plugin->requires = 2023100400;
|
||||
$plugin->version = 2023042400;
|
||||
$plugin->requires = 2023041800;
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2023100900; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023100400; // Requires this Moodle version.
|
||||
$plugin->version = 2023042400; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023041800; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_capability'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2023100900; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023100400; // Requires this Moodle version.
|
||||
$plugin->version = 2023042401; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023041800; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_cohortroles'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -9,7 +9,7 @@ menu: "main"
|
||||
|
||||
## Moodle templates
|
||||
|
||||
[Moodle templates](https://moodledev.io/docs/guides/templates) are use to write HTML and Javascript using mustache files.
|
||||
[Moodle templates](https://docs.moodle.org/dev/Templates) are use to write HTML and Javascript using mustache files.
|
||||
|
||||
If you are creating your own pages in the UI Component library you can load core templates using this (shortcode) syntax:
|
||||
|
||||
@@ -51,3 +51,4 @@ This is the result of adding the core/notification template on this page:
|
||||
"extraclasses": "foo bar"
|
||||
}
|
||||
{{< /mustache >}}
|
||||
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
---
|
||||
layout: docs
|
||||
title: "Action menus"
|
||||
description: "A reusable action menu component"
|
||||
date: 2023-07-27T10:10:00+08:00
|
||||
draft: false
|
||||
tags:
|
||||
- MDL-78665
|
||||
- "4.3"
|
||||
---
|
||||
|
||||
## How it works
|
||||
|
||||
Moodle action menus are a reusable component that can display a list of actions in a dropdown menu. They are used in many places in Moodle, including the user menu, the course administration menu, and the activity administration menu.
|
||||
|
||||
## Source files
|
||||
|
||||
- `lib/outputcomponents.php`: contains the main `action_menu`, `action_menu_link` and `pix_icon`.
|
||||
- `lib/classes/output/local/action_menu/subpanel.php`: contains the `subpanel` menu item class.
|
||||
- `lib/templates/action_menu.mustache`: contains the main template for the action menu.
|
||||
- `lib/templates/action_menu_*`: location for the legacy auxliar mustache files.
|
||||
- `lib/templates/local/action_menu/*`: location for any new auxiliar mustache files.
|
||||
|
||||
## Examples
|
||||
|
||||
<!-- markdownlint-disable-next-line MD033 -->
|
||||
<iframe src="../../../../examples/actionmenu.php" style="overflow:hidden;height:400px;width:100%;border:0" title="Moodle action menus"></iframe>
|
||||
|
||||
## Usage
|
||||
|
||||
### Rendering an action menu
|
||||
|
||||
The component output classes can render an action menu entirely in PHP. The steps to do it are:
|
||||
|
||||
1. Create an action menu instance (with or without items)
|
||||
2. (optional) Setup the action menu trigger
|
||||
3. (optional) Add items to the menu (if they are not added on creation)
|
||||
4. Render the menu.
|
||||
|
||||
The following code is a basic example of an action menu:
|
||||
|
||||
{{< php >}}
|
||||
/** @var core_renderer $output*/
|
||||
$output = $PAGE->get_renderer('core');
|
||||
|
||||
$menu = new action_menu();
|
||||
|
||||
// Add items.
|
||||
$menu->add(new action_menu_link(
|
||||
new moodle_url($PAGE->url, ['foo' => 'bar']),
|
||||
new pix_icon('t/emptystar', ''),
|
||||
'Action link example',
|
||||
false
|
||||
));
|
||||
|
||||
echo $output->render($menu);
|
||||
{{< / php >}}
|
||||
|
||||
And this is the same example but passing the items in the creation:
|
||||
|
||||
{{< php >}}
|
||||
/** @var core_renderer $output*/
|
||||
$output = $PAGE->get_renderer('core');
|
||||
|
||||
$menu = new action_menu([
|
||||
new action_menu_link(
|
||||
new moodle_url($PAGE->url, ['foo' => 'bar']),
|
||||
new pix_icon('t/emptystar', ''),
|
||||
'Action link example',
|
||||
false
|
||||
),
|
||||
]);
|
||||
|
||||
echo $output->render($menu);
|
||||
{{< / php >}}
|
||||
|
||||
### Setup the menu trigger
|
||||
|
||||
By default, the action menu trigger is a cog icon. However, the class has methods to convert it to a kebab menu or even display any arbitrary content.
|
||||
|
||||
Example of a kebab menu:
|
||||
|
||||
{{< php >}}
|
||||
/** @var core_renderer $output*/
|
||||
$output = $PAGE->get_renderer('core');
|
||||
|
||||
$menu = new action_menu();
|
||||
$menu->set_kebab_trigger(get_string('edit'), $output);
|
||||
$menu->set_additional_classes('fields-actions');
|
||||
{{< / php >}}
|
||||
|
||||
Example of a custom trigger:
|
||||
|
||||
{{< php >}}
|
||||
/** @var core_renderer $output*/
|
||||
$output = $PAGE->get_renderer('core');
|
||||
|
||||
$menu = new action_menu();
|
||||
$menu->set_menu_trigger(get_string('edit'));
|
||||
{{< / php >}}
|
||||
|
||||
### Add items
|
||||
|
||||
Items can be added as an array on creation or using the `add` method. Depending on the param passed to `add` the item can be displayed in two different locations:
|
||||
|
||||
Primary items: are displayed next to the trigger button as direct actions.
|
||||
Secondary items: are displayed inside the action menu dropdown.
|
||||
|
||||
The item location must be configured before adding the element. The following example shows different ways to add primary and secondary menu items.
|
||||
|
||||
{{< php >}}
|
||||
// Primary items examples.
|
||||
$menu->add(new action_menu_link(
|
||||
new moodle_url($PAGE->url),
|
||||
new pix_icon('t/emptystar', ''),
|
||||
'Action link example',
|
||||
true
|
||||
));
|
||||
$menu->add(new action_menu_link_primary(
|
||||
$PAGE->url,
|
||||
new pix_icon('t/emptystar', ''),
|
||||
'Action link example',
|
||||
));
|
||||
|
||||
// Secondary items examples.
|
||||
$menu->add(new action_menu_link(
|
||||
new moodle_url($PAGE->url),
|
||||
new pix_icon('t/emptystar', ''),
|
||||
'Action link example',
|
||||
false
|
||||
));
|
||||
$menu->add(new action_menu_link_secondary(
|
||||
$PAGE->url,
|
||||
new pix_icon('t/user', ''),
|
||||
'Action link example',
|
||||
));
|
||||
{{< / php >}}
|
||||
|
||||
## Types of items
|
||||
|
||||
The `add` method accepts several item types.
|
||||
|
||||
### `action_menu_link`
|
||||
|
||||
The `action_menu_link` class is the generic class for link items. It has several construct params:
|
||||
|
||||
- `moodle_url $url`: the link URL.
|
||||
- `pix_icon $icon`: an optional pix_icon. If none passed, the item will show the trigger icon or none if it is a kebab menu.
|
||||
- `string $text`: the text to display.
|
||||
- `bool $primary`: if the item is primary or secondary. By default, all items are primary.
|
||||
- `array $attributes`: an optional array of HTML attributes.
|
||||
|
||||
Two convenience classes extend `action_menu_link`:
|
||||
|
||||
- `action_menu_link_primary`: will be added as a primary item.
|
||||
- `action_menu_link_secondary`: will be added as a secondary item.
|
||||
|
||||
### `pix_icon`
|
||||
|
||||
The action menu can render `pix_icon` as primary actions. The `pix_icon` is a standard output class for generating icons in Moodle.
|
||||
|
||||
Construct params:
|
||||
|
||||
- `String $pix`: the internal icon location. For example, "t/user".
|
||||
- `String $alt`: an optional alternative text
|
||||
- `String $component`: the pix icon component. By default, only core icons from the `pix` folder will be used
|
||||
- `Array $attributes`: optional HTML attributes.
|
||||
|
||||
### `core\output\local\action_menu\subpanel`
|
||||
|
||||
The `core\output\local\action_menu` allow the `action_menu` to add items that display subpanels when hovered or clicked.
|
||||
|
||||
Construct params:
|
||||
|
||||
- `string $text`: text to display in the menu item
|
||||
- `renderable $subpanel`: the output to render inside the subpanel. This param should be renderable using the standard `output::render` method.
|
||||
- `array $attributes` optional HTML attributes
|
||||
|
||||
The following example creates a subpanel using a renderable choicelist instance:
|
||||
|
||||
{{< php >}}
|
||||
/** @var core_renderer $output*/
|
||||
$output = $PAGE->get_renderer('core');
|
||||
|
||||
// A choice list is a renderable class to outpout a user choice.
|
||||
$choice = new core\output\choicelist('Choice example');
|
||||
$choice->add_option("statusa", "Status A", [
|
||||
'url' => $PAGE->url,
|
||||
'description' => 'Status A description',
|
||||
'icon' => new pix_icon('t/user', '', ''),
|
||||
]);
|
||||
$choice->add_option("statusb", "Status B", [
|
||||
'url' => $PAGE->url,
|
||||
'description' => 'Status B description',
|
||||
'icon' => new pix_icon('t/groupv', '', ''),
|
||||
]);
|
||||
$choice->set_selected_value('statusb');
|
||||
|
||||
$menu = new action_menu();
|
||||
|
||||
// Add subpanel item.
|
||||
$menu->add(new core\output\local\action_menu\subpanel(
|
||||
'Subpanel example',
|
||||
$choice
|
||||
));
|
||||
|
||||
echo $output->render($menu);
|
||||
{{< / php >}}
|
||||
|
||||
### HTML string
|
||||
|
||||
If a plain string is added to an action_menu, the action_menu::add method will be printed as it is inside the dropdown menu (as a secondary item).
|
||||
@@ -68,15 +68,17 @@ each defined as 'MOD_PURPOSE_X', so Assessment is MOD_PURPOSE_ASSESSMENT.
|
||||
|
||||
### Purpose colours
|
||||
|
||||
The activity icon colours can be customised using the theme Boost 'Raw initial SCSS' feature. Simply copy any of these scss variables that you want to customize, change the colour value and done! There is no background colour for the 'Other' type purpose, it defaults to ```light-grey: #f8f9fa```.
|
||||
The activity icon colours can be customised using the theme Boost 'Raw initial SCSS' feature. Simply copy this array of scss colours, customise the colours and done! There is no background colour for the 'Other' type purpose, it defaults to ```light-grey: #f8f9fa```.
|
||||
|
||||
{{< highlight scss >}}
|
||||
$activity-icon-administration-bg: #5d63f6;
|
||||
$activity-icon-assessment-bg: #eb66a2;
|
||||
$activity-icon-collaboration-bg: #f7634d;
|
||||
$activity-icon-communication-bg: #11a676;
|
||||
$activity-icon-content-bg: #399be2;
|
||||
$activity-icon-interface-bg: #a378ff;
|
||||
$activity-icon-colors: (
|
||||
"administration": #5d63f6,
|
||||
"assessment": #eb00a2,
|
||||
"collaboration": #f7634d,
|
||||
"communication": #11a676,
|
||||
"content": #399be2,
|
||||
"interface": #a378ff
|
||||
);
|
||||
{{</ highlight >}}
|
||||
|
||||
### Custom activity icons
|
||||
|
||||
@@ -1,378 +0,0 @@
|
||||
---
|
||||
layout: docs
|
||||
title: "Dropdowns"
|
||||
description: "A reusable dropdown component"
|
||||
date: 2023-06-13T10:10:00+08:00
|
||||
draft: false
|
||||
tags:
|
||||
- MDL-78279
|
||||
- "4.3"
|
||||
---
|
||||
|
||||
## How it works
|
||||
|
||||
Moodle dropdowns are output components to generate elements that expand extra floating information when clicked.
|
||||
|
||||
Currently, the core comes with two prebuild dropdowns:
|
||||
|
||||
- Dropdown dialog: to display rich content inside the dropdown area.
|
||||
- Dropdown status: to display a list of available statuses
|
||||
|
||||
## Source files
|
||||
|
||||
- `lib/classes/output/local/dialog.php`: to define a dropdown dialog.
|
||||
- `lib/classes/output/local/dialog.php`: to define a dropdown dialog.
|
||||
- `lib/classes/output/choicelist.php`: generic output class to define a user choice.
|
||||
- `lib/templates/local/dropdown/dialog.mustache`
|
||||
- `lib/templates/local/dropdown/status.mustache`
|
||||
|
||||
## Usage
|
||||
|
||||
### Dropdown dialog
|
||||
|
||||
The constructor for the dropdown dialog class only requires three parameters.
|
||||
|
||||
- The button content
|
||||
- The dropdown content
|
||||
- An array of additional definitions. However, the output public methods can override all the definition values once the instance is created. Check out the examples to learn how to use them
|
||||
|
||||
The following example is the most simple example of creating a dropdown:
|
||||
|
||||
{{< php >}}
|
||||
$dialog = new core\output\local\dropdown\dialog('Open dialog button', 'Dialog content');
|
||||
echo $OUTPUT->render($dialog);
|
||||
{{< / php >}}
|
||||
|
||||
You have the option to include additional classes to the main component but also to the button itself.
|
||||
|
||||
{{< php >}}
|
||||
$dialog = new core\output\local\dropdown\dialog(
|
||||
'Open dialog',
|
||||
'Dialog content',
|
||||
[
|
||||
'classes' => 'mb-4',
|
||||
'buttonclasses' => 'btn btn-primary extraclass',
|
||||
]
|
||||
);
|
||||
echo $OUTPUT->render($dialog);
|
||||
{{< / php >}}
|
||||
|
||||
{{< mustache template="core/local/dropdown/dialog" >}}
|
||||
{
|
||||
"buttonid" : "example01",
|
||||
"buttoncontent" : "Open dialog",
|
||||
"dialogcontent" : "Dialog content",
|
||||
"buttonclasses": "btn btn-primary extraclass"
|
||||
}
|
||||
{{< /mustache >}}
|
||||
|
||||
If a specific item is floating towards the end of the page, you might consider aligning the dropdown menu to the left rather than to the right. To achieve this, you can use the POSITION constant values to set the `dropdownposition` $definition attribute or input it into the `set_position` method.
|
||||
|
||||
{{< php >}}
|
||||
$dialog = new core\output\local\dropdown\dialog('Open dialog', 'Dialog content');
|
||||
$dialog->set_position(core\output\local\dropdown\dialog::POSITION['end']);
|
||||
echo $OUTPUT->render($dialog);
|
||||
{{< / php >}}
|
||||
|
||||
By default, the dropdown width will adapt to the content. However, for long texts, there may be better scenarios. You can use the WIDTH constant values to set the `dialogwidth` $definition attribute or input it into the `set_dialog_width` method.
|
||||
|
||||
{{< php >}}
|
||||
// Big but fixed-width example.
|
||||
$dialog = new core\output\local\dropdown\dialog('Big dialog', $content);
|
||||
$dialog->set_dialog_width(core\output\local\dropdown\dialog::WIDTH['big']);
|
||||
echo $OUTPUT->render($dialog);
|
||||
|
||||
// Small width example.
|
||||
$dialog = new core\output\local\dropdown\dialog('Small dialog', $content);
|
||||
$dialog->set_dialog_width(core\output\local\dropdown\dialog::WIDTH['small']);
|
||||
echo $OUTPUT->render($dialog);
|
||||
{{< / php >}}
|
||||
|
||||
{{< mustache template="core/local/dropdown/dialog" >}}
|
||||
{
|
||||
"buttonid" : "example02",
|
||||
"buttoncontent" : "Big dialog",
|
||||
"dialogcontent" : "This is a long content for a big dialog that will be displayed in a fixed-width container.",
|
||||
"buttonclasses": "btn btn-primary extraclass",
|
||||
"dialogclasses": "dialog-big"
|
||||
}
|
||||
{{< /mustache >}}
|
||||
|
||||
### Dropdown status
|
||||
|
||||
The dropdown status is a user-choice wrapper. To create it, first, you need to create an instance of `core\output\choicelist` that will be used to generate the dropdown content data.
|
||||
|
||||
{{< php >}}
|
||||
$choice = new core\output\choicelist('Dialog content');
|
||||
$choice->add_option('option1', 'Option 1');
|
||||
$choice->add_option('option2', 'Option 2');
|
||||
$choice->add_option('option3', 'Option 3');
|
||||
$choice->set_selected_value('option2');
|
||||
|
||||
$dialog = new core\output\local\dropdown\status('Open dialog button', $choice);
|
||||
echo $OUTPUT->render($dialog);
|
||||
{{< / php >}}
|
||||
|
||||
{{< mustache template="core/local/dropdown/status" >}}
|
||||
{
|
||||
"buttonid" : "example04",
|
||||
"buttoncontent" : "Open dialog button",
|
||||
"dialogcontent" : "Dialog content",
|
||||
"choices" : {
|
||||
"hasoptions" : true,
|
||||
"options" : [
|
||||
{
|
||||
"optionid" : "option1",
|
||||
"value" : "option1",
|
||||
"name" : "Option 1",
|
||||
"hasicon" : false,
|
||||
"first" : true,
|
||||
"optionnumber" : 1,
|
||||
"optionuniqid" : "option1uniqid"
|
||||
},
|
||||
{
|
||||
"optionid" : "option2",
|
||||
"value" : "option2",
|
||||
"name" : "Option 2",
|
||||
"hasicon" : false,
|
||||
"selected" : true,
|
||||
"optionnumber" : 2,
|
||||
"optionuniqid" : "option2uniqid"
|
||||
},
|
||||
{
|
||||
"optionid" : "option3",
|
||||
"value" : "option3",
|
||||
"name" : "Option 3",
|
||||
"hasicon" : false,
|
||||
"optionnumber" : 3,
|
||||
"optionuniqid" : "option3uniqid"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
{{< /mustache >}}
|
||||
|
||||
The status dropdown is an extension of the dropdown dialog, which means that all the definitions mentioned earlier can also be applied to it.
|
||||
|
||||
- The status dropdown is also compatible with all the `core\output\choicelist` extra features like:
|
||||
- Adding additional icons and descriptions to the options
|
||||
- Disable options
|
||||
- Add links to options
|
||||
|
||||
The following example shows how to use the advanced features:
|
||||
|
||||
{{< php >}}
|
||||
$choice = new core\output\choicelist('Dialog content');
|
||||
|
||||
// Option one is a link.
|
||||
$choice->add_option('option1', 'Option 1', [
|
||||
'url' => new moodle_url('/'),
|
||||
]);
|
||||
// Option two has an icon and description.
|
||||
$choice->add_option('option2', 'Option 2', [
|
||||
'description' => 'Option 2 description',
|
||||
'icon' => new pix_icon('t/hide', 'Eye icon 2')
|
||||
]);
|
||||
// Option three is disabled.
|
||||
$choice->add_option('option3', 'Option 3', [
|
||||
'disabled' => true,
|
||||
]);
|
||||
|
||||
$choice->set_selected_value('option2');
|
||||
|
||||
$dialog = new core\output\local\dropdown\status('Open dialog button', $choice);
|
||||
echo $OUTPUT->render($dialog);
|
||||
{{< / php >}}
|
||||
|
||||
#### Sync button text with selected status
|
||||
|
||||
The status dropdown can be configured to sync the button text with the selected status.
|
||||
|
||||
To do so, you need to set the `buttonsync` $definition attribute to `true`.
|
||||
|
||||
{{< php >}}
|
||||
$choice = new core\output\choicelist();
|
||||
$choice->add_option('option1', get_string('option1', YOURPLUGIN));
|
||||
$choice->add_option('option2', get_string('option2', YOURPLUGIN));
|
||||
$choice->set_selected_value('option2');
|
||||
|
||||
// Add some attribute to select through a query selector.
|
||||
$dialog = new core\output\local\dropdown\status(
|
||||
get_string('buttontext', YOURPLUGIN),
|
||||
$choice,
|
||||
[
|
||||
'extras' => ['id' => 'mydropdown'],
|
||||
'buttonsync' => true,
|
||||
// With 'updatestatus' it will change the status when the user clicks an option
|
||||
// See "Dropdown status in update mode" section for more information.
|
||||
'updatestatus' => true,
|
||||
]
|
||||
);
|
||||
echo $OUTPUT->render($dialog);
|
||||
{{< / php >}}
|
||||
|
||||
## Javascript
|
||||
|
||||
### Controlling dropdowns
|
||||
|
||||
Both `core/local/dropdown/status` and `core/local/dropdown/status` AMD modules provide functions to:
|
||||
|
||||
- Open and close the dropdown.
|
||||
- Change the button content.
|
||||
- Get the main dropdown HTML element.
|
||||
|
||||
Both modules are object-oriented. To get the dropdown instance, the process is as follows:
|
||||
|
||||
1. Add id or data attributes to the main component to select it using a query selector.
|
||||
2. Import `getDropdownDialog` from `core/local/dropdown/dialog`, or `getDropdownStatus` from `core/local/dropdown/status`, depending on whether you use a dialogue or a status dropdown.
|
||||
3. Call `getDropdownDialog` or `getDropdownStatus` with the query selector to get the instance
|
||||
|
||||
Both classes provide the following methods:
|
||||
|
||||
- `setVisible(Boolean)` to open or close the dropdown.
|
||||
- `isVisible()` to know if it is open or closed.
|
||||
- `setButtonContent(String)` to replace the button content.
|
||||
- `getElement()`to get the main HTMLElement to add eventListeners.
|
||||
|
||||
The following example uses the module to open the dropdown when an extra button is preset:
|
||||
|
||||
```js
|
||||
import {getDropdownDialog} from 'core/local/dropdown/';
|
||||
|
||||
const dialog = getDropdownDialog('[MYDROPDOWNSELECTOR]');
|
||||
document.querySelector('[data-for="openDropdown"]').addEventListener('click', (event) => {
|
||||
event.stopPropagation();
|
||||
dialog.setVisible(true);
|
||||
});
|
||||
```
|
||||
|
||||
### Specific dropdown status methods
|
||||
|
||||
The `core/local/dropdown/status` provides extra controls for the status selector, such as:
|
||||
|
||||
- `getSelectedValue()` and `setSelectedValue(String)` to control the currently selected status.
|
||||
- `isButtonSyncEnabled()` and `setButtonSyncEnabled(Boolean)` to synchronise the button text with the selected status.
|
||||
- `isUpdateStatusEnabled()` and `setUpdateStatusEnabled(Boolean)` to control the auto-update status mode.
|
||||
|
||||
## Using dropdown status from the frontend
|
||||
|
||||
The dropdown status can operate in two different ways.
|
||||
|
||||
### Dropdown status in display only
|
||||
|
||||
The display-only is the default behaviour for any dropdown. In display-only mode, the component will show all the status values to the user, but it won't handle and click the event nor change the current status.
|
||||
|
||||
If a plugin wants to change the status value when the user clicks, it should code a custom module to:
|
||||
|
||||
1. Capture `click` event listeners to the choice items.
|
||||
2. Send the new status to the backend (using an ad-hoc webservice).
|
||||
3. If the webservice execution is ok, update the component value using the `setSelectedValue` instance method.
|
||||
|
||||
The following example shows how to render a display-only dropdown status in the backend:
|
||||
|
||||
{{< php >}}
|
||||
$choice = new core\output\choicelist('Dialog content');
|
||||
|
||||
// Add some data attributes to the choices.
|
||||
$choice->add_option(
|
||||
'option1',
|
||||
get_string('option1', YOURPLUGIN), [
|
||||
extras' => ['data-action' => 'updateActionName']
|
||||
]);
|
||||
$choice->add_option(
|
||||
'option2',
|
||||
get_string('option2', YOURPLUGIN), [
|
||||
extras' => ['data-action' => 'updateActionName']
|
||||
]);
|
||||
$choice->set_selected_value('option2');
|
||||
|
||||
// Add some attribute to select through a query selector.
|
||||
$dialog = new core\output\local\dropdown\status(
|
||||
get_string('buttontext', YOURPLUGIN),
|
||||
$choice,
|
||||
['extras' => ['id' => 'mydropdown']]
|
||||
);
|
||||
echo $OUTPUT->render($dialog);
|
||||
{{< / php >}}
|
||||
|
||||
Having this PHP code, the AMD controller could be something like:
|
||||
|
||||
```js
|
||||
import {getDropdownStatus} from 'core/local/dropdown/status';
|
||||
import {sendValueToTheBackend} from 'YOURPLUGIN/example';
|
||||
|
||||
const status = getDropdownStatus('#mydropdown');
|
||||
status.getElement().addEventListener('click', (event) => {
|
||||
const option = event.target.closest("[data-action='updateActionName']");
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if(sendValueToTheBackend(option.dataset.value)) {
|
||||
status.setSelectedValue(option.dataset.value);
|
||||
}
|
||||
} catch (error) {
|
||||
// Do some error handling here.
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Dropdown status in update mode
|
||||
|
||||
The component will act more like an HTML radio button in update mode. It will store the current status value and will trigger `change` events when the value changes.
|
||||
|
||||
In this case, the plugin controller has to:
|
||||
|
||||
1. Capture the component element `change` event. Remember that, as in radio events, the `change` event won't bubble, so it cannot be delegated to a parent element.
|
||||
2. Send the new status to the backend (using an ad-hoc webservice).
|
||||
3. If the webservice execution fails, do a value rollback using the `setSelectedValue` instance method.
|
||||
|
||||
The following example shows how to render an update mode dropdown status in the backend:
|
||||
|
||||
{{< php >}}
|
||||
$choice = new core\output\choicelist('Dialog content');
|
||||
|
||||
$choice->add_option('option1', get_string('option1', YOURPLUGIN));
|
||||
$choice->add_option('option2', get_string('option2', YOURPLUGIN));
|
||||
$choice->set_selected_value('option2');
|
||||
|
||||
// Add some attribute to select through a query selector.
|
||||
$dialog = new core\output\local\dropdown\status(
|
||||
get_string('buttontext', YOURPLUGIN),
|
||||
$choice,
|
||||
[
|
||||
'extras' => ['id' => 'mydropdown'],
|
||||
'updatestatus' => true,
|
||||
]
|
||||
);
|
||||
echo $OUTPUT->render($dialog);
|
||||
{{< / php >}}
|
||||
|
||||
Having this PHP code, the AMD controller could be something like:
|
||||
|
||||
```js
|
||||
import {getDropdownStatus} from 'core/local/dropdown/status';
|
||||
import {sendValueToTheBackend} from 'YOURPLUGIN/example';
|
||||
|
||||
const status = getDropdownStatus('#mydropdown');
|
||||
let currentValue = status.getSelectedValue();
|
||||
|
||||
status.getElement().addEventListener('change', (event) => {
|
||||
if (currentValue == status.getSelectedValue()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
sendValueToTheBackend(status.getSelectedValue());
|
||||
currentValue = status.getSelectedValue();
|
||||
} catch (error) {
|
||||
status.setSelectedValue(currentValue);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Note**: the `event.target` is also the main element. You can also get the current value from `event.target.dataset.value` if you prefer.
|
||||
|
||||
## Examples
|
||||
|
||||
<!-- markdownlint-disable-next-line MD033 -->
|
||||
<iframe src="../../../../examples/dropdowns.php" style="overflow:hidden;height:400px;width:100%;border:0" title="Moodle dynamic tabs"></iframe>
|
||||
@@ -11,7 +11,7 @@ tags:
|
||||
|
||||
## How to use moodle forms
|
||||
|
||||
Forms are constructed using lib/formslib.php. Using the addElement methods in php a set of different form element types can be added to a form. For more info visit the [Moodledocs](https://moodledev.io/docs/apis/subsystems/form) page for forms
|
||||
Forms are constructed using lib/formslib.php. Using the addElement methods in php a set of different form element types can be added to a form. For more info visit the [Moodledocs](https://docs.moodle.org/dev/lib/formslib.php_Form_Definition) page for forms
|
||||
|
||||
{{< php >}}
|
||||
$mform->addElement('button', 'intro', get_string("buttonlabel"));
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
---
|
||||
layout: docs
|
||||
title: "Show more"
|
||||
date: 2023-06-12T00:00:00+01:00
|
||||
draft: false
|
||||
weight: 70
|
||||
tags:
|
||||
- MDL-78204
|
||||
- 4.3
|
||||
---
|
||||
|
||||
## How to use
|
||||
|
||||
The show more component is used to show and hide content. It is useful for showing a preview of content and then allowing the user to expand it to see more.
|
||||
|
||||
The parameters for the template context are:
|
||||
* collapsedcontent: The content to show when collapsed.
|
||||
* expandedcontent: The content to show when expanded.
|
||||
* extraclasses: Any extra classes added to the showmore outer container.
|
||||
* buttonextraclasses: Any extra classes added to the button.
|
||||
* collapsedextraclasses: Any extra classes added to the collapsed content container.
|
||||
* expandedextraclasses: Any extra classes added to the expanded content container.
|
||||
|
||||
## Example
|
||||
|
||||
{{< mustache template="core/showmore" >}}
|
||||
{
|
||||
"collapsedcontent": "Hello...",
|
||||
"expandedcontent": "Hello<br>Is it me you're looking for? I can see it in your eyes",
|
||||
"extraclasses": "rounded p-2 border",
|
||||
"buttonextraclasses": "font-weight-bold"
|
||||
}
|
||||
{{< /mustache >}}
|
||||
|
||||
## Example used as a template block
|
||||
|
||||
{{< mustache template="tool_componentlibrary/examples/showmore/example" >}}
|
||||
{
|
||||
}
|
||||
{{< /mustache >}}
|
||||
@@ -61,7 +61,7 @@ Disabled toggle with extra classes.
|
||||
|
||||
## Use toggle as a template block
|
||||
|
||||
It is also possible to include *core/toggle* in any other template using [blocks](https://moodledev.io/docs/guides/templates#blocks), instead of rendering it with a context.
|
||||
It is also possible to include *core/toggle* in any other template using [blocks](https://docs.moodle.org/dev/Templates#Blocks), instead of rendering it with a context.
|
||||
The parameters that you can define are:
|
||||
* id: Unique id for the toggle input.
|
||||
* extraclasses: Any extra classes added to the toggle input outer container.
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Moodle Component Library
|
||||
*
|
||||
* A sample of a default action menu.
|
||||
*
|
||||
* @package tool_componentlibrary
|
||||
* @copyright 2023 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once(__DIR__ . '/../../../../config.php');
|
||||
|
||||
global $PAGE;
|
||||
|
||||
$PAGE->set_url(new moodle_url('/admin/tool/componentlibrary/examples/actionmenu.php'));
|
||||
$PAGE->set_context(context_system::instance());
|
||||
$PAGE->set_pagelayout('embedded');
|
||||
|
||||
$PAGE->set_heading('Moodle action menus');
|
||||
$PAGE->set_title('Moodle action menus');
|
||||
|
||||
/** @var core_renderer $output*/
|
||||
$output = $PAGE->get_renderer('core');
|
||||
|
||||
// Some menu items require as renderable element. This is just an
|
||||
// example of a choice list but it can be any other renderable.
|
||||
$choice = new core\output\choicelist('Choice example');
|
||||
$choice->add_option("statusa", "Status A", [
|
||||
'url' => $PAGE->url,
|
||||
'description' => 'Status A description',
|
||||
'icon' => new pix_icon('t/user', '', ''),
|
||||
]);
|
||||
$choice->add_option("statusb", "Status B", [
|
||||
'url' => $PAGE->url,
|
||||
'description' => 'Status B description',
|
||||
'icon' => new pix_icon('t/groupv', '', ''),
|
||||
]);
|
||||
$choice->set_selected_value('statusb');
|
||||
|
||||
// Those are some examples of action items.
|
||||
|
||||
// Action menu links is the most used action item.
|
||||
$basicactionlink = new action_menu_link(
|
||||
new moodle_url($PAGE->url),
|
||||
new pix_icon('t/emptystar', ''),
|
||||
'Action link example',
|
||||
false
|
||||
);
|
||||
|
||||
// Subpanels display lateral panels on hovered or clicked.
|
||||
$subpanel = new core\output\local\action_menu\subpanel(
|
||||
'Subpanel example',
|
||||
$choice
|
||||
);
|
||||
|
||||
echo $output->header();
|
||||
|
||||
echo '<p><strong>Important note:</strong> actions menus are not prepared
|
||||
to be displayed inside iframes. You may need to scroll to see the
|
||||
action menu options.</p>';
|
||||
|
||||
echo $output->heading("Action menu default example", 4);
|
||||
|
||||
$menu = new action_menu();
|
||||
|
||||
$menu->add($basicactionlink);
|
||||
$menu->add($basicactionlink);
|
||||
$menu->add($subpanel);
|
||||
$menu->add($basicactionlink);
|
||||
|
||||
echo '<div class="border m-3 p-3 d-flex flex-row">';
|
||||
echo '<div class="flex-fill">Example of default an action menu</div><div>';
|
||||
echo $OUTPUT->render($menu);
|
||||
echo '</div></div>';
|
||||
|
||||
echo $output->heading("Kebab menu example", 4);
|
||||
|
||||
$menu = new action_menu();
|
||||
$menu->set_kebab_trigger(get_string('edit'), $output);
|
||||
$menu->set_additional_classes('fields-actions');
|
||||
|
||||
$menu->add($basicactionlink);
|
||||
$menu->add($basicactionlink);
|
||||
$menu->add(new core\output\local\action_menu\subpanel(
|
||||
'Subpanel example',
|
||||
$choice
|
||||
));
|
||||
$menu->add($basicactionlink);
|
||||
|
||||
echo '<div class="border m-3 p-3 d-flex flex-row">';
|
||||
echo '<div class="flex-fill">Example of kebab menu</div><div>';
|
||||
echo $OUTPUT->render($menu);
|
||||
echo '</div></div>';
|
||||
|
||||
echo $output->heading("Custom trigger menu example", 4);
|
||||
|
||||
$menu = new action_menu();
|
||||
$menu->set_menu_trigger(get_string('edit'));
|
||||
|
||||
$menu->add($basicactionlink);
|
||||
$menu->add($basicactionlink);
|
||||
$menu->add(new core\output\local\action_menu\subpanel(
|
||||
'Subpanel example',
|
||||
$choice
|
||||
));
|
||||
$menu->add($basicactionlink);
|
||||
|
||||
echo '<div class="border m-3 p-3 d-flex flex-row">';
|
||||
echo '<div class="flex-fill">Example of kebab menu</div><div>';
|
||||
echo $OUTPUT->render($menu);
|
||||
echo '</div></div>';
|
||||
|
||||
echo $output->heading("Primary actions menu example", 4);
|
||||
|
||||
$menu = new action_menu();
|
||||
$menu->set_menu_trigger(get_string('edit'));
|
||||
|
||||
$menu->add($basicactionlink);
|
||||
$menu->add($basicactionlink);
|
||||
$menu->add(new core\output\local\action_menu\subpanel(
|
||||
'Subpanel example',
|
||||
$choice
|
||||
));
|
||||
$menu->add($basicactionlink);
|
||||
$menu->add(new action_menu_link_primary(
|
||||
$PAGE->url,
|
||||
new pix_icon('t/emptystar', ''),
|
||||
'Action link example',
|
||||
));
|
||||
$menu->add(new action_menu_link_primary(
|
||||
$PAGE->url,
|
||||
new pix_icon('t/user', ''),
|
||||
'Action link example',
|
||||
));
|
||||
|
||||
echo '<div class="border m-3 p-3 d-flex flex-row">';
|
||||
echo '<div class="flex-fill">Example of a menu with primary actions</div><div>';
|
||||
echo $OUTPUT->render($menu);
|
||||
echo '</div></div>';
|
||||
|
||||
echo $output->footer();
|
||||
@@ -1,124 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Moodle Component Library
|
||||
*
|
||||
* A sample page with dropdowns.
|
||||
*
|
||||
* @package tool_componentlibrary
|
||||
* @copyright 2023 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once(__DIR__ . '/../../../../config.php');
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/site:configview', context_system::instance());
|
||||
|
||||
global $PAGE, $OUTPUT;
|
||||
$PAGE->set_url(new moodle_url('/admin/tool/componentlibrary/examples/dropdowns.php'));
|
||||
$PAGE->set_context(context_system::instance());
|
||||
$PAGE->set_pagelayout('embedded');
|
||||
|
||||
$PAGE->set_heading('Moodle dropdowns');
|
||||
$PAGE->set_title('Moodle dropdowns');
|
||||
|
||||
/** @var core_renderer $output*/
|
||||
$output = $PAGE->get_renderer('core');
|
||||
|
||||
echo $output->header();
|
||||
|
||||
echo $output->paragraph(
|
||||
'<strong>Important note:</strong> dropdowns are not prepared
|
||||
to be displayed inside iframes. You may need to scroll to see the
|
||||
the dropdown content.'
|
||||
);
|
||||
|
||||
echo $output->heading("Dropdown dialog example", 3);
|
||||
echo '<div class="p-3">';
|
||||
|
||||
$dialog = new core\output\local\dropdown\dialog(
|
||||
'Open dialog',
|
||||
'<p>Some rich content <b>element</b>.</p>
|
||||
<ul>
|
||||
<li>Item 1 <a href="#">Link 1</a></li>
|
||||
<li>Item 2 <a href="#">Link 2</a></li>
|
||||
</ul>'
|
||||
);
|
||||
echo $OUTPUT->render($dialog);
|
||||
echo "</div>";
|
||||
|
||||
|
||||
echo $output->heading("Dropdown status example", 3);
|
||||
echo '<div class="p-3">';
|
||||
|
||||
$choice = new core\output\choicelist('Choice description text');
|
||||
|
||||
// Option one is a link.
|
||||
$choice->add_option('option1', 'Option 1', [
|
||||
'icon' => new pix_icon('t/show', 'Eye icon 1'),
|
||||
'url' => new moodle_url('/admin/tool/componentlibrary/examples/dropdowns.php'),
|
||||
]);
|
||||
// Option two has an icon and description.
|
||||
$choice->add_option('option2', 'Option 2', [
|
||||
'description' => 'Option 2 description',
|
||||
'icon' => new pix_icon('t/hide', 'Eye icon 2'),
|
||||
]);
|
||||
// Option three is disabled.
|
||||
$choice->add_option('option3', 'Option 3', [
|
||||
'description' => 'Option 3 description',
|
||||
'icon' => new pix_icon('t/stealth', 'Eye icon 3'),
|
||||
'disabled' => true,
|
||||
]);
|
||||
|
||||
$choice->set_selected_value('option2');
|
||||
|
||||
$dialog = new core\output\local\dropdown\status('Open dialog button', $choice);
|
||||
echo $OUTPUT->render($dialog);
|
||||
echo "</div>";
|
||||
|
||||
echo $output->heading("Dropdown status in update mode example", 3);
|
||||
echo '<div class="p-3">';
|
||||
|
||||
$choice = new core\output\choicelist('Choice description text');
|
||||
|
||||
$choice->add_option('option1', 'Option 1', [
|
||||
'description' => 'Option 1 description',
|
||||
'icon' => new pix_icon('t/show', 'Eye icon 1'),
|
||||
]);
|
||||
$choice->add_option('option2', 'Option 2', [
|
||||
'description' => 'Option 2 description',
|
||||
'icon' => new pix_icon('t/hide', 'Eye icon 2'),
|
||||
]);
|
||||
|
||||
$choice->set_selected_value('option2');
|
||||
|
||||
$dialog = new core\output\local\dropdown\status(
|
||||
'Open dialog button',
|
||||
$choice,
|
||||
[
|
||||
'buttonsync' => true,
|
||||
'updatestatus' => true,
|
||||
'dialogwidth' => core\output\local\dropdown\status::WIDTH['big']
|
||||
]
|
||||
);
|
||||
echo $OUTPUT->render($dialog);
|
||||
echo "</div>";
|
||||
|
||||
echo $output->footer();
|
||||
@@ -1,37 +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 <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template tool_componentlibrary/examples/showmore/example
|
||||
|
||||
Template for showmore element used as a block example
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
<div id="showmore-example">
|
||||
<h1>Show more block</h1>
|
||||
<p>This is a simple example using showmore template as a block.</p>
|
||||
{{< core/showmore }}
|
||||
{{$collapsedcontent}} Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem... {{/collapsedcontent}}
|
||||
{{$expandedcontent}}
|
||||
Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem suspendisse faucibus, nunc et pellentesque egestas, lacus ante convallis tellus, vitae iaculis lacus elit id tortor.
|
||||
Sed augue ipsum, egestas nec, vestibulum et, malesuada adipiscing, dui. Sed cursus turpis vitae tortor. Praesent turpis. Proin viverra, ligula sit amet ultrices semper, ligula arcu
|
||||
tristique sapien, a accumsan nisi mauris ac eros. Donec venenatis vulputate lorem. Vestibulum eu odio. Morbi nec metus. Vivamus euismod mauris. Vivamus elementum semper nisi.
|
||||
{{/expandedcontent}}
|
||||
{{/core/showmore }}
|
||||
</div>
|
||||
@@ -21,6 +21,6 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
$plugin->version = 2023100900; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023100400; // Requires this Moodle version.
|
||||
$plugin->version = 2023042400; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023041800; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_componentlibrary';
|
||||
|
||||
@@ -57,17 +57,13 @@ if ($action === 'checkout') {
|
||||
$progressbar = new progress_bar();
|
||||
$progressbar->create(); // prints the HTML code of the progress bar
|
||||
|
||||
echo $output->continue_button(new moodle_url("/admin/tool/customlang/{$next}.php", array('lng' => $lng)), 'get');
|
||||
echo $output->footer();
|
||||
|
||||
\core\session\manager::write_close();
|
||||
echo $OUTPUT->select_element_for_append();
|
||||
|
||||
// We may need a bit of extra execution time and memory here.
|
||||
// we may need a bit of extra execution time and memory here
|
||||
core_php_time_limit::raise(HOURSECS);
|
||||
raise_memory_limit(MEMORY_EXTRA);
|
||||
tool_customlang_utils::checkout($lng, $progressbar);
|
||||
|
||||
echo $output->continue_button(new moodle_url("/admin/tool/customlang/{$next}.php", array('lng' => $lng)), 'get');
|
||||
echo $output->footer();
|
||||
exit;
|
||||
}
|
||||
if ($action === 'checkin') {
|
||||
|
||||