commit
b5b8e566ac
|
@ -204,7 +204,7 @@ const appConfig = {
|
|||
'no-fallthrough': 'off',
|
||||
'no-invalid-this': 'error',
|
||||
'no-irregular-whitespace': 'error',
|
||||
'no-multiple-empty-lines': 'error',
|
||||
'no-multiple-empty-lines': ['error', { "max": 1 }],
|
||||
'no-new-wrappers': 'error',
|
||||
'no-sequences': 'error',
|
||||
'no-trailing-spaces': 'error',
|
||||
|
|
|
@ -2039,9 +2039,9 @@
|
|||
}
|
||||
},
|
||||
"@eslint/eslintrc": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz",
|
||||
"integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==",
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
|
||||
"integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^6.12.4",
|
||||
|
@ -2051,15 +2051,14 @@
|
|||
"ignore": "^4.0.6",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
"lodash": "^4.17.19",
|
||||
"minimatch": "^3.0.4",
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
|
||||
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
|
@ -4915,9 +4914,9 @@
|
|||
}
|
||||
},
|
||||
"astral-regex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
|
||||
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
|
||||
"integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
|
||||
"dev": true
|
||||
},
|
||||
"async": {
|
||||
|
@ -8780,13 +8779,13 @@
|
|||
}
|
||||
},
|
||||
"eslint": {
|
||||
"version": "7.10.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.10.0.tgz",
|
||||
"integrity": "sha512-BDVffmqWl7JJXqCjAK6lWtcQThZB/aP1HXSH1JKwGwv0LQEdvpR7qzNrUT487RM39B5goWuboFad5ovMBmD8yA==",
|
||||
"version": "7.21.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.21.0.tgz",
|
||||
"integrity": "sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"@eslint/eslintrc": "^0.1.3",
|
||||
"@babel/code-frame": "7.12.11",
|
||||
"@eslint/eslintrc": "^0.4.0",
|
||||
"ajv": "^6.10.0",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-spawn": "^7.0.2",
|
||||
|
@ -8795,11 +8794,11 @@
|
|||
"enquirer": "^2.3.5",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^2.1.0",
|
||||
"eslint-visitor-keys": "^1.3.0",
|
||||
"espree": "^7.3.0",
|
||||
"esquery": "^1.2.0",
|
||||
"eslint-visitor-keys": "^2.0.0",
|
||||
"espree": "^7.3.1",
|
||||
"esquery": "^1.4.0",
|
||||
"esutils": "^2.0.2",
|
||||
"file-entry-cache": "^5.0.1",
|
||||
"file-entry-cache": "^6.0.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"glob-parent": "^5.0.0",
|
||||
"globals": "^12.1.0",
|
||||
|
@ -8810,7 +8809,7 @@
|
|||
"js-yaml": "^3.13.1",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.4.1",
|
||||
"lodash": "^4.17.19",
|
||||
"lodash": "^4.17.20",
|
||||
"minimatch": "^3.0.4",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.1",
|
||||
|
@ -8819,11 +8818,20 @@
|
|||
"semver": "^7.2.1",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"strip-json-comments": "^3.1.0",
|
||||
"table": "^5.2.3",
|
||||
"table": "^6.0.4",
|
||||
"text-table": "^0.2.0",
|
||||
"v8-compile-cache": "^2.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/code-frame": {
|
||||
"version": "7.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
|
||||
"integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.10.4"
|
||||
}
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
|
@ -8841,9 +8849,9 @@
|
|||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
|
||||
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
|
@ -8859,12 +8867,6 @@
|
|||
"estraverse": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"eslint-visitor-keys": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
|
||||
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
|
||||
"dev": true
|
||||
},
|
||||
"globals": {
|
||||
"version": "12.4.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
|
||||
|
@ -9069,13 +9071,13 @@
|
|||
"dev": true
|
||||
},
|
||||
"espree": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz",
|
||||
"integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==",
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
|
||||
"integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^7.4.0",
|
||||
"acorn-jsx": "^5.2.0",
|
||||
"acorn-jsx": "^5.3.1",
|
||||
"eslint-visitor-keys": "^1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -9100,9 +9102,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"esquery": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
|
||||
"integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
|
||||
"integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"estraverse": "^5.1.0"
|
||||
|
@ -9548,12 +9550,12 @@
|
|||
}
|
||||
},
|
||||
"file-entry-cache": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
|
||||
"integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||
"integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"flat-cache": "^2.0.1"
|
||||
"flat-cache": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"file-loader": {
|
||||
|
@ -9811,31 +9813,19 @@
|
|||
"dev": true
|
||||
},
|
||||
"flat-cache": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
|
||||
"integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
|
||||
"integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"flatted": "^2.0.0",
|
||||
"rimraf": "2.6.3",
|
||||
"write": "1.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"rimraf": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
|
||||
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.1.3"
|
||||
}
|
||||
}
|
||||
"flatted": "^3.1.0",
|
||||
"rimraf": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"flatted": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
|
||||
"integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz",
|
||||
"integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==",
|
||||
"dev": true
|
||||
},
|
||||
"flush-write-stream": {
|
||||
|
@ -18084,6 +18074,12 @@
|
|||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
|
||||
"dev": true
|
||||
},
|
||||
"require-from-string": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||
"dev": true
|
||||
},
|
||||
"require-main-filename": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||
|
@ -19109,38 +19105,20 @@
|
|||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
|
||||
},
|
||||
"slice-ansi": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
|
||||
"integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
|
||||
"integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.0",
|
||||
"astral-regex": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^2.0.0"
|
||||
"ansi-styles": "^4.0.0",
|
||||
"astral-regex": "^2.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
|
@ -20297,26 +20275,71 @@
|
|||
"integrity": "sha512-3ozUwGSf5jmrhGgOXlX/O6hk1KQ28XPb7d3NiPZX267QmimuDq3TuIgnkw+vICUrGJGKWPLKmXVASnuJ3w07nw=="
|
||||
},
|
||||
"table": {
|
||||
"version": "5.4.6",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
|
||||
"integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
|
||||
"version": "6.0.7",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz",
|
||||
"integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^6.10.2",
|
||||
"lodash": "^4.17.14",
|
||||
"slice-ansi": "^2.1.0",
|
||||
"string-width": "^3.0.0"
|
||||
"ajv": "^7.0.2",
|
||||
"lodash": "^4.17.20",
|
||||
"slice-ansi": "^4.0.0",
|
||||
"string-width": "^4.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
"ajv": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.1.tgz",
|
||||
"integrity": "sha512-+nu0HDv7kNSOua9apAVc979qd932rrZeb3WOvoiD31A/p1mIE5/9bN2027pE2rOPYEdS3UHzsvof4hY+lM9/WQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^7.0.1",
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^5.1.0"
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||
"dev": true
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21384,9 +21407,9 @@
|
|||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||
},
|
||||
"v8-compile-cache": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
|
||||
"integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
|
||||
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
|
||||
"dev": true
|
||||
},
|
||||
"v8-to-istanbul": {
|
||||
|
@ -22850,15 +22873,6 @@
|
|||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"write": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
|
||||
"integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mkdirp": "^0.5.1"
|
||||
}
|
||||
},
|
||||
"write-file-atomic": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"test:ci": "NODE_ENV=testing gulp && jest -ci --runInBand --verbose",
|
||||
"test:watch": "NODE_ENV=testing gulp watch & jest --watch",
|
||||
"test:coverage": "NODE_ENV=testing gulp && jest --coverage",
|
||||
"lint": "ng lint",
|
||||
"lint": "NODE_OPTIONS=--max-old-space-size=4096 ng lint",
|
||||
"ionic:serve:before": "gulp",
|
||||
"ionic:serve": "gulp watch & ng serve",
|
||||
"ionic:build:before": "gulp"
|
||||
|
@ -138,7 +138,7 @@
|
|||
"@types/webpack-env": "^1.16.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.3.0",
|
||||
"@typescript-eslint/parser": "4.3.0",
|
||||
"eslint": "^7.6.0",
|
||||
"eslint": "^7.21.0",
|
||||
"eslint-config-prettier": "^6.12.0",
|
||||
"eslint-plugin-header": "^3.1.0",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
|
|
|
@ -26,11 +26,13 @@ import { AddonMessagesModule } from './messages/messages.module';
|
|||
import { AddonModModule } from './mod/mod.module';
|
||||
import { AddonQbehaviourModule } from './qbehaviour/qbehaviour.module';
|
||||
import { AddonQtypeModule } from './qtype/qtype.module';
|
||||
import { AddonBlogModule } from './blog/blog.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
AddonBlockModule,
|
||||
AddonBadgesModule,
|
||||
AddonBlogModule,
|
||||
AddonCalendarModule,
|
||||
AddonMessagesModule,
|
||||
AddonPrivateFilesModule,
|
||||
|
|
|
@ -20,7 +20,6 @@ import { CoreNavigator } from '@services/navigator';
|
|||
import { makeSingleton } from '@singletons';
|
||||
import { AddonBadges } from '../badges';
|
||||
|
||||
|
||||
/**
|
||||
* Handler to treat links to user participants page.
|
||||
*/
|
||||
|
|
|
@ -41,7 +41,6 @@ export class AddonBlockRecentlyAccessedItemsComponent extends CoreBlockBaseCompo
|
|||
super('AddonBlockRecentlyAccessedItemsComponent');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform the invalidate content function.
|
||||
*
|
||||
|
|
|
@ -77,7 +77,6 @@ export class AddonBlockRecentlyAccessedItemsProvider {
|
|||
}
|
||||
export const AddonBlockRecentlyAccessedItems = makeSingleton(AddonBlockRecentlyAccessedItemsProvider);
|
||||
|
||||
|
||||
/**
|
||||
* Result of WS block_recentlyaccesseditems_get_recent_items.
|
||||
*/
|
||||
|
|
|
@ -19,7 +19,6 @@ import { CoreCourseComponentsModule } from '@features/course/components/componen
|
|||
|
||||
import { AddonBlockSiteMainMenuComponent } from './sitemainmenu/sitemainmenu';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonBlockSiteMainMenuComponent,
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injector, NgModule } from '@angular/core';
|
||||
import { RouterModule, ROUTES, Routes } from '@angular/router';
|
||||
|
||||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
import { AddonBlogEntriesPage } from './pages/entries/entries';
|
||||
import { CoreCommentsComponentsModule } from '@features/comments/components/components.module';
|
||||
|
||||
import { CoreTagComponentsModule } from '@features/tag/components/components.module';
|
||||
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
|
||||
|
||||
function buildRoutes(injector: Injector): Routes {
|
||||
return [
|
||||
...buildTabMainRoutes(injector, {
|
||||
component: AddonBlogEntriesPage,
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
CoreCommentsComponentsModule,
|
||||
CoreTagComponentsModule,
|
||||
],
|
||||
exports: [RouterModule],
|
||||
providers: [
|
||||
{
|
||||
provide: ROUTES,
|
||||
multi: true,
|
||||
deps: [Injector],
|
||||
useFactory: buildRoutes,
|
||||
},
|
||||
],
|
||||
declarations: [
|
||||
AddonBlogEntriesPage,
|
||||
],
|
||||
})
|
||||
export class AddonBlogLazyModule {}
|
|
@ -0,0 +1,65 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { APP_INITIALIZER, NgModule, Type } from '@angular/core';
|
||||
import { Routes } from '@angular/router';
|
||||
import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
|
||||
import { CoreCourseIndexRoutingModule } from '@features/course/pages/index/index-routing.module';
|
||||
import { CoreCourseOptionsDelegate } from '@features/course/services/course-options-delegate';
|
||||
import { CoreMainMenuRoutingModule } from '@features/mainmenu/mainmenu-routing.module';
|
||||
import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module';
|
||||
import { CoreMainMenuDelegate } from '@features/mainmenu/services/mainmenu-delegate';
|
||||
import { CoreTagAreaDelegate } from '@features/tag/services/tag-area-delegate';
|
||||
import { CoreUserDelegate } from '@features/user/services/user-delegate';
|
||||
import { AddonBlogProvider } from './services/blog';
|
||||
import { AddonBlogCourseOptionHandler } from './services/handlers/course-option';
|
||||
import { AddonBlogIndexLinkHandler } from './services/handlers/index-link';
|
||||
import { AddonBlogMainMenuHandler, AddonBlogMainMenuHandlerService } from './services/handlers/mainmenu';
|
||||
import { AddonBlogTagAreaHandler } from './services/handlers/tag-area';
|
||||
import { AddonBlogUserHandler } from './services/handlers/user';
|
||||
|
||||
export const ADDON_BLOG_SERVICES: Type<unknown>[] = [
|
||||
AddonBlogProvider,
|
||||
];
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: AddonBlogMainMenuHandlerService.PAGE_NAME,
|
||||
loadChildren: () => import('@addons/blog/blog-lazy.module').then(m => m.AddonBlogLazyModule),
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CoreMainMenuTabRoutingModule.forChild(routes),
|
||||
CoreMainMenuRoutingModule.forChild({ children: routes }),
|
||||
CoreCourseIndexRoutingModule.forChild({ children: routes }),
|
||||
],
|
||||
exports: [CoreMainMenuRoutingModule],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => async () => {
|
||||
CoreContentLinksDelegate.registerHandler(AddonBlogIndexLinkHandler.instance);
|
||||
CoreMainMenuDelegate.registerHandler(AddonBlogMainMenuHandler.instance);
|
||||
CoreUserDelegate.registerHandler(AddonBlogUserHandler.instance);
|
||||
CoreTagAreaDelegate.registerHandler(AddonBlogTagAreaHandler.instance);
|
||||
CoreCourseOptionsDelegate.registerHandler(AddonBlogCourseOptionHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AddonBlogModule {}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"blog": "Blog",
|
||||
"blogentries": "Blog entries",
|
||||
"errorloadentries": "Error loading blog entries.",
|
||||
"linktooriginalentry": "Link to original blog entry",
|
||||
"noentriesyet": "No visible entries here",
|
||||
"publishtonoone": "Yourself (draft)",
|
||||
"publishtosite": "Anyone on this site",
|
||||
"publishtoworld": "Anyone in the world",
|
||||
"showonlyyourentries": "Show only your entries",
|
||||
"siteblogheading": "Site blog"
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>{{ title | translate }}</ion-title>
|
||||
<ion-buttons slot="end"></ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refresh($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||
<ion-item *ngIf="showMyEntriesToggle">
|
||||
<ion-label>{{ 'addon.blog.showonlyyourentries' | translate }}</ion-label>
|
||||
<ion-toggle [(ngModel)]="onlyMyEntries" (ionChange)="onlyMyEntriesToggleChanged(onlyMyEntries)"></ion-toggle>
|
||||
</ion-item>
|
||||
<core-empty-box *ngIf="entries && entries.length == 0" icon="far-newspaper"
|
||||
[message]="'addon.blog.noentriesyet' | translate">
|
||||
</core-empty-box>
|
||||
<ng-container *ngFor="let entry of entries">
|
||||
<ion-card *ngIf="!onlyMyEntries || entry.userid == currentUserId">
|
||||
<ion-item class="ion-text-wrap">
|
||||
<core-user-avatar [user]="entry.user" slot="start" [courseId]="entry.courseid"></core-user-avatar>
|
||||
<ion-label>
|
||||
<h2>
|
||||
<core-format-text [text]="entry.subject" [contextLevel]="contextLevel"
|
||||
[contextInstanceId]="contextInstanceId">
|
||||
</core-format-text>
|
||||
<ion-note class="ion-float-end ion-padding-left ion-text-end">
|
||||
{{ 'addon.blog.' + entry.publishTranslated! | translate}}
|
||||
</ion-note>
|
||||
</h2>
|
||||
<p>
|
||||
<ion-note class="ion-float-end ion-padding-left ion-text-end">
|
||||
{{entry.created | coreDateDayOrTime}}
|
||||
</ion-note>
|
||||
{{entry.user && entry.user!.fullname}}
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-card-content>
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
<core-format-text [text]="entry.summary" [component]="this.component" [componentId]="entry.id"
|
||||
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId">
|
||||
</core-format-text>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap" *ngIf="tagsEnabled && entry.tags && entry.tags!.length > 0">
|
||||
<ion-label>
|
||||
<div slot="start">{{ 'core.tag.tags' | translate }}:</div>
|
||||
<core-tag-list [tags]="entry.tags"></core-tag-list>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item *ngIf="commentsEnabled" detail>
|
||||
<ion-label>
|
||||
<core-comments [component]="this.component" [itemId]="entry.id" area="format_blog"
|
||||
[instanceId]="entry.userid" contextLevel="user">
|
||||
</core-comments>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<core-file *ngFor="let file of entry.attachmentfiles" [file]="file" [component]="this.component"
|
||||
[componentId]="entry.id">
|
||||
</core-file>
|
||||
<ion-item *ngIf="entry.uniquehash" [href]="entry.uniquehash" core-link>
|
||||
<ion-label>{{ 'addon.blog.linktooriginalentry' | translate }}</ion-label>
|
||||
</ion-item>
|
||||
</ion-card-content>
|
||||
<ion-row class="ion-text-center">
|
||||
<ion-col *ngIf="entry.lastmodified > entry.created">
|
||||
<ion-note>
|
||||
<ion-icon name="fas-clock"></ion-icon> {{entry.lastmodified | coreTimeAgo}}
|
||||
</ion-note>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-card>
|
||||
</ng-container>
|
||||
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMore($event)" [error]="loadMoreError"></core-infinite-loading>
|
||||
</core-loading>
|
||||
</ion-content>
|
|
@ -0,0 +1,288 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { ContextLevel } from '@/core/constants';
|
||||
import { AddonBlog, AddonBlogFilter, AddonBlogPost, AddonBlogProvider } from '@addons/blog/services/blog';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { CoreComments } from '@features/comments/services/comments';
|
||||
import { CoreTag } from '@features/tag/services/tag';
|
||||
import { CoreUser, CoreUserProfile } from '@features/user/services/user';
|
||||
import { IonRefresher } from '@ionic/angular';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
|
||||
/**
|
||||
* Page that displays the list of blog entries.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'page-addon-blog-entries',
|
||||
templateUrl: 'entries.html',
|
||||
})
|
||||
export class AddonBlogEntriesPage implements OnInit {
|
||||
|
||||
title = '';
|
||||
|
||||
protected filter: AddonBlogFilter = {};
|
||||
protected pageLoaded = 0;
|
||||
protected userPageLoaded = 0;
|
||||
protected canLoadMoreEntries = false;
|
||||
protected canLoadMoreUserEntries = true;
|
||||
protected siteHomeId: number;
|
||||
|
||||
loaded = false;
|
||||
canLoadMore = false;
|
||||
loadMoreError = false;
|
||||
entries: AddonBlogPostFormatted[] = [];
|
||||
currentUserId: number;
|
||||
showMyEntriesToggle = false;
|
||||
onlyMyEntries = false;
|
||||
component = AddonBlogProvider.COMPONENT;
|
||||
commentsEnabled = false;
|
||||
tagsEnabled = false;
|
||||
contextLevel: ContextLevel = ContextLevel.SYSTEM;
|
||||
contextInstanceId = 0;
|
||||
|
||||
constructor() {
|
||||
this.currentUserId = CoreSites.getCurrentSiteUserId();
|
||||
this.siteHomeId = CoreSites.getCurrentSiteHomeId();
|
||||
}
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
const userId = CoreNavigator.getRouteNumberParam('userId');
|
||||
const courseId = CoreNavigator.getRouteNumberParam('courseId');
|
||||
const cmId = CoreNavigator.getRouteNumberParam('cmId');
|
||||
const entryId = CoreNavigator.getRouteNumberParam('entryId');
|
||||
const groupId = CoreNavigator.getRouteNumberParam('groupId');
|
||||
const tagId = CoreNavigator.getRouteNumberParam('tagId');
|
||||
|
||||
if (!userId && !courseId && !cmId && !entryId && !groupId && !tagId) {
|
||||
this.title = 'addon.blog.siteblogheading';
|
||||
} else {
|
||||
this.title = 'addon.blog.blogentries';
|
||||
}
|
||||
|
||||
if (userId) {
|
||||
this.filter.userid = userId;
|
||||
}
|
||||
this.showMyEntriesToggle = !userId;
|
||||
|
||||
if (courseId) {
|
||||
this.filter.courseid = courseId;
|
||||
}
|
||||
|
||||
if (cmId) {
|
||||
this.filter.cmid = cmId;
|
||||
}
|
||||
|
||||
if (entryId) {
|
||||
this.filter.entryid = entryId;
|
||||
}
|
||||
|
||||
if (groupId) {
|
||||
this.filter.groupid = groupId;
|
||||
}
|
||||
|
||||
if (tagId) {
|
||||
this.filter.tagid = tagId;
|
||||
}
|
||||
|
||||
// Calculate the context level.
|
||||
if (userId && !courseId && !cmId) {
|
||||
this.contextLevel = ContextLevel.USER;
|
||||
this.contextInstanceId = userId;
|
||||
} else if (courseId && courseId != this.siteHomeId) {
|
||||
this.contextLevel = ContextLevel.COURSE;
|
||||
this.contextInstanceId = courseId;
|
||||
} else {
|
||||
this.contextLevel = ContextLevel.SYSTEM;
|
||||
this.contextInstanceId = 0;
|
||||
}
|
||||
|
||||
this.commentsEnabled = !CoreComments.areCommentsDisabledInSite();
|
||||
this.tagsEnabled = CoreTag.areTagsAvailableInSite();
|
||||
|
||||
await this.fetchEntries();
|
||||
|
||||
CoreUtils.ignoreErrors(AddonBlog.logView(this.filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch blog entries.
|
||||
*
|
||||
* @param refresh Empty events array first.
|
||||
* @return Promise with the entries.
|
||||
*/
|
||||
protected async fetchEntries(refresh: boolean = false): Promise<void> {
|
||||
this.loadMoreError = false;
|
||||
|
||||
if (refresh) {
|
||||
this.pageLoaded = 0;
|
||||
this.userPageLoaded = 0;
|
||||
}
|
||||
|
||||
const loadPage = this.onlyMyEntries ? this.userPageLoaded : this.pageLoaded;
|
||||
|
||||
try {
|
||||
const result = await AddonBlog.getEntries(this.filter, loadPage);
|
||||
|
||||
const promises = result.entries.map(async (entry: AddonBlogPostFormatted) => {
|
||||
switch (entry.publishstate) {
|
||||
case 'draft':
|
||||
entry.publishTranslated = 'publishtonoone';
|
||||
break;
|
||||
case 'site':
|
||||
entry.publishTranslated = 'publishtosite';
|
||||
break;
|
||||
case 'public':
|
||||
entry.publishTranslated = 'publishtoworld';
|
||||
break;
|
||||
default:
|
||||
entry.publishTranslated = 'privacy:unknown';
|
||||
break;
|
||||
}
|
||||
|
||||
// Calculate the context. This code was inspired by calendar events, Moodle doesn't do this for blogs.
|
||||
if (entry.moduleid || entry.coursemoduleid) {
|
||||
entry.contextLevel = ContextLevel.MODULE;
|
||||
entry.contextInstanceId = entry.moduleid || entry.coursemoduleid;
|
||||
} else if (entry.courseid) {
|
||||
entry.contextLevel = ContextLevel.COURSE;
|
||||
entry.contextInstanceId = entry.courseid;
|
||||
} else {
|
||||
entry.contextLevel = ContextLevel.USER;
|
||||
entry.contextInstanceId = entry.userid;
|
||||
}
|
||||
|
||||
entry.summary = CoreTextUtils.instance.replacePluginfileUrls(entry.summary, entry.summaryfiles || []);
|
||||
|
||||
return CoreUser.getProfile(entry.userid, entry.courseid, true).then((user) => {
|
||||
entry.user = user;
|
||||
|
||||
return;
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
});
|
||||
|
||||
if (refresh) {
|
||||
this.entries = result.entries;
|
||||
} else {
|
||||
this.entries = CoreUtils.uniqueArray(this.entries
|
||||
.concat(result.entries), 'id')
|
||||
.sort((a, b) => b.created - a.created);
|
||||
}
|
||||
|
||||
if (this.onlyMyEntries) {
|
||||
const count = this.entries.filter((entry) => entry.userid == this.currentUserId).length;
|
||||
this.canLoadMoreUserEntries = result.totalentries > count;
|
||||
this.canLoadMore = this.canLoadMoreUserEntries;
|
||||
this.userPageLoaded++;
|
||||
} else {
|
||||
this.canLoadMoreEntries = result.totalentries > this.entries.length;
|
||||
this.canLoadMore = this.canLoadMoreEntries;
|
||||
this.pageLoaded++;
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'addon.blog.errorloadentries', true);
|
||||
this.loadMoreError = true; // Set to prevent infinite calls with infinite-loading.
|
||||
} finally {
|
||||
this.loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle between showing only my entries or not.
|
||||
*
|
||||
* @param enabled If true, filter my entries. False otherwise.
|
||||
*/
|
||||
onlyMyEntriesToggleChanged(enabled: boolean): void {
|
||||
this.canLoadMore = enabled ? this.canLoadMoreUserEntries : this.canLoadMoreEntries;
|
||||
|
||||
if (!enabled) {
|
||||
delete this.filter.userid;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const count = this.entries.filter((entry) => entry.userid == this.currentUserId).length;
|
||||
this.userPageLoaded = Math.floor(count / AddonBlogProvider.ENTRIES_PER_PAGE);
|
||||
this.filter.userid = this.currentUserId;
|
||||
|
||||
if (count == 0 && this.canLoadMoreUserEntries) {
|
||||
// First time but no entry loaded. Try to load some.
|
||||
this.loadMore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to load more entries.
|
||||
*
|
||||
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
|
||||
* @return Resolved when done.
|
||||
*/
|
||||
loadMore(infiniteComplete?: () => void): Promise<void> {
|
||||
return this.fetchEntries().finally(() => {
|
||||
infiniteComplete && infiniteComplete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh blog entries on PTR.
|
||||
*
|
||||
* @param refresher Refresher instance.
|
||||
*/
|
||||
refresh(refresher?: CustomEvent<IonRefresher>): void {
|
||||
const promises = this.entries.map((entry) =>
|
||||
CoreComments.invalidateCommentsData('user', entry.userid, this.component, entry.id, 'format_blog'));
|
||||
|
||||
promises.push(AddonBlog.invalidateEntries(this.filter));
|
||||
|
||||
if (this.showMyEntriesToggle) {
|
||||
this.filter['userid'] = this.currentUserId;
|
||||
promises.push(AddonBlog.invalidateEntries(this.filter));
|
||||
|
||||
if (!this.onlyMyEntries) {
|
||||
delete this.filter['userid'];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CoreUtils.allPromises(promises).finally(() => {
|
||||
this.fetchEntries(true).finally(() => {
|
||||
if (refresher) {
|
||||
refresher?.detail.complete();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Blog post with some calculated data.
|
||||
*/
|
||||
type AddonBlogPostFormatted = AddonBlogPost & {
|
||||
publishTranslated?: string; // Calculated in the app. Key of the string to translate the publish state of the post.
|
||||
user?: CoreUserProfile; // Calculated in the app. Data of the user that wrote the post.
|
||||
contextLevel?: string; // Calculated in the app. The context level of the entry.
|
||||
contextInstanceId?: number; // Calculated in the app. The context instance id.
|
||||
};
|
|
@ -0,0 +1,204 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||
import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
|
||||
import { CoreTagItem } from '@features/tag/services/tag';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
const ROOT_CACHE_KEY = 'addonBlog:';
|
||||
|
||||
/**
|
||||
* Service to handle blog entries.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonBlogProvider {
|
||||
|
||||
static readonly ENTRIES_PER_PAGE = 10;
|
||||
static readonly COMPONENT = 'blog';
|
||||
|
||||
/**
|
||||
* Returns whether or not the blog plugin is enabled for a certain site.
|
||||
*
|
||||
* This method is called quite often and thus should only perform a quick
|
||||
* check, we should not be calling WS from here.
|
||||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with true if enabled, resolved with false or rejected otherwise.
|
||||
*/
|
||||
async isPluginEnabled(siteId?: string): Promise<boolean> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
return site.wsAvailable('core_blog_get_entries') &&site.canUseAdvancedFeature('enableblogs');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cache key for the blog entries.
|
||||
*
|
||||
* @param filter Filter to apply on search.
|
||||
* @return Cache key.
|
||||
*/
|
||||
getEntriesCacheKey(filter: AddonBlogFilter = {}): string {
|
||||
return ROOT_CACHE_KEY + CoreUtils.sortAndStringify(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blog entries.
|
||||
*
|
||||
* @param filter Filter to apply on search.
|
||||
* @param page Page of the blog entries to fetch.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise to be resolved when the entries are retrieved.
|
||||
*/
|
||||
async getEntries(filter: AddonBlogFilter = {}, page: number = 0, siteId?: string): Promise<CoreBlogGetEntriesWSResponse> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
const data: CoreBlogGetEntriesWSParams = {
|
||||
filters: CoreUtils.objectToArrayOfObjects(filter, 'name', 'value'),
|
||||
page: page,
|
||||
perpage: AddonBlogProvider.ENTRIES_PER_PAGE,
|
||||
};
|
||||
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getEntriesCacheKey(filter),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
};
|
||||
|
||||
return site.read('core_blog_get_entries', data, preSets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate blog entries WS call.
|
||||
*
|
||||
* @param filter Filter to apply on search
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved when data is invalidated.
|
||||
*/
|
||||
async invalidateEntries(filter: AddonBlogFilter = {}, siteId?: string): Promise<void> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
await site.invalidateWsCacheForKey(this.getEntriesCacheKey(filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger the blog_entries_viewed event.
|
||||
*
|
||||
* @param filter Filter to apply on search.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise to be resolved when done.
|
||||
*/
|
||||
async logView(filter: AddonBlogFilter = {}, siteId?: string): Promise<CoreStatusWithWarningsWSResponse> {
|
||||
CorePushNotifications.logViewListEvent('blog', 'core_blog_view_entries', filter, siteId);
|
||||
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
const data: AddonBlogViewEntriesWSParams = {
|
||||
filters: CoreUtils.objectToArrayOfObjects(filter, 'name', 'value'),
|
||||
};
|
||||
|
||||
return site.write('core_blog_view_entries', data);
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonBlog = makeSingleton(AddonBlogProvider);
|
||||
|
||||
/**
|
||||
* Params of core_blog_get_entries WS.
|
||||
*/
|
||||
type CoreBlogGetEntriesWSParams = {
|
||||
filters?: { // Parameters to filter blog listings.
|
||||
name: string; // The expected keys (value format) are:
|
||||
// tag PARAM_NOTAGS blog tag
|
||||
// tagid PARAM_INT blog tag id
|
||||
// userid PARAM_INT blog author (userid)
|
||||
// cmid PARAM_INT course module id
|
||||
// entryid PARAM_INT entry id
|
||||
// groupid PARAM_INT group id
|
||||
// courseid PARAM_INT course id
|
||||
// search PARAM_RAW search term.
|
||||
value: string; // The value of the filter.
|
||||
}[];
|
||||
page?: number; // The blog page to return.
|
||||
perpage?: number; // The number of posts to return per page.
|
||||
};
|
||||
|
||||
/**
|
||||
* Data returned by core_blog_get_entries WS.
|
||||
*/
|
||||
export type CoreBlogGetEntriesWSResponse = {
|
||||
entries: AddonBlogPost[];
|
||||
totalentries: number; // The total number of entries found.
|
||||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Data returned by blog's post_exporter.
|
||||
*/
|
||||
export type AddonBlogPost = {
|
||||
id: number; // Post/entry id.
|
||||
module: string; // Where it was published the post (blog, blog_external...).
|
||||
userid: number; // Post author.
|
||||
courseid: number; // Course where the post was created.
|
||||
groupid: number; // Group post was created for.
|
||||
moduleid: number; // Module id where the post was created (not used anymore).
|
||||
coursemoduleid: number; // Course module id where the post was created.
|
||||
subject: string; // Post subject.
|
||||
summary: string; // Post summary.
|
||||
summaryformat?: number; // Summary format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
content: string; // Post content.
|
||||
uniquehash: string; // Post unique hash.
|
||||
rating: number; // Post rating.
|
||||
format: number; // Post content format.
|
||||
attachment: string; // Post atachment.
|
||||
publishstate: string; // Post publish state.
|
||||
lastmodified: number; // When it was last modified.
|
||||
created: number; // When it was created.
|
||||
usermodified: number; // User that updated the post.
|
||||
summaryfiles: CoreWSExternalFile[]; // Summaryfiles.
|
||||
attachmentfiles?: CoreWSExternalFile[]; // Attachmentfiles.
|
||||
tags?: CoreTagItem[]; // @since 3.7. Tags.
|
||||
};
|
||||
|
||||
/**
|
||||
* Params of core_blog_view_entries WS.
|
||||
*/
|
||||
type AddonBlogViewEntriesWSParams = {
|
||||
filters?: { // Parameters used in the filter of view_entries.
|
||||
name: string; // The expected keys (value format) are:
|
||||
// tag PARAM_NOTAGS blog tag
|
||||
// tagid PARAM_INT blog tag id
|
||||
// userid PARAM_INT blog author (userid)
|
||||
// cmid PARAM_INT course module id
|
||||
// entryid PARAM_INT entry id
|
||||
// groupid PARAM_INT group id
|
||||
// courseid PARAM_INT course id
|
||||
// search PARAM_RAW search term.
|
||||
value: string; // The value of the filter.
|
||||
}[];
|
||||
};
|
||||
|
||||
export type AddonBlogFilter = {
|
||||
tag?: string; // Blog tag
|
||||
tagid?: number; // Blog tag id
|
||||
userid?: number; // Blog author (userid)
|
||||
cmid?: number; // Course module id
|
||||
entryid?: number; // Entry id
|
||||
groupid?: number; // Group id
|
||||
courseid?: number; // Course id
|
||||
search?: string; // Search term.
|
||||
};
|
|
@ -0,0 +1,109 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreCourse } from '@features/course/services/course';
|
||||
import { CoreCourseHelper } from '@features/course/services/course-helper';
|
||||
import {
|
||||
CoreCourseAccess,
|
||||
CoreCourseOptionsHandler,
|
||||
CoreCourseOptionsHandlerData,
|
||||
} from '@features/course/services/course-options-delegate';
|
||||
import { CoreCourseUserAdminOrNavOptionIndexed } from '@features/courses/services/courses';
|
||||
import { CoreEnrolledCourseDataWithExtraInfoAndOptions } from '@features/courses/services/courses-helper';
|
||||
import { CoreFilepool } from '@services/filepool';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreWSExternalFile } from '@services/ws';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonBlog } from '../blog';
|
||||
import { AddonBlogMainMenuHandlerService } from './mainmenu';
|
||||
|
||||
/**
|
||||
* Course nav handler.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonBlogCourseOptionHandlerService implements CoreCourseOptionsHandler {
|
||||
|
||||
name = 'AddonBlog';
|
||||
priority = 100;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
invalidateEnabledForCourse(courseId: number): Promise<void> {
|
||||
return CoreCourse.invalidateCourseBlocks(courseId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
isEnabled(): Promise<boolean> {
|
||||
return AddonBlog.isPluginEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabledForCourse(
|
||||
courseId: number,
|
||||
accessData: CoreCourseAccess,
|
||||
navOptions?: CoreCourseUserAdminOrNavOptionIndexed,
|
||||
): Promise<boolean> {
|
||||
const enabled = await CoreCourseHelper.hasABlockNamed(courseId, 'blog_menu');
|
||||
|
||||
if (enabled && navOptions && typeof navOptions.blogs != 'undefined') {
|
||||
return navOptions.blogs;
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getDisplayData(): CoreCourseOptionsHandlerData | Promise<CoreCourseOptionsHandlerData> {
|
||||
return {
|
||||
title: 'addon.blog.blog',
|
||||
class: 'addon-blog-handler',
|
||||
page: AddonBlogMainMenuHandlerService.PAGE_NAME,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async prefetch(course: CoreEnrolledCourseDataWithExtraInfoAndOptions): Promise<void> {
|
||||
const siteId = CoreSites.getCurrentSiteId();
|
||||
|
||||
const result = await AddonBlog.getEntries({ courseid: course.id });
|
||||
|
||||
await Promise.all(result.entries.map(async (entry) => {
|
||||
let files: CoreWSExternalFile[] = [];
|
||||
|
||||
if (entry.attachmentfiles && entry.attachmentfiles.length) {
|
||||
files = entry.attachmentfiles;
|
||||
}
|
||||
|
||||
if (entry.summaryfiles && entry.summaryfiles.length) {
|
||||
files = files.concat(entry.summaryfiles);
|
||||
}
|
||||
|
||||
if (files.length > 0) {
|
||||
await CoreFilepool.addFilesToQueue(siteId, files, entry.module, entry.id);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonBlogCourseOptionHandler = makeSingleton(AddonBlogCourseOptionHandlerService);
|
|
@ -0,0 +1,61 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Params } from '@angular/router';
|
||||
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
|
||||
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonBlog } from '../blog';
|
||||
|
||||
/**
|
||||
* Handler to treat links to blog page.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonBlogIndexLinkHandlerService extends CoreContentLinksHandlerBase {
|
||||
|
||||
name = 'AddonBlogIndexLinkHandler';
|
||||
featureName = 'CoreUserDelegate_AddonBlog:blogs';
|
||||
pattern = /\/blog\/index\.php/;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getActions(siteIds: string[], url: string, params: Record<string, string>): CoreContentLinksAction[] {
|
||||
const pageParams: Params = {};
|
||||
|
||||
params.userid ? pageParams['userId'] = parseInt(params.userid, 10) : null;
|
||||
params.modid ? pageParams['cmId'] = parseInt(params.modid, 10) : null;
|
||||
params.courseid ? pageParams['courseId'] = parseInt(params.courseid, 10) : null;
|
||||
params.entryid ? pageParams['entryId'] = parseInt(params.entryid, 10) : null;
|
||||
params.groupid ? pageParams['groupId'] = parseInt(params.groupid, 10) : null;
|
||||
params.tagid ? pageParams['tagId'] = parseInt(params.tagid, 10) : null;
|
||||
|
||||
return [{
|
||||
action: (siteId: string): void => {
|
||||
CoreNavigator.navigateToSitePath('/blog', { params: pageParams, siteId });
|
||||
},
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
isEnabled(siteId: string): Promise<boolean> {
|
||||
return AddonBlog.isPluginEnabled(siteId);
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonBlogIndexLinkHandler = makeSingleton(AddonBlogIndexLinkHandlerService);
|
|
@ -0,0 +1,51 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@features/mainmenu/services/mainmenu-delegate';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonBlog } from '../blog';
|
||||
|
||||
/**
|
||||
* Handler to inject an option into main menu.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonBlogMainMenuHandlerService implements CoreMainMenuHandler {
|
||||
|
||||
static readonly PAGE_NAME = 'blog';
|
||||
|
||||
name = 'AddonBlog';
|
||||
priority = 450;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return AddonBlog.isPluginEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getDisplayData(): CoreMainMenuHandlerData {
|
||||
return {
|
||||
icon: 'far-newspaper',
|
||||
title: 'addon.blog.siteblogheading',
|
||||
page: AddonBlogMainMenuHandlerService.PAGE_NAME,
|
||||
class: 'addon-blog-handler',
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonBlogMainMenuHandler = makeSingleton(AddonBlogMainMenuHandlerService);
|
|
@ -0,0 +1,53 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreTagFeedComponent } from '@features/tag/components/feed/feed';
|
||||
import { CoreTagAreaHandler } from '@features/tag/services/tag-area-delegate';
|
||||
import { CoreTagFeedElement, CoreTagHelper } from '@features/tag/services/tag-helper';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonBlog } from '../blog';
|
||||
|
||||
/**
|
||||
* Handler to support tags.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonBlogTagAreaHandlerService implements CoreTagAreaHandler {
|
||||
|
||||
name = 'AddonBlogTagAreaHandler';
|
||||
type = 'core/post';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
isEnabled(): Promise<boolean> {
|
||||
return AddonBlog.isPluginEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async parseContent(content: string): Promise<CoreTagFeedElement[]> {
|
||||
return CoreTagHelper.parseFeedContent(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown> | Promise<Type<unknown>> {
|
||||
return CoreTagFeedComponent;
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonBlogTagAreaHandler = makeSingleton(AddonBlogTagAreaHandlerService);
|
|
@ -0,0 +1,64 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreUserProfileHandler, CoreUserProfileHandlerData, CoreUserDelegateService } from '@features/user/services/user-delegate';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonBlog } from '../blog';
|
||||
|
||||
/**
|
||||
* Profile item handler.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonBlogUserHandlerService implements CoreUserProfileHandler {
|
||||
|
||||
name = 'AddonBlog:blogs';
|
||||
priority = 300;
|
||||
type = CoreUserDelegateService.TYPE_NEW_PAGE;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
isEnabled(): Promise<boolean> {
|
||||
return AddonBlog.isPluginEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabledForUser(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getDisplayData(): CoreUserProfileHandlerData {
|
||||
return {
|
||||
icon: 'far-newspaper',
|
||||
title: 'addon.blog.blogentries',
|
||||
class: 'addon-blog-handler',
|
||||
action: (event, user, courseId): void => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
CoreNavigator.navigateToSitePath('/blog', {
|
||||
params: { courseId, userId: user.id },
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonBlogUserHandler = makeSingleton(AddonBlogUserHandlerService);
|
|
@ -10,6 +10,7 @@
|
|||
.addon-calendar-months {
|
||||
background-color: var(--contrast-background);
|
||||
padding: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.addon-calendar-day {
|
||||
|
|
|
@ -139,7 +139,6 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
|
|||
this.fetchData();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect and act upon changes that Angular can’t or won’t detect on its own (objects and arrays).
|
||||
*/
|
||||
|
|
|
@ -29,7 +29,6 @@ import { AddonCalendarFilter, AddonCalendarEventIcons } from '../../services/cal
|
|||
})
|
||||
export class AddonCalendarFilterPopoverComponent implements OnInit {
|
||||
|
||||
|
||||
@Input() filter: AddonCalendarFilter = {
|
||||
filtered: false,
|
||||
courseId: -1,
|
||||
|
@ -54,7 +53,6 @@ export class AddonCalendarFilterPopoverComponent implements OnInit {
|
|||
this.types.push(value);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -266,7 +266,6 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave {
|
|||
// Ignore errors.
|
||||
});
|
||||
|
||||
|
||||
if (this.showAll) {
|
||||
// Remove site home from the list of courses.
|
||||
const siteHomeId = CoreSites.getCurrentSiteHomeId();
|
||||
|
@ -285,7 +284,6 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave {
|
|||
await Promise.all((courses as CoreEnrolledCourseData[]).map(courseFillterFullname));
|
||||
}
|
||||
|
||||
|
||||
// Sort courses by name.
|
||||
this.courses = courses.sort((a, b) => {
|
||||
const compareA = a.fullname.toLowerCase();
|
||||
|
|
|
@ -34,7 +34,6 @@ import { CoreNavigator } from '@services/navigator';
|
|||
import { CoreLocalNotifications } from '@services/local-notifications';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
|
||||
|
||||
/**
|
||||
* Page that displays the calendar events.
|
||||
*/
|
||||
|
|
|
@ -47,7 +47,6 @@ const routes: Routes = [
|
|||
...conditionalRoutes(tabletRoutes, () => CoreScreen.isTablet),
|
||||
];
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild(routes),
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
|
|
|
@ -55,7 +55,6 @@ export class AddonCalendarHelperProvider {
|
|||
|
||||
protected eventTypeIcons: string[] = [];
|
||||
|
||||
|
||||
/**
|
||||
* Returns event icon based on event type.
|
||||
*
|
||||
|
|
|
@ -722,7 +722,6 @@ export class AddonCalendarProvider {
|
|||
const originalEvent = record as AddonCalendarGetEventsEvent;
|
||||
const recordAsRecord = record as AddonCalendarEventDBRecord;
|
||||
|
||||
|
||||
// Calculate data to match the new WS.
|
||||
eventConverted.descriptionformat = originalEvent.format;
|
||||
eventConverted.iscourseevent = originalEvent.eventtype == AddonCalendarEventType.COURSE;
|
||||
|
@ -947,7 +946,6 @@ export class AddonCalendarProvider {
|
|||
params.events!.courseids = courses.map((course) => course.id);
|
||||
params.events!.courseids.push(site.getSiteHomeId()); // Add front page.
|
||||
|
||||
|
||||
return;
|
||||
}));
|
||||
|
||||
|
@ -1941,7 +1939,6 @@ export type AddonCalendarCalendarDay = {
|
|||
rarrow: string; // Rarrow.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Params of core_calendar_get_calendar_monthly_view WS.
|
||||
*/
|
||||
|
@ -2035,7 +2032,6 @@ export type AddonCalendarDayName = {
|
|||
fullname: string; // Fullname.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Params of core_calendar_get_calendar_upcoming_view WS.
|
||||
*/
|
||||
|
@ -2090,7 +2086,6 @@ export type AddonCalendarGetAllowedEventTypesWSResponse = {
|
|||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Params of core_calendar_get_calendar_events WS.
|
||||
*/
|
||||
|
@ -2187,7 +2182,6 @@ type AddonCalendarGetCalendarDayViewWSParams = {
|
|||
categoryid?: number; // Category being viewed.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Params of core_calendar_submit_create_update_form WS.
|
||||
*/
|
||||
|
|
|
@ -25,7 +25,6 @@ export class AddonCalendarMainMenuHandlerService implements CoreMainMenuHandler
|
|||
|
||||
static readonly PAGE_NAME = 'calendar';
|
||||
|
||||
|
||||
name = 'AddonCalendar';
|
||||
priority = 900;
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ import { CoreSharedModule } from '@/core/shared.module';
|
|||
|
||||
import { AddonMessagesConversationInfoComponent } from './conversation-info/conversation-info';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonMessagesConversationInfoComponent,
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.note {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: 4px 8px;
|
||||
font-size: 1.3rem;
|
||||
ion-note {
|
||||
ion-badge {
|
||||
margin-left: 6px;
|
||||
margin-right: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.addon-message-last-message {
|
||||
|
@ -43,6 +43,11 @@
|
|||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
ion-item-divider ion-badge {
|
||||
margin-left: 16px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
:host-context([dir=rtl]) {
|
||||
|
@ -53,11 +58,6 @@
|
|||
margin-left: 0;
|
||||
}
|
||||
|
||||
.note {
|
||||
left: 0;
|
||||
right: unset;
|
||||
}
|
||||
|
||||
.addon-message-last-message-user {
|
||||
margin-left: 2px;
|
||||
margin-right: 0;
|
||||
|
|
|
@ -62,7 +62,6 @@ export class AddonMessagesContacts35Page implements OnInit, OnDestroy {
|
|||
|
||||
searchString = '';
|
||||
|
||||
|
||||
constructor(
|
||||
protected route: ActivatedRoute,
|
||||
) {
|
||||
|
|
|
@ -45,7 +45,6 @@ const routes: Routes = [
|
|||
...conditionalRoutes(tabletRoutes, () => CoreScreen.isTablet),
|
||||
];
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild(routes),
|
||||
|
|
|
@ -58,7 +58,6 @@ export class AddonMessagesContactsPage implements OnInit, OnDestroy {
|
|||
protected contactRequestsCountObserver: CoreEventObserver;
|
||||
protected memberInfoObserver: CoreEventObserver;
|
||||
|
||||
|
||||
constructor() {
|
||||
|
||||
this.siteId = CoreSites.getCurrentSiteId();
|
||||
|
|
|
@ -326,7 +326,6 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
|||
return;
|
||||
}));
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Fetch the messages for the first time.
|
||||
|
@ -596,7 +595,6 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Retrieve the conversation. Invalidate data first to get the right unreadcount.
|
||||
await AddonMessages.invalidateConversation(conversationId!);
|
||||
|
||||
|
@ -1191,7 +1189,6 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
|||
data = await AddonMessages.sendMessage(this.userId!, text);
|
||||
}
|
||||
|
||||
|
||||
this.messagesBeingSent--;
|
||||
let failure = false;
|
||||
if (data.sent) {
|
||||
|
|
|
@ -124,7 +124,6 @@ export class AddonMessagesDiscussions35Page implements OnInit, OnDestroy {
|
|||
this.refreshData();
|
||||
});
|
||||
|
||||
|
||||
// If a message push notification is received, refresh the view.
|
||||
this.pushObserver = CorePushNotificationsDelegate.on<CorePushNotificationsNotificationBasicData>('receive')
|
||||
.subscribe((notification) => {
|
||||
|
|
|
@ -123,10 +123,6 @@
|
|||
<ion-icon *ngIf="conversation.ismuted" name="fas-volume-mute"
|
||||
[title]="'addon.messages.mutedconversation' | translate"></ion-icon>
|
||||
</h2>
|
||||
<ion-note *ngIf="conversation.lastmessagedate > 0 || conversation.unreadcount">
|
||||
<ion-badge *ngIf="conversation.unreadcount > 0">{{ conversation.unreadcount }}</ion-badge>
|
||||
<span *ngIf="conversation.lastmessagedate > 0">{{conversation.lastmessagedate | coreDateDayOrTime}}</span>
|
||||
</ion-note>
|
||||
<p *ngIf="conversation.subname"><core-format-text [text]="conversation.subname" contextLevel="system"
|
||||
[contextInstanceId]="0"></core-format-text></p>
|
||||
<p class="addon-message-last-message">
|
||||
|
@ -139,5 +135,9 @@
|
|||
class="addon-message-last-message-text" contextLevel="system" [contextInstanceId]="0"></core-format-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
<ion-note *ngIf="conversation.lastmessagedate > 0 || conversation.unreadcount" slot="end">
|
||||
<ion-badge *ngIf="conversation.unreadcount > 0">{{ conversation.unreadcount }}</ion-badge>
|
||||
<span *ngIf="conversation.lastmessagedate > 0">{{conversation.lastmessagedate | coreDateDayOrTime}}</span>
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
</ng-template>
|
||||
|
|
|
@ -29,7 +29,6 @@ export class AddonMessagesIndexLinkHandlerService extends CoreContentLinksHandle
|
|||
name = 'AddonMessagesIndexLinkHandler';
|
||||
pattern = /\/message\/index\.php((?![?&](id|user1|user2)=\d+).)*$/;
|
||||
|
||||
|
||||
/**
|
||||
* Get the list of actions for a link (url).
|
||||
*
|
||||
|
|
|
@ -106,7 +106,6 @@ export class AddonMessagesOfflineProvider {
|
|||
),
|
||||
]);
|
||||
|
||||
|
||||
const messageResult:
|
||||
AddonMessagesOfflineAnyMessagesFormatted[] =
|
||||
this.parseMessages(messages);
|
||||
|
@ -379,6 +378,5 @@ export type AddonMessagesOfflineConversationMessagesDBRecordFormatted =
|
|||
useridfrom?: number; // User Id who send the message, will be likely us.
|
||||
};
|
||||
|
||||
|
||||
export type AddonMessagesOfflineAnyMessagesFormatted =
|
||||
AddonMessagesOfflineConversationMessagesDBRecordFormatted | AddonMessagesOfflineMessagesDBRecordFormatted;
|
||||
|
|
|
@ -1413,7 +1413,6 @@ export class AddonMessagesProvider {
|
|||
return AddonMessagesMainMenuHandlerService.PAGE_NAME + ( enabled ? '/group-conversations' : '');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get messages according to the params.
|
||||
*
|
||||
|
@ -1749,7 +1748,6 @@ export class AddonMessagesProvider {
|
|||
const site = await CoreSites.getSite(siteId);
|
||||
userId = userId || site.getUserId();
|
||||
|
||||
|
||||
await site.invalidateWsCacheForKey(this.getCacheKeyForConversationBetweenUsers(userId, otherUserId));
|
||||
}
|
||||
|
||||
|
@ -3065,7 +3063,6 @@ export type AddonMessagesConversationMessageFormatted =
|
|||
showTail?: boolean; // Calculated in the app. Whether to show a "tail" in the message.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Data returned by core_message_get_user_message_preferences WS.
|
||||
*/
|
||||
|
@ -3559,7 +3556,6 @@ export type AddonMessagesGetUserContactsWSResponse = {
|
|||
}[];
|
||||
}[];
|
||||
|
||||
|
||||
/**
|
||||
* Params of core_message_get_contact_requests WS.
|
||||
*/
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
import { Component, Input, ViewChild, ElementRef } from '@angular/core';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
|
|
|
@ -275,7 +275,6 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
cmId: this.module!.id,
|
||||
});
|
||||
|
||||
|
||||
this.summary = submissionStatus.gradingsummary;
|
||||
if (!this.summary) {
|
||||
this.needsGradingAvalaible = false;
|
||||
|
|
|
@ -1190,7 +1190,6 @@ type AddonModAssignSubmissionFeedbackFormatted = AddonModAssignSubmissionFeedbac
|
|||
advancedgrade?: boolean; // Calculated in the app. Whether it uses advanced grading.
|
||||
};
|
||||
|
||||
|
||||
type AddonModAssignSubmissionGrade = {
|
||||
method: string;
|
||||
grade?: number | string;
|
||||
|
|
|
@ -346,7 +346,6 @@ export class AddonModAssignSubmissionListPage implements AfterViewInit, OnDestro
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to manage submissions.
|
||||
*/
|
||||
|
|
|
@ -46,7 +46,6 @@ export class AddonModAssignSubmissionReviewPage implements OnInit, CanLeave {
|
|||
protected blindMarking = false; // Whether it uses blind marking.
|
||||
protected forceLeave = false; // To allow leaving the page without checking for changes.
|
||||
|
||||
|
||||
constructor(
|
||||
protected route: ActivatedRoute,
|
||||
) { }
|
||||
|
|
|
@ -212,7 +212,6 @@ export class AddonModAssignHelperProvider {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
// If all the plugins were empty (or there were no plugins), we consider the submission to be empty.
|
||||
return true;
|
||||
}
|
||||
|
@ -709,7 +708,6 @@ export class AddonModAssignHelperProvider {
|
|||
}
|
||||
export const AddonModAssignHelper = makeSingleton(AddonModAssignHelperProvider);
|
||||
|
||||
|
||||
/**
|
||||
* Assign submission with some calculated data.
|
||||
*/
|
||||
|
|
|
@ -290,7 +290,6 @@ export class AddonModAssignOfflineProvider {
|
|||
const promises:
|
||||
Promise<AddonModAssignSubmissionsDBRecordFormatted[] | AddonModAssignSubmissionsGradingDBRecordFormatted[]>[] = [];
|
||||
|
||||
|
||||
promises.push(this.getAssignSubmissions(assignId, siteId));
|
||||
promises.push(this.getAssignSubmissionsGrade(assignId, siteId));
|
||||
|
||||
|
|
|
@ -178,7 +178,6 @@ export class AddonModAssignSyncProvider extends CoreCourseActivitySyncBaseProvid
|
|||
throw new CoreSyncBlockedError(Translate.instant('core.errorsyncblocked', { $a: this.componentTranslate }));
|
||||
}
|
||||
|
||||
|
||||
this.logger.debug('Try to sync assign ' + assignId + ' in site ' + siteId);
|
||||
|
||||
const syncPromise = this.performSyncAssign(assignId, siteId);
|
||||
|
@ -553,7 +552,6 @@ export type AddonModAssignSyncResult = {
|
|||
gradesBlocked: number[]; // Whether some grade couldn't be synced because it was blocked. UserId fields of the blocked grade.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Data passed to AUTO_SYNCED event.
|
||||
*/
|
||||
|
|
|
@ -761,7 +761,6 @@ export class AddonModAssignProvider {
|
|||
promises.push(this.invalidateAssignmentData(courseId, siteId));
|
||||
promises.push(CoreGrades.invalidateAllCourseGradesData(courseId));
|
||||
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
|
@ -1562,7 +1561,6 @@ export type AddonModAssignSubmissionFeedback = {
|
|||
plugins?: AddonModAssignPlugin[]; // Plugins info.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Params of mod_assign_list_participants WS.
|
||||
*/
|
||||
|
@ -1692,7 +1690,6 @@ type AddonModAssignGetSubmissionStatusWSParams = {
|
|||
groupid?: number; // Filter by users in group (used for generating the grading summary). Empty or 0 for all groups information.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Result of WS mod_assign_get_submission_status.
|
||||
*/
|
||||
|
@ -1812,7 +1809,6 @@ type AddonModAssignSubmitGradingFormWSParams = {
|
|||
jsonformdata: string; // The data from the grading form, encoded as a json array.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Params of mod_assign_save_grade WS.
|
||||
*/
|
||||
|
|
|
@ -49,7 +49,6 @@ export interface AddonModAssignFeedbackHandler extends CoreDelegateHandler {
|
|||
*/
|
||||
getComponent?(plugin: AddonModAssignPlugin): Type<unknown> | undefined | Promise<Type<unknown> | undefined>;
|
||||
|
||||
|
||||
/**
|
||||
* Return the draft saved data of the feedback plugin.
|
||||
*
|
||||
|
|
|
@ -29,7 +29,6 @@ export class AddonModAssignSubmissionCommentsHandlerService implements AddonModA
|
|||
name = 'AddonModAssignSubmissionCommentsHandler';
|
||||
type = 'comments';
|
||||
|
||||
|
||||
/**
|
||||
* Whether the plugin can be edited in offline for existing submissions. In general, this should return false if the
|
||||
* plugin uses Moodle filters. The reason is that the app only prefetches filtered data, and the user should edit
|
||||
|
|
|
@ -22,7 +22,6 @@ import { CoreTextUtils } from '@services/utils/text';
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { AddonModAssignSubmissionOnlineTextPluginData } from '../services/handler';
|
||||
|
||||
|
||||
/**
|
||||
* Component to render an onlinetext submission plugin.
|
||||
*/
|
||||
|
@ -74,7 +73,6 @@ export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignS
|
|||
this.text = AddonModAssign.getSubmissionPluginText(this.plugin);
|
||||
}
|
||||
|
||||
|
||||
// Set the text.
|
||||
if (!this.edit) {
|
||||
// Not editing, see full text when clicked.
|
||||
|
|
|
@ -100,7 +100,6 @@ export class AddonModBookIndexComponent extends CoreCourseModuleMainResourceComp
|
|||
// @todo leaveAnimation: 'core-modal-lateral-transition',
|
||||
});
|
||||
|
||||
|
||||
await modal.present();
|
||||
|
||||
const result = await modal.onDidDismiss();
|
||||
|
|
|
@ -48,7 +48,6 @@ export const enum AddonModBookNavStyle {
|
|||
|
||||
const ROOT_CACHE_KEY = 'mmaModBook:';
|
||||
|
||||
|
||||
/**
|
||||
* Service that provides some features for books.
|
||||
*/
|
||||
|
|
|
@ -160,7 +160,6 @@ export class AddonModFolderProvider {
|
|||
}
|
||||
export const AddonModFolder = makeSingleton(AddonModFolderProvider);
|
||||
|
||||
|
||||
/**
|
||||
* Folder returned by mod_folder_get_folders_by_courses.
|
||||
*/
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
[priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'">
|
||||
</core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="blog"
|
||||
[priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog()">
|
||||
[priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'far-newspaper'" (action)="gotoBlog()">
|
||||
</core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="discussions.loaded && !(hasOffline || hasOfflineRatings) && isOnline"
|
||||
[priority]="700" [content]="'addon.mod_forum.refreshdiscussions' | translate" [iconAction]="refreshIcon" [closeOnClick]="false"
|
||||
|
|
|
@ -55,9 +55,8 @@
|
|||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.addon-mod-forum-discussion-more-info {
|
||||
font-size: 1.4rem;
|
||||
clear: both;
|
||||
.addon-mod-forum-discussion-more-info.ios {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1928,7 +1928,6 @@ export type AddonModForumDeletePostWSParams = {
|
|||
*/
|
||||
export type AddonModForumDeletePostWSResponse = CoreStatusWithWarningsWSResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Params of mod_forum_get_discussion_post WS.
|
||||
*/
|
||||
|
@ -1944,7 +1943,6 @@ export type AddonModForumGetDiscussionPostWSResponse = {
|
|||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Params of mod_forum_get_discussion_posts WS.
|
||||
*/
|
||||
|
|
|
@ -46,7 +46,6 @@ export class AddonModImscpIndexComponent extends CoreCourseModuleMainResourceCom
|
|||
previousItem = '';
|
||||
nextItem = '';
|
||||
|
||||
|
||||
constructor(@Optional() courseContentsPage?: CoreCourseContentsPage) {
|
||||
super('AddonModImscpIndexComponent', courseContentsPage);
|
||||
}
|
||||
|
|
|
@ -343,7 +343,6 @@ export class AddonModImscpProvider {
|
|||
}
|
||||
export const AddonModImscp = makeSingleton(AddonModImscpProvider);
|
||||
|
||||
|
||||
/**
|
||||
* Params of mod_imscp_view_imscp WS.
|
||||
*/
|
||||
|
@ -387,7 +386,6 @@ type AddonModImscpGetImscpsByCoursesWSResponse = {
|
|||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
|
||||
export type AddonModImscpTocItem = {
|
||||
href: string;
|
||||
title: string;
|
||||
|
|
|
@ -165,7 +165,6 @@ export class AddonModLabelProvider {
|
|||
}
|
||||
export const AddonModLabel = makeSingleton(AddonModLabelProvider);
|
||||
|
||||
|
||||
/**
|
||||
* Label returned by mod_label_get_labels_by_courses.
|
||||
*/
|
||||
|
|
|
@ -19,7 +19,6 @@ import { CoreSites } from '@services/sites';
|
|||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { ModalController } from '@singletons';
|
||||
|
||||
|
||||
/**
|
||||
* Modal that asks the password for a lesson.
|
||||
*/
|
||||
|
|
|
@ -175,7 +175,6 @@ export class AddonModPageProvider {
|
|||
|
||||
export const AddonModPage = makeSingleton(AddonModPageProvider);
|
||||
|
||||
|
||||
/**
|
||||
* Page returned by mod_page_get_pages_by_courses.
|
||||
*/
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
|
|
|
@ -251,7 +251,6 @@ export class AddonModResourceModuleHandlerService implements CoreCourseModuleHan
|
|||
}
|
||||
export const AddonModResourceModuleHandler = makeSingleton(AddonModResourceModuleHandlerService);
|
||||
|
||||
|
||||
type AddonResourceHandlerData = {
|
||||
icon: string;
|
||||
extra: string;
|
||||
|
|
|
@ -258,7 +258,6 @@ type AddonModUrlViewUrlWSParams = {
|
|||
urlid: number; // Url instance id.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* URL returnd by mod_url_get_urls_by_courses.
|
||||
*/
|
||||
|
|
|
@ -13,9 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
|
||||
import { AddonNotificationsActionsComponent } from './actions/actions';
|
||||
|
||||
|
@ -24,9 +22,7 @@ import { AddonNotificationsActionsComponent } from './actions/actions';
|
|||
AddonNotificationsActionsComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
TranslateModule.forChild(),
|
||||
CoreSharedModule,
|
||||
],
|
||||
exports: [
|
||||
AddonNotificationsActionsComponent,
|
||||
|
|
|
@ -176,7 +176,6 @@ export class AddonQbehaviourDeferredFeedbackHandlerService implements CoreQuesti
|
|||
|
||||
export const AddonQbehaviourDeferredFeedbackHandler = makeSingleton(AddonQbehaviourDeferredFeedbackHandlerService);
|
||||
|
||||
|
||||
/**
|
||||
* Check if a response is complete.
|
||||
*
|
||||
|
|
|
@ -871,7 +871,6 @@ export class AddonQtypeDdMarkerQuestion {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulates operations on dd area.
|
||||
*/
|
||||
|
|
|
@ -17,7 +17,6 @@ import { APP_INITIALIZER, NgModule } from '@angular/core';
|
|||
import { CoreQuestionDelegate } from '@features/question/services/question-delegate';
|
||||
import { AddonQtypeNumericalHandler } from './services/handlers/numerical';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
|
|
|
@ -128,7 +128,6 @@ export class CoreAttachmentsComponent implements OnInit {
|
|||
*/
|
||||
async delete(index: number, askConfirm?: boolean): Promise<void> {
|
||||
|
||||
|
||||
if (askConfirm) {
|
||||
try {
|
||||
await CoreDomUtils.showDeleteConfirm('core.confirmdeletefile');
|
||||
|
|
|
@ -44,7 +44,6 @@ export class CoreContextMenuComponent implements OnInit, OnDestroy {
|
|||
protected instanceId: string;
|
||||
protected parentContextMenu?: CoreContextMenuComponent;
|
||||
|
||||
|
||||
constructor(
|
||||
elementRef: ElementRef,
|
||||
) {
|
||||
|
|
|
@ -77,6 +77,10 @@ export class CoreInfiniteLoadingComponent implements OnChanges {
|
|||
|
||||
// Calculate distance from edge.
|
||||
const content = this.element.nativeElement.closest('ion-content') as IonContent;
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scrollElement = await content.getScrollElement();
|
||||
|
||||
const infiniteHeight = this.element.nativeElement.getBoundingClientRect().height;
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
--menu-border-width: 0;
|
||||
--menu-box-shadow: none;
|
||||
--menu-z: 0;
|
||||
--selected-item-border-width: 0;
|
||||
--selected-item-color: transparent;
|
||||
}
|
||||
|
||||
:host(.content-only) {
|
||||
|
|
|
@ -518,7 +518,6 @@ export type CoreCommentsDataWithUser = CoreCommentsData & {
|
|||
deleted?: boolean;
|
||||
};
|
||||
|
||||
|
||||
export type CoreCommentsOfflineWithUser = CoreCommentsDBRecord & {
|
||||
profileimageurl?: string;
|
||||
fullname?: string;
|
||||
|
|
|
@ -322,7 +322,6 @@ export type CoreCommentsSyncResult = {
|
|||
updated: boolean; // Whether some data was sent to the server or offline data was updated.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Data passed to AUTO_SYNCED event.
|
||||
*/
|
||||
|
|
|
@ -530,7 +530,6 @@ export type CoreCommentsArea = {
|
|||
canpostorhascomments: boolean; // Canpostorhascomments.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Params of core_comment_add_comments WS.
|
||||
*/
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ export class CoreCourseModuleMainActivityPage<ActivityType extends CoreCourseMod
|
|||
module!: CoreCourseAnyModuleData;
|
||||
courseId!: number;
|
||||
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
*/
|
||||
|
|
|
@ -13,9 +13,13 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import { AddonBlog } from '@addons/blog/services/blog';
|
||||
import { AddonBlogMainMenuHandlerService } from '@addons/blog/services/handlers/mainmenu';
|
||||
import { OnInit, OnDestroy, Input, Output, EventEmitter, Component, Optional, Inject } from '@angular/core';
|
||||
import { Params } from '@angular/router';
|
||||
import { IonRefresher } from '@ionic/angular';
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
|
||||
|
@ -90,7 +94,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
|
|||
this.componentId = this.module?.id;
|
||||
this.externalUrl = this.module?.url;
|
||||
this.courseId = this.courseId || this.module?.course;
|
||||
// @todo this.blog = await this.blogProvider.isPluginEnabled();
|
||||
this.blog = await AddonBlog.isPluginEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,8 +227,9 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
|
|||
* Go to blog posts.
|
||||
*/
|
||||
async gotoBlog(): Promise<void> {
|
||||
// const params: Params = { cmId: this.module?.id };
|
||||
// @todo return CoreNavigator.navigateToSitePath('AddonBlogEntriesPage', { params });
|
||||
const params: Params = { cmId: this.module?.id };
|
||||
|
||||
CoreNavigator.navigateToSitePath(AddonBlogMainMenuHandlerService.PAGE_NAME, { params });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -208,7 +208,6 @@ export class CoreCourseProvider {
|
|||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
|
||||
const data = await site.read<CoreCourseCompletionActivityStatusWSResponse>(
|
||||
'core_completion_get_activities_completion_status',
|
||||
params,
|
||||
|
@ -551,7 +550,6 @@ export class CoreCourseProvider {
|
|||
return grade;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -508,7 +508,6 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
|
|||
return downloadedSize;
|
||||
}
|
||||
|
||||
|
||||
const cachedSize = await site.getComponentCacheSize(handler.component, module.id);
|
||||
|
||||
return cachedSize + downloadedSize;
|
||||
|
|
|
@ -146,7 +146,6 @@ export class CoreCourseSyncProvider extends CoreSyncBaseProvider<CoreCourseSyncR
|
|||
<CoreCourseManualCompletionDBRecord[]> [],
|
||||
);
|
||||
|
||||
|
||||
if (!completions || !completions.length) {
|
||||
// Nothing to sync, set sync time.
|
||||
await this.setSyncTime(courseId, siteId);
|
||||
|
|
|
@ -20,7 +20,6 @@ import { CoreCoursesComponentsModule } from '../../components/components.module'
|
|||
|
||||
import { CoreCoursesAvailableCoursesPage } from './available-courses';
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
|
|
|
@ -20,7 +20,6 @@ import { CoreCoursesComponentsModule } from '../../components/components.module'
|
|||
|
||||
import { CoreCoursesCategoriesPage } from './categories';
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
|
|
|
@ -138,7 +138,6 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Toggle download enabled.
|
||||
*/
|
||||
|
@ -179,5 +178,4 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy {
|
|||
this.updateSiteObserver?.off();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -122,7 +122,6 @@ export class CoreCoursesDashboardProvider {
|
|||
|
||||
export const CoreCoursesDashboard = makeSingleton(CoreCoursesDashboardProvider);
|
||||
|
||||
|
||||
/**
|
||||
* Params of core_block_get_dashboard_blocks WS.
|
||||
*/
|
||||
|
|
|
@ -25,7 +25,6 @@ import { CoreUtils } from '@services/utils/utils';
|
|||
import { makeSingleton } from '@singletons';
|
||||
import { CoreCourses } from '../courses';
|
||||
|
||||
|
||||
/**
|
||||
* Handler for course request push notifications clicks.
|
||||
*/
|
||||
|
|
|
@ -370,7 +370,6 @@ export class CoreEmulatorCaptureMediaComponent implements OnInit, OnDestroy {
|
|||
const height = this.streamVideo?.nativeElement.videoHeight;
|
||||
const loadingModal = await CoreDomUtils.showModalLoading();
|
||||
|
||||
|
||||
this.imgCanvas.nativeElement.width = width;
|
||||
this.imgCanvas.nativeElement.height = height;
|
||||
this.imgCanvas.nativeElement.getContext('2d').drawImage(this.streamVideo?.nativeElement, 0, 0, width, height);
|
||||
|
|
|
@ -51,7 +51,6 @@ export class CoreEmulatorHelperProvider {
|
|||
return;
|
||||
}));
|
||||
|
||||
|
||||
return CoreUtils.allPromises(promises);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
height: 100%;
|
||||
flex-direction: column;
|
||||
ion-tab-button {
|
||||
display: contents;
|
||||
width: 100%;
|
||||
ion-badge {
|
||||
top: calc(50% - 20px);
|
||||
|
|
|
@ -109,7 +109,6 @@ export const SITE_SCHEMA: CoreSiteSchema = {
|
|||
],
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Data stored in DB for badge.
|
||||
*/
|
||||
|
|
|
@ -128,7 +128,6 @@ export class CoreQuestionComponent implements OnInit {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
// Load local answers if offline is enabled.
|
||||
if (this.offlineEnabled && this.component && this.attemptId) {
|
||||
await CoreQuestionHelper.loadLocalAnswers(this.question, this.component, this.attemptId);
|
||||
|
|
|
@ -28,7 +28,6 @@ import {
|
|||
QUESTION_TABLE_NAME,
|
||||
} from './database/question';
|
||||
|
||||
|
||||
const QUESTION_PREFIX_REGEX = /q\d+:(\d+)_/;
|
||||
const STATES: Record<string, CoreQuestionState> = {
|
||||
todo: {
|
||||
|
|
|
@ -76,7 +76,6 @@ export const RATINGS_SITE_SCHEMA: CoreSiteSchema = {
|
|||
],
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Primary data to identify a stored rating.
|
||||
*/
|
||||
|
|
|
@ -25,7 +25,6 @@ import { CoreEvents } from '@singletons/events';
|
|||
import { CoreRating } from './rating';
|
||||
import { CoreRatingItemSet, CoreRatingOffline } from './rating-offline';
|
||||
|
||||
|
||||
/**
|
||||
* Service to sync ratings.
|
||||
*/
|
||||
|
|
|
@ -513,7 +513,6 @@ export type CoreRatingItemRating = {
|
|||
timemodified: number; // Time modified (timestamp).
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Params of core_rating_get_item_ratings WS.
|
||||
*/
|
||||
|
@ -535,7 +534,6 @@ export type CoreRatingGetItemRatingsWSResponse = {
|
|||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Params of core_rating_add_rating WS.
|
||||
*/
|
||||
|
|
|
@ -17,7 +17,6 @@ import { NgModule } from '@angular/core';
|
|||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
import { CoreSearchBoxComponent } from './search-box/search-box';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreSearchBoxComponent,
|
||||
|
|
|
@ -159,7 +159,6 @@ export class CoreSearchBoxComponent implements OnInit {
|
|||
if (!this.formElement) {
|
||||
this.formElement = event.detail.target.closest('form');
|
||||
|
||||
|
||||
this.formElement?.addEventListener('blur', () => {
|
||||
// Wait the new element to be focused.
|
||||
setTimeout(() => {
|
||||
|
|
|
@ -94,7 +94,6 @@ export class CoreSettingsGeneralPage {
|
|||
selected: value === this.selectedZoomLevel,
|
||||
}));
|
||||
|
||||
|
||||
this.richTextEditor = await CoreConfig.get(CoreConstants.SETTINGS_RICH_TEXT_EDITOR, true);
|
||||
|
||||
this.debugDisplay = await CoreConfig.get(CoreConstants.SETTINGS_DEBUG_DISPLAY, false);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue