commit
						a72542cb44
					
				
							
								
								
									
										338
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										338
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -3986,8 +3986,7 @@ | ||||
|     "aproba": { | ||||
|       "version": "1.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", | ||||
|       "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", | ||||
|       "dev": true | ||||
|       "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" | ||||
|     }, | ||||
|     "archy": { | ||||
|       "version": "1.0.0", | ||||
| @ -3995,6 +3994,16 @@ | ||||
|       "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "are-we-there-yet": { | ||||
|       "version": "1.1.5", | ||||
|       "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", | ||||
|       "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "delegates": "^1.0.0", | ||||
|         "readable-stream": "^2.0.6" | ||||
|       } | ||||
|     }, | ||||
|     "arg": { | ||||
|       "version": "4.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", | ||||
| @ -4694,6 +4703,40 @@ | ||||
|         "file-uri-to-path": "1.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "bl": { | ||||
|       "version": "4.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", | ||||
|       "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "buffer": "^5.5.0", | ||||
|         "inherits": "^2.0.4", | ||||
|         "readable-stream": "^3.4.0" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "buffer": { | ||||
|           "version": "5.7.1", | ||||
|           "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", | ||||
|           "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "base64-js": "^1.3.1", | ||||
|             "ieee754": "^1.1.13" | ||||
|           } | ||||
|         }, | ||||
|         "readable-stream": { | ||||
|           "version": "3.6.0", | ||||
|           "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", | ||||
|           "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "inherits": "^2.0.3", | ||||
|             "string_decoder": "^1.1.1", | ||||
|             "util-deprecate": "^1.0.1" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "bluebird": { | ||||
|       "version": "3.7.2", | ||||
|       "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", | ||||
| @ -5581,8 +5624,7 @@ | ||||
|     "code-point-at": { | ||||
|       "version": "1.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", | ||||
|       "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" | ||||
|     }, | ||||
|     "collect-v8-coverage": { | ||||
|       "version": "1.0.1", | ||||
| @ -5879,6 +5921,12 @@ | ||||
|       "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "console-control-strings": { | ||||
|       "version": "1.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", | ||||
|       "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "constants-browserify": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", | ||||
| @ -7387,6 +7435,12 @@ | ||||
|       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", | ||||
|       "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" | ||||
|     }, | ||||
|     "delegates": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", | ||||
|       "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "dep-graph": { | ||||
|       "version": "1.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/dep-graph/-/dep-graph-1.1.0.tgz", | ||||
| @ -7439,6 +7493,12 @@ | ||||
|       "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", | ||||
|       "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==" | ||||
|     }, | ||||
|     "detect-libc": { | ||||
|       "version": "1.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", | ||||
|       "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "detect-newline": { | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", | ||||
| @ -8455,6 +8515,12 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "expand-template": { | ||||
|       "version": "2.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", | ||||
|       "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "expand-tilde": { | ||||
|       "version": "2.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", | ||||
| @ -9106,6 +9172,12 @@ | ||||
|         "readable-stream": "^2.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "fs-constants": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", | ||||
|       "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "fs-extra": { | ||||
|       "version": "9.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", | ||||
| @ -9172,6 +9244,59 @@ | ||||
|       "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "gauge": { | ||||
|       "version": "2.7.4", | ||||
|       "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", | ||||
|       "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "aproba": "^1.0.3", | ||||
|         "console-control-strings": "^1.0.0", | ||||
|         "has-unicode": "^2.0.0", | ||||
|         "object-assign": "^4.1.0", | ||||
|         "signal-exit": "^3.0.0", | ||||
|         "string-width": "^1.0.1", | ||||
|         "strip-ansi": "^3.0.1", | ||||
|         "wide-align": "^1.1.0" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "ansi-regex": { | ||||
|           "version": "2.1.1", | ||||
|           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", | ||||
|           "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", | ||||
|           "optional": true | ||||
|         }, | ||||
|         "is-fullwidth-code-point": { | ||||
|           "version": "1.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", | ||||
|           "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "number-is-nan": "^1.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "string-width": { | ||||
|           "version": "1.0.2", | ||||
|           "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", | ||||
|           "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "code-point-at": "^1.0.0", | ||||
|             "is-fullwidth-code-point": "^1.0.0", | ||||
|             "strip-ansi": "^3.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "strip-ansi": { | ||||
|           "version": "3.0.1", | ||||
|           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", | ||||
|           "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "ansi-regex": "^2.0.0" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "genfun": { | ||||
|       "version": "5.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", | ||||
| @ -9224,6 +9349,12 @@ | ||||
|         "assert-plus": "^1.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "github-from-package": { | ||||
|       "version": "0.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", | ||||
|       "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "glob": { | ||||
|       "version": "7.1.6", | ||||
|       "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", | ||||
| @ -10057,6 +10188,12 @@ | ||||
|       "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "has-unicode": { | ||||
|       "version": "2.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", | ||||
|       "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "has-value": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", | ||||
| @ -10571,8 +10708,7 @@ | ||||
|     "ieee754": { | ||||
|       "version": "1.1.13", | ||||
|       "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", | ||||
|       "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", | ||||
|       "dev": true | ||||
|       "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" | ||||
|     }, | ||||
|     "iferr": { | ||||
|       "version": "0.1.5", | ||||
| @ -12663,6 +12799,16 @@ | ||||
|         "source-map-support": "^0.5.5" | ||||
|       } | ||||
|     }, | ||||
|     "keytar": { | ||||
|       "version": "7.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.2.0.tgz", | ||||
|       "integrity": "sha512-ECSaWvoLKI5SI0pGpZQeUV1/lpBYfkaxvoSp3zkiPOz05VavwSfLi8DdEaa9N2ekQZv3Chy+o7aP6n9mairBgw==", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "node-addon-api": "^3.0.0", | ||||
|         "prebuild-install": "^6.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "keyv": { | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", | ||||
| @ -13671,6 +13817,12 @@ | ||||
|         "minimist": "^1.2.5" | ||||
|       } | ||||
|     }, | ||||
|     "mkdirp-classic": { | ||||
|       "version": "0.5.3", | ||||
|       "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", | ||||
|       "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "moment": { | ||||
|       "version": "2.29.0", | ||||
|       "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz", | ||||
| @ -13776,6 +13928,12 @@ | ||||
|         "to-regex": "^3.0.1" | ||||
|       } | ||||
|     }, | ||||
|     "napi-build-utils": { | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", | ||||
|       "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "native-request": { | ||||
|       "version": "1.0.7", | ||||
|       "resolved": "https://registry.npmjs.org/native-request/-/native-request-1.0.7.tgz", | ||||
| @ -13825,6 +13983,29 @@ | ||||
|         "lower-case": "^1.1.1" | ||||
|       } | ||||
|     }, | ||||
|     "node-abi": { | ||||
|       "version": "2.19.3", | ||||
|       "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.19.3.tgz", | ||||
|       "integrity": "sha512-9xZrlyfvKhWme2EXFKQhZRp1yNWT/uI1luYPr3sFl+H4keYY4xR+1jO7mvTTijIsHf1M+QDe9uWuKeEpLInIlg==", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "semver": "^5.4.1" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "semver": { | ||||
|           "version": "5.7.1", | ||||
|           "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", | ||||
|           "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node-addon-api": { | ||||
|       "version": "3.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.2.tgz", | ||||
|       "integrity": "sha512-+D4s2HCnxPd5PjjI0STKwncjXTUKKqm74MDMz9OPXavjsGmjkvwgLtA5yoxJUdmpj52+2u+RrXgPipahKczMKg==", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "node-fetch-npm": { | ||||
|       "version": "2.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz", | ||||
| @ -13938,6 +14119,12 @@ | ||||
|       "integrity": "sha512-DD5vebQLg8jLCOzwupn954fbIiZht05DAZs0k2u8NStSe6h9XdsuIQL8hSRKYiU8WUQRznmSDrKGbv3ObOmC7g==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "noop-logger": { | ||||
|       "version": "0.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", | ||||
|       "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "nopt": { | ||||
|       "version": "4.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", | ||||
| @ -14121,6 +14308,18 @@ | ||||
|         "path-key": "^3.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "npmlog": { | ||||
|       "version": "4.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", | ||||
|       "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "are-we-there-yet": "~1.1.2", | ||||
|         "console-control-strings": "~1.1.0", | ||||
|         "gauge": "~2.7.3", | ||||
|         "set-blocking": "~2.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "nth-check": { | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", | ||||
| @ -14139,8 +14338,7 @@ | ||||
|     "number-is-nan": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", | ||||
|       "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" | ||||
|     }, | ||||
|     "nwsapi": { | ||||
|       "version": "2.2.0", | ||||
| @ -14156,8 +14354,7 @@ | ||||
|     "object-assign": { | ||||
|       "version": "4.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | ||||
|       "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" | ||||
|     }, | ||||
|     "object-copy": { | ||||
|       "version": "0.1.0", | ||||
| @ -15986,6 +16183,29 @@ | ||||
|       "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "prebuild-install": { | ||||
|       "version": "6.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.0.0.tgz", | ||||
|       "integrity": "sha512-h2ZJ1PXHKWZpp1caLw0oX9sagVpL2YTk+ZwInQbQ3QqNd4J03O6MpFNmMTJlkfgPENWqe5kP0WjQLqz5OjLfsw==", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "detect-libc": "^1.0.3", | ||||
|         "expand-template": "^2.0.3", | ||||
|         "github-from-package": "0.0.0", | ||||
|         "minimist": "^1.2.3", | ||||
|         "mkdirp-classic": "^0.5.3", | ||||
|         "napi-build-utils": "^1.0.1", | ||||
|         "node-abi": "^2.7.0", | ||||
|         "noop-logger": "^0.1.1", | ||||
|         "npmlog": "^4.0.1", | ||||
|         "pump": "^3.0.0", | ||||
|         "rc": "^1.2.7", | ||||
|         "simple-get": "^3.0.3", | ||||
|         "tar-fs": "^2.0.0", | ||||
|         "tunnel-agent": "^0.6.0", | ||||
|         "which-pm-runs": "^1.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "prelude-ls": { | ||||
|       "version": "1.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", | ||||
| @ -17556,8 +17776,7 @@ | ||||
|     "set-blocking": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", | ||||
|       "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" | ||||
|     }, | ||||
|     "set-immediate-shim": { | ||||
|       "version": "1.0.1", | ||||
| @ -17663,6 +17882,40 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "simple-concat": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", | ||||
|       "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "simple-get": { | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", | ||||
|       "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "decompress-response": "^4.2.0", | ||||
|         "once": "^1.3.1", | ||||
|         "simple-concat": "^1.0.0" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "decompress-response": { | ||||
|           "version": "4.2.1", | ||||
|           "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", | ||||
|           "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "mimic-response": "^2.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "mimic-response": { | ||||
|           "version": "2.1.0", | ||||
|           "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", | ||||
|           "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "simple-plist": { | ||||
|       "version": "1.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.1.1.tgz", | ||||
| @ -18812,6 +19065,52 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "tar-fs": { | ||||
|       "version": "2.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", | ||||
|       "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "chownr": "^1.1.1", | ||||
|         "mkdirp-classic": "^0.5.2", | ||||
|         "pump": "^3.0.0", | ||||
|         "tar-stream": "^2.1.4" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "chownr": { | ||||
|           "version": "1.1.4", | ||||
|           "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", | ||||
|           "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "tar-stream": { | ||||
|       "version": "2.1.4", | ||||
|       "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz", | ||||
|       "integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "bl": "^4.0.3", | ||||
|         "end-of-stream": "^1.4.1", | ||||
|         "fs-constants": "^1.0.0", | ||||
|         "inherits": "^2.0.3", | ||||
|         "readable-stream": "^3.1.1" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "readable-stream": { | ||||
|           "version": "3.6.0", | ||||
|           "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", | ||||
|           "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "inherits": "^2.0.3", | ||||
|             "string_decoder": "^1.1.1", | ||||
|             "util-deprecate": "^1.0.1" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "term-size": { | ||||
|       "version": "2.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", | ||||
| @ -20907,6 +21206,21 @@ | ||||
|       "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "which-pm-runs": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", | ||||
|       "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "wide-align": { | ||||
|       "version": "1.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", | ||||
|       "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "string-width": "^1.0.2 || 2" | ||||
|       } | ||||
|     }, | ||||
|     "widest-line": { | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", | ||||
|  | ||||
| @ -221,5 +221,8 @@ | ||||
|       "cordova-plugin-globalization": {}, | ||||
|       "cordova-plugin-file-transfer": {} | ||||
|     } | ||||
|   }, | ||||
|   "optionalDependencies": { | ||||
|     "keytar": "^7.2.0" | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -15,10 +15,12 @@ | ||||
| import { NgModule } from '@angular/core'; | ||||
| 
 | ||||
| import { AddonPrivateFilesModule } from './privatefiles/privatefiles.module'; | ||||
| import { AddonFilterModule } from './filter/filter.module'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     imports: [ | ||||
|         AddonPrivateFilesModule, | ||||
|         AddonFilterModule, | ||||
|     ], | ||||
| }) | ||||
| export class AddonsModule {} | ||||
|  | ||||
							
								
								
									
										34
									
								
								src/addons/filter/activitynames/activitynames.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/activitynames/activitynames.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterActivityNamesHandler } from './services/handlers/activitynames'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterActivityNamesHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterActivityNamesModule {} | ||||
| @ -0,0 +1,46 @@ | ||||
| // (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Activity names filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterActivityNamesHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterActivityNamesHandler'; | ||||
|     filterName = 'activitynames'; | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterActivityNamesHandler extends makeSingleton(AddonFilterActivityNamesHandlerService) {} | ||||
							
								
								
									
										34
									
								
								src/addons/filter/algebra/algebra.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/algebra/algebra.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterAlgebraHandler } from './services/handlers/algebra'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterAlgebraHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterAlgebraModule {} | ||||
							
								
								
									
										46
									
								
								src/addons/filter/algebra/services/handlers/algebra.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/addons/filter/algebra/services/handlers/algebra.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| // (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Algebra notation filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterAlgebraHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterAlgebraHandler'; | ||||
|     filterName = 'algebra'; | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterAlgebraHandler extends makeSingleton(AddonFilterAlgebraHandlerService) {} | ||||
							
								
								
									
										34
									
								
								src/addons/filter/censor/censor.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/censor/censor.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterCensorHandler } from './services/handlers/censor'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterCensorHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterCensorModule {} | ||||
							
								
								
									
										46
									
								
								src/addons/filter/censor/services/handlers/censor.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/addons/filter/censor/services/handlers/censor.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| // (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Word censorship filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterCensorHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterCensorHandler'; | ||||
|     filterName = 'censor'; | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterCensorHandler extends makeSingleton(AddonFilterCensorHandlerService) {} | ||||
							
								
								
									
										34
									
								
								src/addons/filter/data/data.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/data/data.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterDataHandler } from './services/handlers/data'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterDataHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterDataModule {} | ||||
							
								
								
									
										46
									
								
								src/addons/filter/data/services/handlers/data.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/addons/filter/data/services/handlers/data.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| // (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Database auto-link filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterDataHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterDataHandler'; | ||||
|     filterName = 'data'; | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterDataHandler extends makeSingleton(AddonFilterDataHandlerService) {} | ||||
							
								
								
									
										34
									
								
								src/addons/filter/displayh5p/displayh5p.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/displayh5p/displayh5p.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterDisplayH5PHandler } from './services/handlers/displayh5p'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterDisplayH5PHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterDisplayH5PModule {} | ||||
							
								
								
									
										113
									
								
								src/addons/filter/displayh5p/services/handlers/displayh5p.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/addons/filter/displayh5p/services/handlers/displayh5p.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,113 @@ | ||||
| // (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, ViewContainerRef, ComponentFactoryResolver } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| // @todo import { CoreH5PPlayerComponent } from '@core/h5p/components/h5p-player/h5p-player';
 | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Display H5P filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterDisplayH5PHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterDisplayH5PHandler'; | ||||
|     filterName = 'displayh5p'; | ||||
| 
 | ||||
|     protected template = document.createElement('template'); // A template element to convert HTML to element.
 | ||||
| 
 | ||||
|     constructor(protected factoryResolver: ComponentFactoryResolver) { | ||||
|         super(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Filter some text. | ||||
|      * | ||||
|      * @param text The text to filter. | ||||
|      * @param filter The filter. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Filtered text (or promise resolved with the filtered text). | ||||
|      */ | ||||
|     filter( | ||||
|         text: string, | ||||
|         filter: CoreFilterFilter, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         options: CoreFilterFormatTextOptions, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         siteId?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|     ): string | Promise<string> { | ||||
|         this.template.innerHTML = text; | ||||
| 
 | ||||
|         const h5pIframes = <HTMLIFrameElement[]> Array.from(this.template.content.querySelectorAll('iframe.h5p-iframe')); | ||||
| 
 | ||||
|         // Replace all iframes with an empty div that will be treated in handleHtml.
 | ||||
|         h5pIframes.forEach((iframe) => { | ||||
|             const placeholder = document.createElement('div'); | ||||
| 
 | ||||
|             placeholder.classList.add('core-h5p-tmp-placeholder'); | ||||
|             placeholder.setAttribute('data-player-src', iframe.src); | ||||
| 
 | ||||
|             iframe.parentElement?.replaceChild(placeholder, iframe); | ||||
|         }); | ||||
| 
 | ||||
|         return this.template.innerHTML; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Handle HTML. This function is called after "filter", and it will receive an HTMLElement containing the text that was | ||||
|      * filtered. | ||||
|      * | ||||
|      * @param container The HTML container to handle. | ||||
|      * @param filter The filter. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param viewContainerRef The ViewContainerRef where the container is. | ||||
|      * @param component Component. | ||||
|      * @param componentId Component ID. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return If async, promise resolved when done. | ||||
|      */ | ||||
|     handleHtml( | ||||
|         container: HTMLElement, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         filter: CoreFilterFilter, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         options: CoreFilterFormatTextOptions, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         viewContainerRef: ViewContainerRef, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         component?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         componentId?: string | number, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         siteId?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|     ): void | Promise<void> { | ||||
|         // @todo
 | ||||
| 
 | ||||
|         // const placeholders = <HTMLElement[]> Array.from(container.querySelectorAll('div.core-h5p-tmp-placeholder'));
 | ||||
| 
 | ||||
|         // placeholders.forEach((placeholder) => {
 | ||||
|         //     const url = placeholder.getAttribute('data-player-src');
 | ||||
| 
 | ||||
|         //     Create the component to display the player.
 | ||||
|         //     const factory = this.factoryResolver.resolveComponentFactory(CoreH5PPlayerComponent);
 | ||||
|         //     const componentRef = viewContainerRef.createComponent<CoreH5PPlayerComponent>(factory);
 | ||||
| 
 | ||||
|         //     componentRef.instance.src = url;
 | ||||
|         //     componentRef.instance.component = component;
 | ||||
|         //     componentRef.instance.componentId = componentId;
 | ||||
| 
 | ||||
|         //     // Move the component to its right position.
 | ||||
|         //     placeholder.parentElement?.replaceChild(componentRef.instance.elementRef.nativeElement, placeholder);
 | ||||
|         // });
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterDisplayH5PHandler extends makeSingleton(AddonFilterDisplayH5PHandlerService) {} | ||||
							
								
								
									
										34
									
								
								src/addons/filter/emailprotect/emailprotect.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/emailprotect/emailprotect.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterEmailProtectHandler } from './services/handlers/emailprotect'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterEmailProtectHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterEmailProtectModule {} | ||||
| @ -0,0 +1,46 @@ | ||||
| // (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Email protection filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterEmailProtectHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterEmailProtectHandler'; | ||||
|     filterName = 'emailprotect'; | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterEmailProtectHandler extends makeSingleton(AddonFilterEmailProtectHandlerService) {} | ||||
							
								
								
									
										34
									
								
								src/addons/filter/emoticon/emoticon.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/emoticon/emoticon.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterEmoticonHandler } from './services/handlers/emoticon'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterEmoticonHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterEmoticonModule {} | ||||
							
								
								
									
										46
									
								
								src/addons/filter/emoticon/services/handlers/emoticon.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/addons/filter/emoticon/services/handlers/emoticon.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| // (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Emoticon filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterEmoticonHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterEmoticonHandler'; | ||||
|     filterName = 'emoticon'; | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterEmoticonHandler extends makeSingleton(AddonFilterEmoticonHandlerService) {} | ||||
							
								
								
									
										53
									
								
								src/addons/filter/filter.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/addons/filter/filter.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 { NgModule } from '@angular/core'; | ||||
| 
 | ||||
| import { AddonFilterActivityNamesModule } from './activitynames/activitynames.module'; | ||||
| import { AddonFilterAlgebraModule } from './algebra/algebra.module'; | ||||
| import { AddonFilterCensorModule } from './censor/censor.module'; | ||||
| import { AddonFilterDataModule } from './data/data.module'; | ||||
| import { AddonFilterDisplayH5PModule } from './displayh5p/displayh5p.module'; | ||||
| import { AddonFilterEmailProtectModule } from './emailprotect/emailprotect.module'; | ||||
| import { AddonFilterEmoticonModule } from './emoticon/emoticon.module'; | ||||
| import { AddonFilterGlossaryModule } from './glossary/glossary.module'; | ||||
| import { AddonFilterMathJaxLoaderModule } from './mathjaxloader/mathjaxloader.module'; | ||||
| import { AddonFilterMediaPluginModule } from './mediaplugin/mediaplugin.module'; | ||||
| import { AddonFilterMultilangModule } from './multilang/multilang.module'; | ||||
| import { AddonFilterTexModule } from './tex/tex.module'; | ||||
| import { AddonFilterTidyModule } from './tidy/tidy.module'; | ||||
| import { AddonFilterUrlToLinkModule } from './urltolink/urltolink.module'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [], | ||||
|     imports: [ | ||||
|         AddonFilterActivityNamesModule, | ||||
|         AddonFilterAlgebraModule, | ||||
|         AddonFilterCensorModule, | ||||
|         AddonFilterDataModule, | ||||
|         AddonFilterDisplayH5PModule, | ||||
|         AddonFilterEmailProtectModule, | ||||
|         AddonFilterEmoticonModule, | ||||
|         AddonFilterGlossaryModule, | ||||
|         AddonFilterMathJaxLoaderModule, | ||||
|         AddonFilterMediaPluginModule, | ||||
|         AddonFilterMultilangModule, | ||||
|         AddonFilterTexModule, | ||||
|         AddonFilterTidyModule, | ||||
|         AddonFilterUrlToLinkModule, | ||||
|     ], | ||||
|     providers: [], | ||||
|     exports: [], | ||||
| }) | ||||
| export class AddonFilterModule { } | ||||
							
								
								
									
										34
									
								
								src/addons/filter/glossary/glossary.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/glossary/glossary.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterGlossaryHandler } from './services/handlers/glossary'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterGlossaryHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterGlossaryModule {} | ||||
							
								
								
									
										46
									
								
								src/addons/filter/glossary/services/handlers/glossary.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/addons/filter/glossary/services/handlers/glossary.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| // (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Glossary auto-link filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterGlossaryHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterGlossaryHandler'; | ||||
|     filterName = 'glossary'; | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterGlossaryHandler extends makeSingleton(AddonFilterGlossaryHandlerService) {} | ||||
							
								
								
									
										38
									
								
								src/addons/filter/mathjaxloader/mathjaxloader.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/addons/filter/mathjaxloader/mathjaxloader.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterMathJaxLoaderHandler } from './services/handlers/mathjaxloader'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => async () => { | ||||
|                 CoreFilterDelegate.instance.registerHandler(AddonFilterMathJaxLoaderHandler.instance); | ||||
| 
 | ||||
|                 await AddonFilterMathJaxLoaderHandler.instance.initialize(); | ||||
|             }, | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterMathJaxLoaderModule {} | ||||
| @ -0,0 +1,413 @@ | ||||
| // (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, ViewContainerRef } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreLang } from '@services/lang'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { CoreEvents } from '@singletons/events'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the MathJax filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterMathJaxLoaderHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterMathJaxLoaderHandler'; | ||||
|     filterName = 'mathjaxloader'; | ||||
| 
 | ||||
|     // Default values for MathJax config for sites where we cannot retrieve it.
 | ||||
|     protected readonly DEFAULT_URL = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js'; | ||||
|     protected readonly DEFAULT_CONFIG = ` | ||||
|         MathJax.Hub.Config({ | ||||
|             extensions: [ | ||||
|                 "Safe.js", | ||||
|                 "tex2jax.js", | ||||
|                 "mml2jax.js", | ||||
|                 "MathEvents.js", | ||||
|                 "MathZoom.js", | ||||
|                 "MathMenu.js", | ||||
|                 "toMathML.js", | ||||
|                 "TeX/noErrors.js", | ||||
|                 "TeX/noUndefined.js", | ||||
|                 "TeX/AMSmath.js", | ||||
|                 "TeX/AMSsymbols.js", | ||||
|                 "fast-preview.js", | ||||
|                 "AssistiveMML.js", | ||||
|                 "[a11y]/accessibility-menu.js" | ||||
|             ], | ||||
|             jax: ["input/TeX","input/MathML","output/SVG"], | ||||
|             showMathMenu: false, | ||||
|             errorSettings: { message: ["!"] }, | ||||
|             skipStartupTypeset: true, | ||||
|             messageStyle: "none" | ||||
|         }); | ||||
|     `;
 | ||||
| 
 | ||||
|     // List of language codes found in the MathJax/localization/ directory.
 | ||||
|     protected readonly MATHJAX_LANG_CODES = [ | ||||
|         'ar', 'ast', 'bcc', 'bg', 'br', 'ca', 'cdo', 'ce', 'cs', 'cy', 'da', 'de', 'diq', 'en', 'eo', 'es', 'fa', | ||||
|         'fi', 'fr', 'gl', 'he', 'ia', 'it', 'ja', 'kn', 'ko', 'lb', 'lki', 'lt', 'mk', 'nl', 'oc', 'pl', 'pt', | ||||
|         'pt-br', 'qqq', 'ru', 'scn', 'sco', 'sk', 'sl', 'sv', 'th', 'tr', 'uk', 'vi', 'zh-hans', 'zh-hant', | ||||
|     ]; | ||||
| 
 | ||||
|     // List of explicit mappings and known exceptions (moodle => mathjax).
 | ||||
|     protected readonly EXPLICIT_MAPPING = { | ||||
|         'zh-tw': 'zh-hant', | ||||
|         'zh-cn': 'zh-hans', | ||||
|     }; | ||||
| 
 | ||||
|     protected window: MathJaxWindow = window; | ||||
| 
 | ||||
|     /** | ||||
|      * Initialize MathJax. | ||||
|      * | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     async initialize(): Promise<void> { | ||||
|         this.loadJS(); | ||||
| 
 | ||||
|         // Update MathJax locale if app language changes.
 | ||||
|         CoreEvents.on(CoreEvents.LANGUAGE_CHANGED, (lang: string) => { | ||||
|             if (typeof this.window.MathJax == 'undefined') { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             this.window.MathJax.Hub.Queue(() => { | ||||
|                 this.window.MathJax.Localization.setLocale(this.mapLanguageCode(lang)); | ||||
|             }); | ||||
|         }); | ||||
| 
 | ||||
|         // Get the current language.
 | ||||
|         const lang = await CoreLang.instance.getCurrentLanguage(); | ||||
| 
 | ||||
|         // Now call the configure function.
 | ||||
|         this.window.M!.filter_mathjaxloader!.configure({ | ||||
|             mathjaxconfig: this.DEFAULT_CONFIG, | ||||
|             lang: this.mapLanguageCode(lang), | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Filter some text. | ||||
|      * | ||||
|      * @param text The text to filter. | ||||
|      * @param filter The filter. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Filtered text (or promise resolved with the filtered text). | ||||
|      */ | ||||
|     async filter( | ||||
|         text: string, | ||||
|         filter: CoreFilterFilter, | ||||
|         options: CoreFilterFormatTextOptions, | ||||
|         siteId?: string, | ||||
|     ): Promise<string> { | ||||
| 
 | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
| 
 | ||||
|         // Don't apply this filter if Moodle is 3.7 or higher and the WS already filtered the content.
 | ||||
|         if (!options.wsNotFiltered && site.isVersionGreaterEqualThan('3.7')) { | ||||
|             return text; | ||||
|         } | ||||
| 
 | ||||
|         if (text.indexOf('class="filter_mathjaxloader_equation"') != -1) { | ||||
|             // The content seems to have treated mathjax already, don't do it.
 | ||||
|             return text; | ||||
|         } | ||||
| 
 | ||||
|         // We cannot get the filter settings, so we cannot know if it can be used as a replacement for the TeX filter.
 | ||||
|         // Assume it cannot (default value).
 | ||||
|         let hasDisplayOrInline = false; | ||||
|         if (text.match(/\\[[(]/) || text.match(/\$\$/)) { | ||||
|             // Only parse the text if there are mathjax symbols in it.
 | ||||
|             // The recognized math environments are \[ \] and $$ $$ for display mathematics and \( \) for inline mathematics.
 | ||||
|             // Wrap display and inline math environments in nolink spans.
 | ||||
|             const result = this.wrapMathInNoLink(text); | ||||
|             text = result.text; | ||||
|             hasDisplayOrInline = result.changed; | ||||
|         } | ||||
| 
 | ||||
|         if (hasDisplayOrInline) { | ||||
|             return '<span class="filter_mathjaxloader_equation">' + text + '</span>'; | ||||
|         } | ||||
| 
 | ||||
|         return text; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Handle HTML. This function is called after "filter", and it will receive an HTMLElement containing the text that was | ||||
|      * filtered. | ||||
|      * | ||||
|      * @param container The HTML container to handle. | ||||
|      * @param filter The filter. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param viewContainerRef The ViewContainerRef where the container is. | ||||
|      * @param component Component. | ||||
|      * @param componentId Component ID. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return If async, promise resolved when done. | ||||
|      */ | ||||
|     async handleHtml( | ||||
|         container: HTMLElement, | ||||
|         filter: CoreFilterFilter, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         options: CoreFilterFormatTextOptions, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         viewContainerRef: ViewContainerRef, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         component?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         componentId?: string | number, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         siteId?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|     ): Promise<void> { | ||||
|         await this.waitForReady(); | ||||
| 
 | ||||
|         this.window.M!.filter_mathjaxloader!.typeset(container); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Wrap a portion of the $text inside a no link span. The whole text is then returned. | ||||
|      * | ||||
|      * @param text The text to modify. | ||||
|      * @param start The start index of the substring in text that should be wrapped in the span. | ||||
|      * @param end The end index of the substring in text that should be wrapped in the span. | ||||
|      * @return The whole text with the span inserted around the defined substring. | ||||
|      */ | ||||
|     protected insertSpan(text: string, start: number, end: number): string { | ||||
|         return CoreTextUtils.instance.substrReplace( | ||||
|             text, | ||||
|             '<span class="nolink">' + text.substr(start, end - start + 1) + '</span>', | ||||
|             start, | ||||
|             end - start + 1, | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Load the JS to make MathJax work in the app. The JS loaded is extracted from Moodle filter's loader JS file. | ||||
|      */ | ||||
|     protected loadJS(): void { | ||||
|         // eslint-disable-next-line @typescript-eslint/no-this-alias
 | ||||
|         const that = this; | ||||
| 
 | ||||
|         this.window.M = this.window.M || {}; | ||||
|         this.window.M.filter_mathjaxloader = this.window.M.filter_mathjaxloader || { | ||||
|             _lang: '', // eslint-disable-line @typescript-eslint/naming-convention
 | ||||
|             _configured: false, // eslint-disable-line @typescript-eslint/naming-convention
 | ||||
|             // Add the configuration to the head and set the lang.
 | ||||
|             configure: function (params: Record<string, unknown>): void { | ||||
|                 // Add a js configuration object to the head.
 | ||||
|                 const script = document.createElement('script'); | ||||
|                 script.type = 'text/x-mathjax-config'; | ||||
|                 script.text = <string> params.mathjaxconfig; | ||||
|                 document.head.appendChild(script); | ||||
| 
 | ||||
|                 // Save the lang config until MathJax is actually loaded.
 | ||||
|                 this._lang = <string> params.lang; // eslint-disable-line no-underscore-dangle
 | ||||
|             }, | ||||
|             // Set the correct language for the MathJax menus.
 | ||||
|             _setLocale: function (): void { | ||||
|                 if (!this._configured) {  // eslint-disable-line no-underscore-dangle
 | ||||
|                     const lang = this._lang;  // eslint-disable-line no-underscore-dangle
 | ||||
| 
 | ||||
|                     if (typeof that.window.MathJax != 'undefined') { | ||||
|                         that.window.MathJax.Hub.Queue(() => { | ||||
|                             that.window.MathJax.Localization.setLocale(lang); | ||||
|                         }); | ||||
|                         that.window.MathJax.Hub.Configured(); | ||||
|                         this._configured = true;  // eslint-disable-line no-underscore-dangle
 | ||||
|                     } | ||||
|                 } | ||||
|             }, | ||||
|             // Called by the filter when an equation is found while rendering the page.
 | ||||
|             typeset: function (container: HTMLElement): void { | ||||
|                 if (!this._configured) { // eslint-disable-line no-underscore-dangle
 | ||||
|                     this._setLocale(); // eslint-disable-line no-underscore-dangle
 | ||||
|                 } | ||||
| 
 | ||||
|                 if (typeof that.window.MathJax != 'undefined') { | ||||
|                     const processDelay = that.window.MathJax.Hub.processSectionDelay; | ||||
|                     // Set the process section delay to 0 when updating the formula.
 | ||||
|                     that.window.MathJax.Hub.processSectionDelay = 0; | ||||
| 
 | ||||
|                     const equations = Array.from(container.querySelectorAll('.filter_mathjaxloader_equation')); | ||||
|                     equations.forEach((node) => { | ||||
|                         that.window.MathJax.Hub.Queue(['Typeset', that.window.MathJax.Hub, node]); | ||||
|                     }); | ||||
| 
 | ||||
|                     // Set the delay back to normal after processing.
 | ||||
|                     that.window.MathJax.Hub.processSectionDelay = processDelay; | ||||
|                 } | ||||
|             }, | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Perform a mapping of the app language code to the equivalent for MathJax. | ||||
|      * | ||||
|      * @param langCode The app language code. | ||||
|      * @return The MathJax language code. | ||||
|      */ | ||||
|     protected mapLanguageCode(langCode: string): string { | ||||
| 
 | ||||
|         // If defined, explicit mapping takes the highest precedence.
 | ||||
|         if (this.EXPLICIT_MAPPING[langCode]) { | ||||
|             return this.EXPLICIT_MAPPING[langCode]; | ||||
|         } | ||||
| 
 | ||||
|         // If there is exact match, it will be probably right.
 | ||||
|         if (this.MATHJAX_LANG_CODES.indexOf(langCode) != -1) { | ||||
|             return langCode; | ||||
|         } | ||||
| 
 | ||||
|         // Finally try to find the best matching mathjax pack.
 | ||||
|         const parts = langCode.split('-'); | ||||
|         if (this.MATHJAX_LANG_CODES.indexOf(parts[0]) != -1) { | ||||
|             return parts[0]; | ||||
|         } | ||||
| 
 | ||||
|         // No more guessing, use default language.
 | ||||
|         return CoreLang.instance.getDefaultLanguage(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // Only apply the filter if logged in and we're filtering current site.
 | ||||
|         return !!(site && site.getId() == CoreSites.instance.getCurrentSiteId()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Wait for the MathJax library and our JS object to be loaded. | ||||
|      * | ||||
|      * @param retries Number of times this has been retried. | ||||
|      * @return Promise resolved when ready or if it took too long to load. | ||||
|      */ | ||||
|     protected async waitForReady(retries: number = 0): Promise<void> { | ||||
|         if (this.window.MathJax || retries >= 20) { | ||||
|             // Loaded or too many retries, stop.
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const deferred = CoreUtils.instance.promiseDefer<void>(); | ||||
| 
 | ||||
|         setTimeout(async () => { | ||||
|             try { | ||||
|                 await this.waitForReady(retries + 1); | ||||
|             } finally { | ||||
|                 deferred.resolve(); | ||||
|             } | ||||
|         }, 250); | ||||
| 
 | ||||
|         return deferred.promise; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Find math environments in the $text and wrap them in no link spans | ||||
|      * (<span class="nolink"></span>). If math environments are nested, only | ||||
|      * the outer environment is wrapped in the span. | ||||
|      * | ||||
|      * The recognized math environments are \[ \] and $$ $$ for display | ||||
|      * mathematics and \( \) for inline mathematics. | ||||
|      * | ||||
|      * @param text The text to filter. | ||||
|      * @return Object containing the potentially modified text and a boolean that is true if any changes were made to the text. | ||||
|      */ | ||||
|     protected wrapMathInNoLink(text: string): {text: string; changed: boolean} { | ||||
|         let len = text.length; | ||||
|         let i = 1; | ||||
|         let displayStart = -1; | ||||
|         let displayBracket = false; | ||||
|         let displayDollar = false; | ||||
|         let inlineStart = -1; | ||||
|         let changesDone = false; | ||||
| 
 | ||||
|         // Loop over the $text once.
 | ||||
|         while (i < len) { | ||||
|             if (displayStart === -1) { | ||||
|                 // No display math has started yet.
 | ||||
|                 if (text[i - 1] === '\\') { | ||||
| 
 | ||||
|                     if (text[i] === '[') { | ||||
|                         // Display mode \[ begins.
 | ||||
|                         displayStart = i - 1; | ||||
|                         displayBracket = true; | ||||
|                     } else if (text[i] === '(') { | ||||
|                         // Inline math \( begins, not nested inside display math.
 | ||||
|                         inlineStart = i - 1; | ||||
|                     } else if (text[i] === ')' && inlineStart > -1) { | ||||
|                         // Inline math ends, not nested inside display math. Wrap the span around it.
 | ||||
|                         text = this.insertSpan(text, inlineStart, i); | ||||
| 
 | ||||
|                         inlineStart = -1; // Reset.
 | ||||
|                         i += 28; // The text length changed due to the <span>.
 | ||||
|                         len += 28; | ||||
|                         changesDone = true; | ||||
|                     } | ||||
| 
 | ||||
|                 } else if (text[i - 1] === '$' && text[i] === '$') { | ||||
|                     // Display mode $$ begins.
 | ||||
|                     displayStart = i - 1; | ||||
|                     displayDollar = true; | ||||
|                 } | ||||
| 
 | ||||
|             } else { | ||||
|                 // Display math open.
 | ||||
|                 if ((text[i - 1] === '\\' && text[i] === ']' && displayBracket) || | ||||
|                         (text[i - 1] === '$' && text[i] === '$' && displayDollar)) { | ||||
|                     // Display math ends, wrap the span around it.
 | ||||
|                     text = this.insertSpan(text, displayStart, i); | ||||
| 
 | ||||
|                     displayStart = -1; // Reset.
 | ||||
|                     displayBracket = false; | ||||
|                     displayDollar = false; | ||||
|                     i += 28; // The text length changed due to the <span>.
 | ||||
|                     len += 28; | ||||
|                     changesDone = true; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             i++; | ||||
|         } | ||||
| 
 | ||||
|         return { | ||||
|             text: text, | ||||
|             changed: changesDone, | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterMathJaxLoaderHandler extends makeSingleton(AddonFilterMathJaxLoaderHandlerService) {} | ||||
| 
 | ||||
| type MathJaxWindow = Window & { | ||||
|     MathJax?: any; // eslint-disable-line @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any
 | ||||
|     M?: { // eslint-disable-line @typescript-eslint/naming-convention
 | ||||
|         filter_mathjaxloader?: { // eslint-disable-line @typescript-eslint/naming-convention
 | ||||
|             _lang: ''; // eslint-disable-line @typescript-eslint/naming-convention
 | ||||
|             _configured: false; // eslint-disable-line @typescript-eslint/naming-convention
 | ||||
|             // Add the configuration to the head and set the lang.
 | ||||
|             configure: (params: Record<string, unknown>) => void; | ||||
|             _setLocale: () => void; // eslint-disable-line @typescript-eslint/naming-convention
 | ||||
|             typeset: (container: HTMLElement) => void; | ||||
|         }; | ||||
|     }; | ||||
| }; | ||||
							
								
								
									
										34
									
								
								src/addons/filter/mediaplugin/mediaplugin.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/mediaplugin/mediaplugin.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterMediaPluginHandler } from './services/handlers/mediaplugin'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterMediaPluginHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterMediaPluginModule {} | ||||
							
								
								
									
										101
									
								
								src/addons/filter/mediaplugin/services/handlers/mediaplugin.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/addons/filter/mediaplugin/services/handlers/mediaplugin.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | ||||
| // (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { CoreUrlUtils } from '@services/utils/url'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Multimedia filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterMediaPluginHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterMediaPluginHandler'; | ||||
|     filterName = 'mediaplugin'; | ||||
| 
 | ||||
|     protected template = document.createElement('template'); // A template element to convert HTML to element.
 | ||||
| 
 | ||||
|     /** | ||||
|      * Filter some text. | ||||
|      * | ||||
|      * @param text The text to filter. | ||||
|      * @param filter The filter. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Filtered text (or promise resolved with the filtered text). | ||||
|      */ | ||||
|     filter( | ||||
|         text: string, | ||||
|         filter: CoreFilterFilter, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         options: CoreFilterFormatTextOptions, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         siteId?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|     ): string | Promise<string> { | ||||
|         this.template.innerHTML = text; | ||||
| 
 | ||||
|         const videos = Array.from(this.template.content.querySelectorAll('video')); | ||||
| 
 | ||||
|         videos.forEach((video) => { | ||||
|             this.treatVideoFilters(video); | ||||
|         }); | ||||
| 
 | ||||
|         return this.template.innerHTML; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Treat video filters. Currently only treating youtube video using video JS. | ||||
|      * | ||||
|      * @param el Video element. | ||||
|      * @param navCtrl NavController to use. | ||||
|      */ | ||||
|     protected treatVideoFilters(video: HTMLElement): void { | ||||
|         // Treat Video JS Youtube video links and translate them to iframes.
 | ||||
|         if (!video.classList.contains('video-js')) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const dataSetupString = video.getAttribute('data-setup') || video.getAttribute('data-setup-lazy') || '{}'; | ||||
|         const data = <VideoDataSetup> CoreTextUtils.instance.parseJSON(dataSetupString, {}); | ||||
|         const youtubeUrl = data.techOrder?.[0] == 'youtube' && CoreUrlUtils.instance.getYoutubeEmbedUrl(data.sources?.[0]?.src); | ||||
| 
 | ||||
|         if (!youtubeUrl) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const iframe = document.createElement('iframe'); | ||||
|         iframe.id = video.id; | ||||
|         iframe.src = youtubeUrl; | ||||
|         iframe.setAttribute('frameborder', '0'); | ||||
|         iframe.setAttribute('allowfullscreen', '1'); | ||||
|         iframe.width = '100%'; | ||||
|         iframe.height = '300'; | ||||
| 
 | ||||
|         // Replace video tag by the iframe.
 | ||||
|         video.parentNode?.replaceChild(iframe, video); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterMediaPluginHandler extends makeSingleton(AddonFilterMediaPluginHandlerService) {} | ||||
| 
 | ||||
| type VideoDataSetup = { | ||||
|     techOrder?: string[]; | ||||
|     sources?: { | ||||
|         src?: string; | ||||
|     }[]; | ||||
| }; | ||||
							
								
								
									
										34
									
								
								src/addons/filter/multilang/multilang.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/multilang/multilang.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterMultilangHandler } from './services/handlers/multilang'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterMultilangHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterMultilangModule {} | ||||
							
								
								
									
										87
									
								
								src/addons/filter/multilang/services/handlers/multilang.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/addons/filter/multilang/services/handlers/multilang.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | ||||
| // (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 { CoreLang } from '@services/lang'; | ||||
| import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the Multilang filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterMultilangHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterMultilangHandler'; | ||||
|     filterName = 'multilang'; | ||||
| 
 | ||||
|     /** | ||||
|      * Filter some text. | ||||
|      * | ||||
|      * @param text The text to filter. | ||||
|      * @param filter The filter. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Filtered text (or promise resolved with the filtered text). | ||||
|      */ | ||||
|     async filter( | ||||
|         text: string, | ||||
|         filter: CoreFilterFilter, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         options: CoreFilterFormatTextOptions, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         siteId?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|     ): Promise<string> { | ||||
|         let language = await CoreLang.instance.getCurrentLanguage(); | ||||
| 
 | ||||
|         // Match the current language.
 | ||||
|         const anyLangRegEx = /<(?:lang|span)[^>]+lang="[a-zA-Z0-9_-]+"[^>]*>(.*?)<\/(?:lang|span)>/g; | ||||
|         let currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)</(?:lang|span)>', 'g'); | ||||
| 
 | ||||
|         if (!text.match(currentLangRegEx)) { | ||||
|             // Current lang not found. Try to find the first language.
 | ||||
|             const matches = text.match(anyLangRegEx); | ||||
|             if (matches?.[0]) { | ||||
|                 language = matches[0].match(/lang="([a-zA-Z0-9_-]+)"/)?.[1] || language; | ||||
|                 currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)</(?:lang|span)>', 'g'); | ||||
|             } else { | ||||
|                 // No multi-lang tag found, stop.
 | ||||
|                 return text; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Extract contents of current language.
 | ||||
|         text = text.replace(currentLangRegEx, '$1'); | ||||
|         // Delete the rest of languages
 | ||||
|         text = text.replace(anyLangRegEx, ''); | ||||
| 
 | ||||
|         return text; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // The filter should be applied if site is older than 3.7 or the WS didn't filter the text.
 | ||||
|         return !!(options.wsNotFiltered || (site && !site.isVersionGreaterEqualThan('3.7'))); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterMultilangHandler extends makeSingleton(AddonFilterMultilangHandlerService) {} | ||||
							
								
								
									
										46
									
								
								src/addons/filter/tex/services/handlers/tex.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/addons/filter/tex/services/handlers/tex.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| // (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the TeX notation filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterTexHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterTexHandler'; | ||||
|     filterName = 'tex'; | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterTexHandler extends makeSingleton(AddonFilterTexHandlerService) {} | ||||
							
								
								
									
										34
									
								
								src/addons/filter/tex/tex.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/tex/tex.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterTexHandler } from './services/handlers/tex'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterTexHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterTexModule {} | ||||
							
								
								
									
										46
									
								
								src/addons/filter/tidy/services/handlers/tidy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/addons/filter/tidy/services/handlers/tidy.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| // (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the HTML tidy filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterTidyHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterTidyHandler'; | ||||
|     filterName = 'tidy'; | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterTidyHandler extends makeSingleton(AddonFilterTidyHandlerService) {} | ||||
							
								
								
									
										34
									
								
								src/addons/filter/tidy/tidy.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/tidy/tidy.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterTidyHandler } from './services/handlers/tidy'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterTidyHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterTidyModule {} | ||||
							
								
								
									
										46
									
								
								src/addons/filter/urltolink/services/handlers/urltolink.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/addons/filter/urltolink/services/handlers/urltolink.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| // (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; | ||||
| import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support the URL to link and images filter. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonFilterUrlToLinkHandlerService extends CoreFilterDefaultHandler { | ||||
| 
 | ||||
|     name = 'AddonFilterUrlToLinkHandler'; | ||||
|     filterName = 'urltolink'; | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         // This filter is handled by Moodle, nothing to do in the app.
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonFilterUrlToLinkHandler extends makeSingleton(AddonFilterUrlToLinkHandlerService) {} | ||||
							
								
								
									
										34
									
								
								src/addons/filter/urltolink/urltolink.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/addons/filter/urltolink/urltolink.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| // (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 } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { AddonFilterUrlToLinkHandler } from './services/handlers/urltolink'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|     ], | ||||
|     imports: [ | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => CoreFilterDelegate.instance.registerHandler(AddonFilterUrlToLinkHandler.instance), | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonFilterUrlToLinkModule {} | ||||
| @ -12,16 +12,16 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { APP_INITIALIZER, NgModule } from '@angular/core'; | ||||
| import { Routes } from '@angular/router'; | ||||
| 
 | ||||
| import { CoreMainMenuDelegate } from '@features/mainmenu/services/mainmenu-delegate'; | ||||
| import { CoreMainMenuRoutingModule } from '@features/mainmenu/mainmenu-routing.module'; | ||||
| import { AddonPrivateFilesMainMenuHandler } from './services/handlers/mainmenu'; | ||||
| import { AddonPrivateFilesMainMenuHandler, AddonPrivateFilesMainMenuHandlerService } from './services/handlers/mainmenu'; | ||||
| 
 | ||||
| const routes: Routes = [ | ||||
|     { | ||||
|         path: AddonPrivateFilesMainMenuHandler.PAGE_NAME, | ||||
|         path: AddonPrivateFilesMainMenuHandlerService.PAGE_NAME, | ||||
|         loadChildren: () => import('@/addons/privatefiles/privatefiles-lazy.module').then(m => m.AddonPrivateFilesLazyModule), | ||||
|     }, | ||||
| ]; | ||||
| @ -30,16 +30,14 @@ const routes: Routes = [ | ||||
|     imports: [CoreMainMenuRoutingModule.forChild({ children: routes })], | ||||
|     exports: [CoreMainMenuRoutingModule], | ||||
|     providers: [ | ||||
|         AddonPrivateFilesMainMenuHandler, | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => { | ||||
|                 CoreMainMenuDelegate.instance.registerHandler(AddonPrivateFilesMainMenuHandler.instance); | ||||
|             }, | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonPrivateFilesModule { | ||||
| 
 | ||||
|     constructor( | ||||
|         mainMenuDelegate: CoreMainMenuDelegate, | ||||
|         mainMenuHandler: AddonPrivateFilesMainMenuHandler, | ||||
|     ) { | ||||
|         mainMenuDelegate.registerHandler(mainMenuHandler); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| export class AddonPrivateFilesModule {} | ||||
|  | ||||
| @ -16,12 +16,13 @@ import { Injectable } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@features/mainmenu/services/mainmenu-delegate'; | ||||
| import { AddonPrivateFiles } from '@/addons/privatefiles/services/privatefiles'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to inject an option into main menu. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonPrivateFilesMainMenuHandler implements CoreMainMenuHandler { | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonPrivateFilesMainMenuHandlerService implements CoreMainMenuHandler { | ||||
| 
 | ||||
|     static readonly PAGE_NAME = 'private'; | ||||
| 
 | ||||
| @ -46,10 +47,12 @@ export class AddonPrivateFilesMainMenuHandler implements CoreMainMenuHandler { | ||||
|         return { | ||||
|             icon: 'fas-folder', | ||||
|             title: 'addon.privatefiles.files', | ||||
|             page: AddonPrivateFilesMainMenuHandler.PAGE_NAME, | ||||
|             page: AddonPrivateFilesMainMenuHandlerService.PAGE_NAME, | ||||
|             subPage: 'root', | ||||
|             class: 'addon-privatefiles-handler', | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonPrivateFilesMainMenuHandler extends makeSingleton(AddonPrivateFilesMainMenuHandlerService) {} | ||||
|  | ||||
| @ -124,7 +124,7 @@ export class CoreDelegate<HandlerType extends CoreDelegateHandler> { | ||||
|      * @return Function returned value or default value. | ||||
|      */ | ||||
|     protected executeFunction<T = unknown>(handlerName: string, fnName: string, params?: unknown[]): T | undefined { | ||||
|         return this.execute(this.handlers[handlerName], fnName, params); | ||||
|         return this.execute<T>(this.handlers[handlerName], fnName, params); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -60,9 +60,7 @@ export class CoreFileComponent implements OnInit, OnDestroy { | ||||
|     protected fileSize?: number; | ||||
|     protected observer?: CoreEventObserver; | ||||
| 
 | ||||
|     constructor( | ||||
|         protected pluginFileDelegate: CorePluginFileDelegate, | ||||
|     ) { | ||||
|     constructor() { | ||||
|         this.onDelete = new EventEmitter<void>(); | ||||
|     } | ||||
| 
 | ||||
| @ -195,7 +193,7 @@ export class CoreFileComponent implements OnInit, OnDestroy { | ||||
|         } else { | ||||
|             try { | ||||
|                 // File doesn't need to be opened (it's a prefetch). Show confirm modal if file size is defined and it's big.
 | ||||
|                 const size = await this.pluginFileDelegate.getFileSize(this.file, this.siteId); | ||||
|                 const size = await CorePluginFileDelegate.instance.getFileSize(this.file, this.siteId); | ||||
| 
 | ||||
|                 if (size) { | ||||
|                     await CoreDomUtils.instance.confirmDownloadSize({ size: size, total: true }); | ||||
|  | ||||
| @ -12,7 +12,17 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Directive, ElementRef, Input, Output, EventEmitter, OnChanges, SimpleChange, Optional } from '@angular/core'; | ||||
| import { | ||||
|     Directive, | ||||
|     ElementRef, | ||||
|     Input, | ||||
|     Output, | ||||
|     EventEmitter, | ||||
|     OnChanges, | ||||
|     SimpleChange, | ||||
|     Optional, | ||||
|     ViewContainerRef, | ||||
| } from '@angular/core'; | ||||
| import { NavController, IonContent } from '@ionic/angular'; | ||||
| 
 | ||||
| import { CoreEventLoadingChangedData, CoreEventObserver, CoreEvents } from '@singletons/events'; | ||||
| @ -25,6 +35,9 @@ import { CoreSite } from '@classes/site'; | ||||
| import { Translate } from '@singletons'; | ||||
| import { CoreExternalContentDirective } from './external-content'; | ||||
| import { CoreLinkDirective } from './link'; | ||||
| import { CoreFilter, CoreFilterFilter, CoreFilterFormatTextOptions } from '@features/filter/services/filter'; | ||||
| import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; | ||||
| import { CoreFilterHelper } from '@features/filter/services/filter-helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective | ||||
| @ -73,6 +86,7 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
|         element: ElementRef, | ||||
|         @Optional() protected navCtrl: NavController, | ||||
|         @Optional() protected content: IonContent, | ||||
|         protected viewContainerRef: ViewContainerRef, | ||||
|     ) { | ||||
| 
 | ||||
|         this.element = element.nativeElement; | ||||
| @ -371,8 +385,17 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
|         } | ||||
| 
 | ||||
|         if (result.options.filter) { | ||||
|             // Let filters hnadle HTML. We do it here because we don't want them to block the render of the text.
 | ||||
|             // @todo
 | ||||
|             // Let filters handle HTML. We do it here because we don't want them to block the render of the text.
 | ||||
|             CoreFilterDelegate.instance.handleHtml( | ||||
|                 this.element, | ||||
|                 result.filters, | ||||
|                 this.viewContainerRef, | ||||
|                 result.options, | ||||
|                 [], | ||||
|                 this.component, | ||||
|                 this.componentId, | ||||
|                 result.siteId, | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         this.element.classList.remove('core-disable-media-adapt'); | ||||
| @ -388,6 +411,8 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
|         // Retrieve the site since it might be needed later.
 | ||||
|         const site = await CoreUtils.instance.ignoreErrors(CoreSites.instance.getSite(this.siteId)); | ||||
| 
 | ||||
|         const siteId = site?.getId(); | ||||
| 
 | ||||
|         if (site && this.contextLevel == 'course' && this.contextInstanceId !== undefined && this.contextInstanceId <= 0) { | ||||
|             this.contextInstanceId = site.getSiteHomeId(); | ||||
|         } | ||||
| @ -395,7 +420,7 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
|         const filter = typeof this.filter == 'undefined' ? | ||||
|             !!(this.contextLevel && typeof this.contextInstanceId != 'undefined') : CoreUtils.instance.isTrueOrOne(this.filter); | ||||
| 
 | ||||
|         const options = { | ||||
|         const options: CoreFilterFormatTextOptions = { | ||||
|             clean: CoreUtils.instance.isTrueOrOne(this.clean), | ||||
|             singleLine: CoreUtils.instance.isTrueOrOne(this.singleLine), | ||||
|             highlight: this.highlight, | ||||
| @ -404,13 +429,21 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
|         }; | ||||
| 
 | ||||
|         let formatted: string; | ||||
|         let filters: CoreFilterFilter[] = []; | ||||
| 
 | ||||
|         if (filter) { | ||||
|             // @todo
 | ||||
|             formatted = this.text!; | ||||
|             const filterResult = await CoreFilterHelper.instance.getFiltersAndFormatText( | ||||
|                 this.text || '', | ||||
|                 this.contextLevel || '', | ||||
|                 this.contextInstanceId ?? -1, | ||||
|                 options, | ||||
|                 siteId, | ||||
|             ); | ||||
| 
 | ||||
|             filters = filterResult.filters; | ||||
|             formatted = filterResult.text; | ||||
|         } else { | ||||
|             // @todo
 | ||||
|             formatted = this.text!; | ||||
|             formatted = await CoreFilter.instance.formatText(this.text || '', options, [], siteId); | ||||
|         } | ||||
| 
 | ||||
|         formatted = this.treatWindowOpen(formatted); | ||||
| @ -423,9 +456,9 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
| 
 | ||||
|         return { | ||||
|             div, | ||||
|             filters: [], | ||||
|             filters, | ||||
|             options, | ||||
|             siteId: site?.getId(), | ||||
|             siteId, | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
| @ -747,7 +780,7 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
| 
 | ||||
| type FormatContentsResult = { | ||||
|     div: HTMLElement; | ||||
|     filters: any[]; | ||||
|     options: any; | ||||
|     filters: CoreFilterFilter[]; | ||||
|     options: CoreFilterFormatTextOptions; | ||||
|     siteId?: string; | ||||
| }; | ||||
|  | ||||
| @ -18,6 +18,7 @@ import { CoreSites } from '@services/sites'; | ||||
| import { CoreUrlUtils } from '@services/utils/url'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { Params } from '@angular/router'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Interface that all handlers must implement. | ||||
| @ -132,10 +133,8 @@ export interface CoreContentLinksHandlerActions { | ||||
| /** | ||||
|  * Delegate to register handlers to handle links. | ||||
|  */ | ||||
| @Injectable({ | ||||
|     providedIn: 'root', | ||||
| }) | ||||
| export class CoreContentLinksDelegate { | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreContentLinksDelegateService { | ||||
| 
 | ||||
|     protected logger: CoreLogger; | ||||
|     protected handlers: { [s: string]: CoreContentLinksHandler } = {}; // All registered handlers.
 | ||||
| @ -307,3 +306,5 @@ export class CoreContentLinksDelegate { | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreContentLinksDelegate extends makeSingleton(CoreContentLinksDelegateService) {} | ||||
|  | ||||
| @ -33,7 +33,6 @@ import { Params } from '@angular/router'; | ||||
| export class CoreContentLinksHelperProvider { | ||||
| 
 | ||||
|     constructor( | ||||
|         protected contentLinksDelegate: CoreContentLinksDelegate, | ||||
|         protected navCtrl: NavController, | ||||
|     ) { } | ||||
| 
 | ||||
| @ -80,7 +79,7 @@ export class CoreContentLinksHelperProvider { | ||||
|         username?: string, | ||||
|         data?: unknown, | ||||
|     ): Promise<CoreContentLinksAction | undefined> { | ||||
|         const actions = await this.contentLinksDelegate.getActionsFor(url, courseId, username, data); | ||||
|         const actions = await CoreContentLinksDelegate.instance.getActionsFor(url, courseId, username, data); | ||||
|         if (!actions) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
| @ -12,27 +12,27 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { APP_INITIALIZER, NgModule } from '@angular/core'; | ||||
| import { Routes } from '@angular/router'; | ||||
| 
 | ||||
| import { CoreMainMenuHomeRoutingModule } from '@features/mainmenu/pages/home/home-routing.module'; | ||||
| import { CoreMainMenuHomeDelegate } from '@features/mainmenu/services/home-delegate'; | ||||
| 
 | ||||
| import { CoreDashboardHomeHandler } from './services/handlers/dashboard-home'; | ||||
| import { CoreCoursesMyCoursesHomeHandler } from './services/handlers/my-courses.home'; | ||||
| import { CoreDashboardHomeHandler, CoreDashboardHomeHandlerService } from './services/handlers/dashboard-home'; | ||||
| import { CoreCoursesMyCoursesHomeHandler, CoreCoursesMyCoursesHomeHandlerService } from './services/handlers/my-courses.home'; | ||||
| 
 | ||||
| const mainMenuHomeChildrenRoutes: Routes = [ | ||||
|     { | ||||
|         path: '', | ||||
|         pathMatch: 'full', | ||||
|         redirectTo: CoreDashboardHomeHandler.PAGE_NAME, | ||||
|         redirectTo: CoreDashboardHomeHandlerService.PAGE_NAME, | ||||
|     }, | ||||
|     { | ||||
|         path: CoreDashboardHomeHandler.PAGE_NAME, | ||||
|         path: CoreDashboardHomeHandlerService.PAGE_NAME, | ||||
|         loadChildren: () => import('./pages/dashboard/dashboard.module').then(m => m.CoreCoursesDashboardPageModule), | ||||
|     }, | ||||
|     { | ||||
|         path: CoreCoursesMyCoursesHomeHandler.PAGE_NAME, | ||||
|         path: CoreCoursesMyCoursesHomeHandlerService.PAGE_NAME, | ||||
|         loadChildren: () => import('./pages/my-courses/my-courses.module').then(m => m.CoreCoursesMyCoursesPageModule), | ||||
|     }, | ||||
| ]; | ||||
| @ -52,19 +52,15 @@ const mainMenuHomeSiblingRoutes: Routes = [ | ||||
|         }), | ||||
|     ], | ||||
|     providers: [ | ||||
|         CoreDashboardHomeHandler, | ||||
|         CoreCoursesMyCoursesHomeHandler, | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => { | ||||
|                 CoreMainMenuHomeDelegate.instance.registerHandler(CoreDashboardHomeHandler.instance); | ||||
|                 CoreMainMenuHomeDelegate.instance.registerHandler(CoreCoursesMyCoursesHomeHandler.instance); | ||||
|             }, | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class CoreCoursesModule { | ||||
| 
 | ||||
|     constructor( | ||||
|         homeDelegate: CoreMainMenuHomeDelegate, | ||||
|         coursesDashboardHandler: CoreDashboardHomeHandler, | ||||
|         coursesMyCoursesHandler: CoreCoursesMyCoursesHomeHandler, | ||||
|     ) { | ||||
|         homeDelegate.registerHandler(coursesDashboardHandler); | ||||
|         homeDelegate.registerHandler(coursesMyCoursesHandler); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| export class CoreCoursesModule {} | ||||
|  | ||||
| @ -14,12 +14,13 @@ | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreMainMenuHomeHandler, CoreMainMenuHomeHandlerToDisplay } from '@features/mainmenu/services/home-delegate'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to add dashboard into home page. | ||||
|  */ | ||||
| Injectable(); | ||||
| export class CoreDashboardHomeHandler implements CoreMainMenuHomeHandler { | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreDashboardHomeHandlerService implements CoreMainMenuHomeHandler { | ||||
| 
 | ||||
|     static readonly PAGE_NAME = 'dashboard'; | ||||
| 
 | ||||
| @ -55,7 +56,7 @@ export class CoreDashboardHomeHandler implements CoreMainMenuHomeHandler { | ||||
|     getDisplayData(): CoreMainMenuHomeHandlerToDisplay { | ||||
|         return { | ||||
|             title: 'core.courses.mymoodle', | ||||
|             page: CoreDashboardHomeHandler.PAGE_NAME, | ||||
|             page: CoreDashboardHomeHandlerService.PAGE_NAME, | ||||
|             class: 'core-courses-dashboard-handler', | ||||
|             icon: 'fas-tachometer-alt', | ||||
|             selectPriority: 1000, | ||||
| @ -63,3 +64,5 @@ export class CoreDashboardHomeHandler implements CoreMainMenuHomeHandler { | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreDashboardHomeHandler extends makeSingleton(CoreDashboardHomeHandlerService) {} | ||||
|  | ||||
| @ -14,12 +14,13 @@ | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreMainMenuHomeHandler, CoreMainMenuHomeHandlerToDisplay } from '@features/mainmenu/services/home-delegate'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to add my courses into home page. | ||||
|  */ | ||||
| Injectable(); | ||||
| export class CoreCoursesMyCoursesHomeHandler implements CoreMainMenuHomeHandler { | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreCoursesMyCoursesHomeHandlerService implements CoreMainMenuHomeHandler { | ||||
| 
 | ||||
|     static readonly PAGE_NAME = 'courses'; | ||||
| 
 | ||||
| @ -55,7 +56,7 @@ export class CoreCoursesMyCoursesHomeHandler implements CoreMainMenuHomeHandler | ||||
|     getDisplayData(): CoreMainMenuHomeHandlerToDisplay { | ||||
|         return { | ||||
|             title: 'core.courses.mycourses', | ||||
|             page: CoreCoursesMyCoursesHomeHandler.PAGE_NAME, | ||||
|             page: CoreCoursesMyCoursesHomeHandlerService.PAGE_NAME, | ||||
|             class: 'core-courses-my-courses-handler', | ||||
|             icon: 'fas-graduation-cap', | ||||
|             selectPriority: 900, | ||||
| @ -63,3 +64,5 @@ export class CoreCoursesMyCoursesHomeHandler implements CoreMainMenuHomeHandler | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreCoursesMyCoursesHomeHandler extends makeSingleton(CoreCoursesMyCoursesHomeHandlerService) {} | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { APP_INITIALIZER, NgModule } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFileUploaderDelegate } from './services/fileuploader-delegate'; | ||||
| import { CoreFileUploaderAlbumHandler } from './services/handlers/album'; | ||||
| @ -26,28 +26,18 @@ import { CoreFileUploaderVideoHandler } from './services/handlers/video'; | ||||
|     imports: [], | ||||
|     declarations: [], | ||||
|     providers: [ | ||||
|         CoreFileUploaderAlbumHandler, | ||||
|         CoreFileUploaderAudioHandler, | ||||
|         CoreFileUploaderCameraHandler, | ||||
|         CoreFileUploaderFileHandler, | ||||
|         CoreFileUploaderVideoHandler, | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => { | ||||
|                 CoreFileUploaderDelegate.instance.registerHandler(CoreFileUploaderAlbumHandler.instance); | ||||
|                 CoreFileUploaderDelegate.instance.registerHandler(CoreFileUploaderAudioHandler.instance); | ||||
|                 CoreFileUploaderDelegate.instance.registerHandler(CoreFileUploaderCameraHandler.instance); | ||||
|                 CoreFileUploaderDelegate.instance.registerHandler(CoreFileUploaderVideoHandler.instance); | ||||
|                 CoreFileUploaderDelegate.instance.registerHandler(CoreFileUploaderFileHandler.instance); | ||||
|             }, | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class CoreFileUploaderModule { | ||||
| 
 | ||||
|     constructor( | ||||
|         delegate: CoreFileUploaderDelegate, | ||||
|         albumHandler: CoreFileUploaderAlbumHandler, | ||||
|         audioHandler: CoreFileUploaderAudioHandler, | ||||
|         cameraHandler: CoreFileUploaderCameraHandler, | ||||
|         videoHandler: CoreFileUploaderVideoHandler, | ||||
|         fileHandler: CoreFileUploaderFileHandler, | ||||
|     ) { | ||||
|         delegate.registerHandler(albumHandler); | ||||
|         delegate.registerHandler(audioHandler); | ||||
|         delegate.registerHandler(cameraHandler); | ||||
|         delegate.registerHandler(videoHandler); | ||||
|         delegate.registerHandler(fileHandler); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| export class CoreFileUploaderModule {} | ||||
|  | ||||
| @ -18,6 +18,7 @@ import { FileEntry } from '@ionic-native/file'; | ||||
| import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; | ||||
| import { CoreEvents } from '@singletons/events'; | ||||
| import { CoreWSUploadFileResult } from '@services/ws'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Interface that all handlers must implement. | ||||
| @ -141,7 +142,7 @@ export interface CoreFileUploaderHandlerDataToReturn extends CoreFileUploaderHan | ||||
| @Injectable({ | ||||
|     providedIn: 'root', | ||||
| }) | ||||
| export class CoreFileUploaderDelegate extends CoreDelegate<CoreFileUploaderHandler> { | ||||
| export class CoreFileUploaderDelegateService extends CoreDelegate<CoreFileUploaderHandler> { | ||||
| 
 | ||||
|     constructor() { | ||||
|         super('CoreFileUploaderDelegate', true); | ||||
| @ -196,3 +197,5 @@ export class CoreFileUploaderDelegate extends CoreDelegate<CoreFileUploaderHandl | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreFileUploaderDelegate extends makeSingleton(CoreFileUploaderDelegateService) {} | ||||
|  | ||||
| @ -47,7 +47,7 @@ export class CoreFileUploaderHelperProvider { | ||||
|     protected filePickerDeferred?: PromiseDefer<CoreWSUploadFileResult | FileEntry>; | ||||
|     protected actionSheet?: HTMLIonActionSheetElement; | ||||
| 
 | ||||
|     constructor(protected uploaderDelegate: CoreFileUploaderDelegate) { | ||||
|     constructor() { | ||||
|         this.logger = CoreLogger.getInstance('CoreFileUploaderHelperProvider'); | ||||
|     } | ||||
| 
 | ||||
| @ -351,7 +351,7 @@ export class CoreFileUploaderHelperProvider { | ||||
|                 this.filePickerClosed(); | ||||
|             }, | ||||
|         }]; | ||||
|         const handlers = this.uploaderDelegate.getHandlers(mimetypes); | ||||
|         const handlers = CoreFileUploaderDelegate.instance.getHandlers(mimetypes); | ||||
| 
 | ||||
|         this.filePickerDeferred = CoreUtils.instance.promiseDefer(); | ||||
| 
 | ||||
|  | ||||
| @ -16,14 +16,15 @@ import { Injectable } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreApp } from '@services/app'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { CoreFileUploaderHandler, CoreFileUploaderHandlerData, CoreFileUploaderHandlerResult } from '../fileuploader-delegate'; | ||||
| import { CoreFileUploaderHelper } from '../fileuploader-helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to upload files from the album. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class CoreFileUploaderAlbumHandler implements CoreFileUploaderHandler { | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreFileUploaderAlbumHandlerService implements CoreFileUploaderHandler { | ||||
| 
 | ||||
|     name = 'CoreFileUploaderAlbum'; | ||||
|     priority = 2000; | ||||
| @ -75,3 +76,5 @@ export class CoreFileUploaderAlbumHandler implements CoreFileUploaderHandler { | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreFileUploaderAlbumHandler extends makeSingleton(CoreFileUploaderAlbumHandlerService) {} | ||||
|  | ||||
| @ -16,13 +16,14 @@ import { Injectable } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreApp } from '@services/app'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { CoreFileUploaderHandler, CoreFileUploaderHandlerData, CoreFileUploaderHandlerResult } from '../fileuploader-delegate'; | ||||
| import { CoreFileUploaderHelper } from '../fileuploader-helper'; | ||||
| /** | ||||
|  * Handler to record an audio to upload it. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class CoreFileUploaderAudioHandler implements CoreFileUploaderHandler { | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreFileUploaderAudioHandlerService implements CoreFileUploaderHandler { | ||||
| 
 | ||||
|     name = 'CoreFileUploaderAudio'; | ||||
|     priority = 1600; | ||||
| @ -90,3 +91,5 @@ export class CoreFileUploaderAudioHandler implements CoreFileUploaderHandler { | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreFileUploaderAudioHandler extends makeSingleton(CoreFileUploaderAudioHandlerService) {} | ||||
| @ -16,14 +16,15 @@ import { Injectable } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreApp } from '@services/app'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { CoreFileUploaderHandler, CoreFileUploaderHandlerData, CoreFileUploaderHandlerResult } from '../fileuploader-delegate'; | ||||
| import { CoreFileUploaderHelper } from '../fileuploader-helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to take a picture to upload it. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class CoreFileUploaderCameraHandler implements CoreFileUploaderHandler { | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreFileUploaderCameraHandlerService implements CoreFileUploaderHandler { | ||||
| 
 | ||||
|     name = 'CoreFileUploaderCamera'; | ||||
|     priority = 1800; | ||||
| @ -75,3 +76,5 @@ export class CoreFileUploaderCameraHandler implements CoreFileUploaderHandler { | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreFileUploaderCameraHandler extends makeSingleton(CoreFileUploaderCameraHandlerService) {} | ||||
|  | ||||
| @ -19,13 +19,13 @@ import { CoreDomUtils } from '@services/utils/dom'; | ||||
| import { CoreFileUploaderHandler, CoreFileUploaderHandlerData, CoreFileUploaderHandlerResult } from '../fileuploader-delegate'; | ||||
| import { CoreFileUploaderHelper } from '../fileuploader-helper'; | ||||
| import { CoreFileUploader } from '../fileuploader'; | ||||
| import { Translate } from '@singletons'; | ||||
| import { makeSingleton, Translate } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to upload any type of file. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class CoreFileUploaderFileHandler implements CoreFileUploaderHandler { | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreFileUploaderFileHandlerService implements CoreFileUploaderHandler { | ||||
| 
 | ||||
|     name = 'CoreFileUploaderFile'; | ||||
|     priority = 1200; | ||||
| @ -156,3 +156,5 @@ export class CoreFileUploaderFileHandler implements CoreFileUploaderHandler { | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreFileUploaderFileHandler extends makeSingleton(CoreFileUploaderFileHandlerService) {} | ||||
|  | ||||
| @ -16,13 +16,14 @@ import { Injectable } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreApp } from '@services/app'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { CoreFileUploaderHandler, CoreFileUploaderHandlerData, CoreFileUploaderHandlerResult } from '../fileuploader-delegate'; | ||||
| import { CoreFileUploaderHelper } from '../fileuploader-helper'; | ||||
| /** | ||||
|  * Handler to record a video to upload it. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class CoreFileUploaderVideoHandler implements CoreFileUploaderHandler { | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreFileUploaderVideoHandlerService implements CoreFileUploaderHandler { | ||||
| 
 | ||||
|     name = 'CoreFileUploaderVideo'; | ||||
|     priority = 1400; | ||||
| @ -90,3 +91,5 @@ export class CoreFileUploaderVideoHandler implements CoreFileUploaderHandler { | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreFileUploaderVideoHandler extends makeSingleton(CoreFileUploaderVideoHandlerService) {} | ||||
|  | ||||
							
								
								
									
										290
									
								
								src/core/features/filter/services/filter-delegate.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								src/core/features/filter/services/filter-delegate.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,290 @@ | ||||
| // (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, ViewContainerRef } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreFilterFilter, CoreFilterFormatTextOptions } from './filter'; | ||||
| import { CoreFilterDefaultHandler } from './handlers/default-filter'; | ||||
| import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Interface that all filter handlers must implement. | ||||
|  */ | ||||
| export interface CoreFilterHandler extends CoreDelegateHandler { | ||||
|     /** | ||||
|      * Name of the filter. It should match the "filter" field returned in core_filters_get_available_in_context. | ||||
|      */ | ||||
|     filterName: string; | ||||
| 
 | ||||
|     /** | ||||
|      * Filter some text. | ||||
|      * | ||||
|      * @param text The text to filter. | ||||
|      * @param filter The filter. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Filtered text (or promise resolved with the filtered text). | ||||
|      */ | ||||
|     filter(text: string, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, siteId?: string): string | Promise<string>; | ||||
| 
 | ||||
|     /** | ||||
|      * Handle HTML. This function is called after "filter", and it will receive an HTMLElement containing the text that was | ||||
|      * filtered. | ||||
|      * | ||||
|      * @param container The HTML container to handle. | ||||
|      * @param filter The filter. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param viewContainerRef The ViewContainerRef where the container is. | ||||
|      * @param component Component. | ||||
|      * @param componentId Component ID. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return If async, promise resolved when done. | ||||
|      */ | ||||
|     handleHtml?( | ||||
|         container: HTMLElement, | ||||
|         filter: CoreFilterFilter, | ||||
|         options: CoreFilterFormatTextOptions, | ||||
|         viewContainerRef: ViewContainerRef, | ||||
|         component?: string, | ||||
|         componentId?: string | number, | ||||
|         siteId?: string, | ||||
|     ): void | Promise<void>; | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Delegate to register filters. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreFilterDelegateService extends CoreDelegate<CoreFilterHandler> { | ||||
| 
 | ||||
|     protected featurePrefix = 'CoreFilterDelegate_'; | ||||
|     protected handlerNameProperty = 'filterName'; | ||||
| 
 | ||||
|     constructor(protected defaultHandler: CoreFilterDefaultHandler) { | ||||
|         super('CoreFilterDelegate', true); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Apply a list of filters to some content. | ||||
|      * | ||||
|      * @param text The text to filter. | ||||
|      * @param filters Filters to apply. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param skipFilters Names of filters that shouldn't be applied. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with the filtered text. | ||||
|      */ | ||||
|     async filterText( | ||||
|         text: string, | ||||
|         filters?: CoreFilterFilter[], | ||||
|         options?: CoreFilterFormatTextOptions, | ||||
|         skipFilters?: string[], | ||||
|         siteId?: string, | ||||
|     ): Promise<string> { | ||||
| 
 | ||||
|         // Wait for filters to be initialized.
 | ||||
|         await this.handlersInitPromise; | ||||
| 
 | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
| 
 | ||||
|         filters = filters || []; | ||||
|         options = options || {}; | ||||
| 
 | ||||
|         for (let i = 0; i < filters.length; i++) { | ||||
|             const filter = filters[i]; | ||||
|             if (!this.isEnabledAndShouldApply(filter, options, site, skipFilters)) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             try { | ||||
|                 const newText = await this.executeFunctionOnEnabled<string>( | ||||
|                     filter.filter, | ||||
|                     'filter', | ||||
|                     [text, filter, options, siteId], | ||||
|                 ); | ||||
| 
 | ||||
|                 text = newText || text; | ||||
|             } catch (error) { | ||||
|                 this.logger.error('Error applying filter' + filter.filter, error); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Remove <nolink> tags for XHTML compatibility.
 | ||||
|         text = text.replace(/<\/?nolink>/gi, ''); | ||||
| 
 | ||||
|         return text; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get filters that have an enabled handler. | ||||
|      * | ||||
|      * @param contextLevel Context level of the filters. | ||||
|      * @param instanceId Instance ID. | ||||
|      * @return Filters. | ||||
|      */ | ||||
|     getEnabledFilters(contextLevel: string, instanceId: number): CoreFilterFilter[] { | ||||
|         const filters: CoreFilterFilter[] = []; | ||||
| 
 | ||||
|         for (const name in this.enabledHandlers) { | ||||
|             const handler = <CoreFilterHandler> this.enabledHandlers[name]; | ||||
| 
 | ||||
|             filters.push({ | ||||
|                 contextid: -1, | ||||
|                 contextlevel: contextLevel, | ||||
|                 filter: handler.filterName, | ||||
|                 inheritedstate: 1, | ||||
|                 instanceid: instanceId, | ||||
|                 localstate: 1, | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         return filters; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Let filters handle an HTML element. | ||||
|      * | ||||
|      * @param container The HTML container to handle. | ||||
|      * @param filters Filters to apply. | ||||
|      * @param viewContainerRef The ViewContainerRef where the container is. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param skipFilters Names of filters that shouldn't be applied. | ||||
|      * @param component Component. | ||||
|      * @param componentId Component ID. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     async handleHtml( | ||||
|         container: HTMLElement, | ||||
|         filters: CoreFilterFilter[], | ||||
|         viewContainerRef?: ViewContainerRef, | ||||
|         options?: CoreFilterFormatTextOptions, | ||||
|         skipFilters?: string[], | ||||
|         component?: string, | ||||
|         componentId?: string | number, | ||||
|         siteId?: string, | ||||
|     ): Promise<void> { | ||||
| 
 | ||||
|         // Wait for filters to be initialized.
 | ||||
|         await this.handlersInitPromise; | ||||
| 
 | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
| 
 | ||||
|         filters = filters || []; | ||||
|         options = options || {}; | ||||
| 
 | ||||
|         for (let i = 0; i < filters.length; i++) { | ||||
|             const filter = filters[i]; | ||||
|             if (!this.isEnabledAndShouldApply(filter, options, site, skipFilters)) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             try { | ||||
|                 await this.executeFunctionOnEnabled<void>( | ||||
|                     filter.filter, | ||||
|                     'handleHtml', | ||||
|                     [container, filter, options, viewContainerRef, component, componentId, siteId], | ||||
|                 ); | ||||
|             } catch (error) { | ||||
|                 this.logger.error('Error handling HTML' + filter.filter, error); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if a filter is enabled and should be applied. | ||||
|      * | ||||
|      * @param filters Filters to apply. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param site Site. | ||||
|      * @param skipFilters Names of filters that shouldn't be applied. | ||||
|      * @return Whether the filter is enabled and should be applied. | ||||
|      */ | ||||
|     isEnabledAndShouldApply( | ||||
|         filter: CoreFilterFilter, | ||||
|         options: CoreFilterFormatTextOptions, | ||||
|         site: CoreSite, | ||||
|         skipFilters?: string[], | ||||
|     ): boolean { | ||||
| 
 | ||||
|         if (filter.localstate == -1 || (filter.localstate == 0 && filter.inheritedstate == -1)) { | ||||
|             // Filter is disabled, ignore it.
 | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         if (!this.shouldFilterBeApplied(filter, options, site)) { | ||||
|             // Filter shouldn't be applied.
 | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         if (skipFilters && skipFilters.indexOf(filter.filter) != -1) { | ||||
|             // Skip this filter.
 | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if at least 1 filter should be applied in a certain site and with certain options. | ||||
|      * | ||||
|      * @param filter Filter to check. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param site Site. If not defined, current site. | ||||
|      * @return Promise resolved with true: whether the filter should be applied. | ||||
|      */ | ||||
|     async shouldBeApplied(filters: CoreFilterFilter[], options: CoreFilterFormatTextOptions, site?: CoreSite): Promise<boolean> { | ||||
|         // Wait for filters to be initialized.
 | ||||
|         await this.handlersInitPromise; | ||||
| 
 | ||||
|         for (let i = 0; i < filters.length; i++) { | ||||
|             if (this.shouldFilterBeApplied(filters[i], options, site)) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check whether a filter should be applied in a certain site and with certain options. | ||||
|      * | ||||
|      * @param filter Filter to check. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param site Site. If not defined, current site. | ||||
|      * @return Whether the filter should be applied. | ||||
|      */ | ||||
|     protected shouldFilterBeApplied(filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         if (!this.hasHandler(filter.filter, true)) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         return !!(this.executeFunctionOnEnabled<boolean>(filter.filter, 'shouldBeApplied', [options, site])); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreFilterDelegate extends makeSingleton(CoreFilterDelegateService) {} | ||||
							
								
								
									
										358
									
								
								src/core/features/filter/services/filter-helper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										358
									
								
								src/core/features/filter/services/filter-helper.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,358 @@ | ||||
| // (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 { CoreApp } from '@services/app'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreFilterDelegate } from './filter-delegate'; | ||||
| import { | ||||
|     CoreFilter, | ||||
|     CoreFilterFilter, | ||||
|     CoreFilterFormatTextOptions, | ||||
|     CoreFilterClassifiedFilters, | ||||
|     CoreFiltersGetAvailableInContextWSParamContext, | ||||
| } from './filter'; | ||||
| // import { CoreCourseProvider } from '@features/course/providers/course';
 | ||||
| // import { CoreCoursesProvider } from '@features/courses/providers/courses';
 | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { CoreEvents, CoreEventSiteData } from '@singletons/events'; | ||||
| import { CoreLogger } from '@singletons/logger'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Helper service to provide filter functionalities. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreFilterHelperProvider { | ||||
| 
 | ||||
|     protected logger: CoreLogger; | ||||
| 
 | ||||
|     /** | ||||
|      * When a module context is requested, we request all the modules in a course to decrease WS calls. If there are a lot of | ||||
|      * modules, checking the cache of all contexts can be really slow, so we use this memory cache to speed up the process. | ||||
|      */ | ||||
|     protected moduleContextsCache: { | ||||
|         [siteId: string]: { | ||||
|             [courseId: number]: { | ||||
|                 [contextLevel: string]: { | ||||
|                     contexts: CoreFilterClassifiedFilters; | ||||
|                     time: number; | ||||
|                 }; | ||||
|             }; | ||||
|         }; | ||||
|     } = {}; | ||||
| 
 | ||||
|     constructor() { | ||||
|         this.logger = CoreLogger.getInstance('CoreFilterHelperProvider'); | ||||
| 
 | ||||
|         CoreEvents.on(CoreEvents.WS_CACHE_INVALIDATED, (data: CoreEventSiteData) => { | ||||
|             delete this.moduleContextsCache[data.siteId || '']; | ||||
|         }); | ||||
| 
 | ||||
|         CoreEvents.on(CoreEvents.SITE_STORAGE_DELETED, (data: CoreEventSiteData) => { | ||||
|             delete this.moduleContextsCache[data.siteId || '']; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the contexts of all blocks in a course. | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with the contexts. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     async getBlocksContexts(courseId: number, siteId?: string): Promise<CoreFiltersGetAvailableInContextWSParamContext[]> { | ||||
|         return []; | ||||
|         // @todo
 | ||||
|         // const blocks = await this.courseProvider.getCourseBlocks(courseId, siteId);
 | ||||
| 
 | ||||
|         // const contexts: CoreFiltersGetAvailableInContextWSParamContext[] = [];
 | ||||
| 
 | ||||
|         // blocks.forEach((block) => {
 | ||||
|         //     contexts.push({
 | ||||
|         //         contextlevel: 'block',
 | ||||
|         //         instanceid: block.instanceid,
 | ||||
|         //     });
 | ||||
|         // });
 | ||||
| 
 | ||||
|         // return contexts;
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get some filters from memory cache. If not in cache, get them and store them in cache. | ||||
|      * | ||||
|      * @param contextLevel The context level. | ||||
|      * @param instanceId Instance ID related to the context. | ||||
|      * @param options Options for format text. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with the filters. | ||||
|      */ | ||||
|     protected async getCacheableFilters( | ||||
|         contextLevel: string, | ||||
|         instanceId: number, | ||||
|         getFilters: () => Promise<CoreFiltersGetAvailableInContextWSParamContext[]>, | ||||
|         options: CoreFilterFormatTextOptions, | ||||
|         site: CoreSite, | ||||
|     ): Promise<CoreFilterFilter[]> { | ||||
| 
 | ||||
|         // Check the memory cache first.
 | ||||
|         const result = this.getFromMemoryCache(options.courseId ?? -1, contextLevel, instanceId, site); | ||||
|         if (result) { | ||||
|             return result; | ||||
|         } | ||||
| 
 | ||||
|         const siteId = site.getId(); | ||||
| 
 | ||||
|         const contexts = await getFilters(); | ||||
| 
 | ||||
|         const filters = await CoreFilter.instance.getAvailableInContexts(contexts, siteId); | ||||
| 
 | ||||
|         this.storeInMemoryCache(options.courseId ?? -1, contextLevel, filters, siteId); | ||||
| 
 | ||||
|         return filters[contextLevel][instanceId] || []; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * If user is enrolled in the course, return contexts of all enrolled courses to decrease number of WS requests. | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with the contexts. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     async getCourseContexts(courseId: number, siteId?: string): Promise<CoreFiltersGetAvailableInContextWSParamContext[]> { | ||||
|         // @todo
 | ||||
|         return []; | ||||
|         // const courseIds = await this.coursesProvider.getCourseIdsIfEnrolled(courseId, siteId);
 | ||||
| 
 | ||||
|         // const contexts: CoreFiltersGetAvailableInContextWSParamContext[] = [];
 | ||||
| 
 | ||||
|         // courseIds.forEach((courseId) => {
 | ||||
|         //     contexts.push({
 | ||||
|         //         contextlevel: 'course',
 | ||||
|         //         instanceid: courseId
 | ||||
|         //     });
 | ||||
|         // });
 | ||||
| 
 | ||||
|         // return contexts;
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the contexts of all course modules in a course. | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with the contexts. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     async getCourseModulesContexts(courseId: number, siteId?: string): Promise<CoreFiltersGetAvailableInContextWSParamContext[]> { | ||||
|         // @todo
 | ||||
|         return []; | ||||
| 
 | ||||
|         // const sections = await this.courseProvider.getSections(courseId, false, true, undefined, siteId);
 | ||||
| 
 | ||||
|         // const contexts: CoreFiltersGetAvailableInContextWSParamContext[] = [];
 | ||||
| 
 | ||||
|         // sections.forEach((section) => {
 | ||||
|         //     if (section.modules) {
 | ||||
|         //         section.modules.forEach((module) => {
 | ||||
|         //             if (module.uservisible) {
 | ||||
|         //                 contexts.push({
 | ||||
|         //                     contextlevel: 'module',
 | ||||
|         //                     instanceid: module.id
 | ||||
|         //                 });
 | ||||
|         //             }
 | ||||
|         //         });
 | ||||
|         //     }
 | ||||
|         // });
 | ||||
| 
 | ||||
|         // return contexts;
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the filters in a certain context, performing some checks like the site version. | ||||
|      * It's recommended to use this function instead of canGetFilters + getEnabledFilters because this function will check if | ||||
|      * it's really needed to call the WS. | ||||
|      * | ||||
|      * @param contextLevel The context level. | ||||
|      * @param instanceId Instance ID related to the context. | ||||
|      * @param options Options for format text. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with the filters. | ||||
|      */ | ||||
|     async getFilters( | ||||
|         contextLevel: string, | ||||
|         instanceId: number, | ||||
|         options?: CoreFilterFormatTextOptions, | ||||
|         siteId?: string, | ||||
|     ): Promise<CoreFilterFilter[]> { | ||||
|         options = options || {}; | ||||
|         options.contextLevel = contextLevel; | ||||
|         options.instanceId = instanceId; | ||||
|         options.filter = false; | ||||
| 
 | ||||
|         try { | ||||
|             const site = await CoreSites.instance.getSite(siteId); | ||||
| 
 | ||||
|             siteId = site.getId(); | ||||
| 
 | ||||
|             const canGet = await CoreFilter.instance.canGetFilters(siteId); | ||||
|             if (!canGet) { | ||||
|                 options.filter = true; | ||||
| 
 | ||||
|                 // We cannot check which filters are available, apply them all.
 | ||||
|                 return CoreFilterDelegate.instance.getEnabledFilters(contextLevel, instanceId); | ||||
|             } | ||||
| 
 | ||||
|             let hasFilters = true; | ||||
| 
 | ||||
|             if (contextLevel == 'system' || (contextLevel == 'course' && instanceId == site.getSiteHomeId())) { | ||||
|                 // No need to check the site filters because we're requesting the same context, so we'd do the same twice.
 | ||||
|             } else { | ||||
|                 // Check if site has any filter to treat.
 | ||||
|                 hasFilters = await this.siteHasFiltersToTreat(options, siteId); | ||||
|             } | ||||
| 
 | ||||
|             if (!hasFilters) { | ||||
|                 return []; | ||||
|             } | ||||
| 
 | ||||
|             options.filter = true; | ||||
| 
 | ||||
|             if (contextLevel == 'module' && options.courseId) { | ||||
|                 // Get all the modules filters with a single call to decrease the number of WS calls.
 | ||||
|                 const getFilters = this.getCourseModulesContexts.bind(this, options.courseId, siteId); | ||||
| 
 | ||||
|                 return this.getCacheableFilters(contextLevel, instanceId, getFilters, options, site); | ||||
| 
 | ||||
|             } else if (contextLevel == 'course') { | ||||
|                 // If enrolled, get all enrolled courses filters with a single call to decrease number of WS calls.
 | ||||
|                 const getFilters = this.getCourseContexts.bind(this, instanceId, siteId); | ||||
| 
 | ||||
|                 return this.getCacheableFilters(contextLevel, instanceId, getFilters, options, site); | ||||
|             } else if (contextLevel == 'block' && options.courseId) { // @todo && this.courseProvider.canGetCourseBlocks(site)
 | ||||
|                 // Get all the course blocks filters with a single call to decrease number of WS calls.
 | ||||
|                 const getFilters = this.getBlocksContexts.bind(this, options.courseId, siteId); | ||||
| 
 | ||||
|                 return this.getCacheableFilters(contextLevel, instanceId, getFilters, options, site); | ||||
|             } | ||||
| 
 | ||||
|             return CoreFilter.instance.getAvailableInContext(contextLevel, instanceId, siteId); | ||||
|         } catch (error) { | ||||
|             this.logger.error('Error getting filters, return an empty array', error, contextLevel, instanceId); | ||||
| 
 | ||||
|             return []; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get filters and format text. | ||||
|      * | ||||
|      * @param text Text to filter. | ||||
|      * @param contextLevel The context level. | ||||
|      * @param instanceId Instance ID related to the context. | ||||
|      * @param options Options for format text. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with the formatted text and the filters. | ||||
|      */ | ||||
|     async getFiltersAndFormatText( | ||||
|         text: string, | ||||
|         contextLevel: string, | ||||
|         instanceId: number, | ||||
|         options?: CoreFilterFormatTextOptions, | ||||
|         siteId?: string, | ||||
|     ): Promise<{text: string; filters: CoreFilterFilter[]}> { | ||||
| 
 | ||||
|         const filters = await this.getFilters(contextLevel, instanceId, options, siteId); | ||||
| 
 | ||||
|         text = await CoreFilter.instance.formatText(text, options, filters, siteId); | ||||
| 
 | ||||
|         return { text, filters: filters }; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get module context filters from the memory cache. | ||||
|      * | ||||
|      * @param courseId Course the module belongs to. | ||||
|      * @param contextLevel Context level. | ||||
|      * @param instanceId Instance ID. | ||||
|      * @param site Site. | ||||
|      * @return The filters, undefined if not found. | ||||
|      */ | ||||
|     protected getFromMemoryCache( | ||||
|         courseId: number, | ||||
|         contextLevel: string, | ||||
|         instanceId: number, | ||||
|         site: CoreSite, | ||||
|     ): CoreFilterFilter[] | undefined { | ||||
| 
 | ||||
|         const siteId = site.getId(); | ||||
| 
 | ||||
|         // Check if we have the context in the memory cache.
 | ||||
|         if (!this.moduleContextsCache[siteId]?.[courseId]?.[contextLevel]) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const cachedData = this.moduleContextsCache[siteId][courseId][contextLevel]; | ||||
| 
 | ||||
|         if (!CoreApp.instance.isOnline() || Date.now() <= cachedData.time + site.getExpirationDelay(CoreSite.FREQUENCY_RARELY)) { | ||||
|             // We can use cache, return the filters if found.
 | ||||
|             return cachedData.contexts[contextLevel] && cachedData.contexts[contextLevel][instanceId]; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if site has available any filter that should be treated by the app. | ||||
|      * | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with boolean: whether it has filters to treat. | ||||
|      */ | ||||
|     async siteHasFiltersToTreat(options?: CoreFilterFormatTextOptions, siteId?: string): Promise<boolean> { | ||||
|         options = options || {}; | ||||
| 
 | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
| 
 | ||||
|         // Get filters at site level.
 | ||||
|         const filters = await CoreFilter.instance.getAvailableInContext('system', 0, site.getId()); | ||||
| 
 | ||||
|         return CoreFilterDelegate.instance.shouldBeApplied(filters, options, site); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Store filters in the memory cache. | ||||
|      * | ||||
|      * @param contexts Filters to store, classified by contextlevel and instanceid | ||||
|      * @param siteId Site ID. | ||||
|      */ | ||||
|     protected storeInMemoryCache( | ||||
|         courseId: number, | ||||
|         contextLevel: string, | ||||
|         contexts: CoreFilterClassifiedFilters, | ||||
|         siteId: string, | ||||
|     ): void { | ||||
| 
 | ||||
|         this.moduleContextsCache[siteId] = this.moduleContextsCache[siteId] || {}; | ||||
|         this.moduleContextsCache[siteId][courseId] = this.moduleContextsCache[siteId][courseId] || {}; | ||||
|         this.moduleContextsCache[siteId][courseId][contextLevel] = { | ||||
|             contexts: contexts, | ||||
|             time: Date.now(), | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreFilterHelper extends makeSingleton(CoreFilterHelperProvider) {} | ||||
							
								
								
									
										543
									
								
								src/core/features/filter/services/filter.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										543
									
								
								src/core/features/filter/services/filter.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,543 @@ | ||||
| // (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 { CoreApp } from '@services/app'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| import { CoreWSExternalWarning } from '@services/ws'; | ||||
| import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { CoreFilterDelegate } from './filter-delegate'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { CoreEvents, CoreEventSiteData } from '@singletons/events'; | ||||
| import { CoreLogger } from '@singletons/logger'; | ||||
| 
 | ||||
| /** | ||||
|  * Service to provide filter functionalities. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreFilterProvider { | ||||
| 
 | ||||
|     protected readonly ROOT_CACHE_KEY = 'mmFilter:'; | ||||
| 
 | ||||
|     protected logger: CoreLogger; | ||||
| 
 | ||||
|     /** | ||||
|      * Store the contexts in memory to speed up the process, it can take a lot of time otherwise. | ||||
|      */ | ||||
|     protected contextsCache: { | ||||
|         [siteId: string]: { | ||||
|             [contextlevel: string]: { | ||||
|                 [instanceid: number]: { | ||||
|                     filters: CoreFilterFilter[]; | ||||
|                     time: number; | ||||
|                 }; | ||||
|             }; | ||||
|         }; | ||||
|     } = {}; | ||||
| 
 | ||||
|     constructor() { | ||||
|         this.logger = CoreLogger.getInstance('CoreFilterProvider'); | ||||
| 
 | ||||
|         CoreEvents.on(CoreEvents.WS_CACHE_INVALIDATED, (data: CoreEventSiteData) => { | ||||
|             delete this.contextsCache[data.siteId || '']; | ||||
|         }); | ||||
| 
 | ||||
|         CoreEvents.on(CoreEvents.SITE_STORAGE_DELETED, (data: CoreEventSiteData) => { | ||||
|             delete this.contextsCache[data.siteId || '']; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns whether or not WS get available in context is available. | ||||
|      * | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with true if ws is available, false otherwise. | ||||
|      * @since 3.4 | ||||
|      */ | ||||
|     async canGetAvailableInContext(siteId?: string): Promise<boolean> { | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
| 
 | ||||
|         return this.canGetAvailableInContextInSite(site); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns whether or not WS get available in context is available in a certain site. | ||||
|      * | ||||
|      * @param site Site. If not defined, current site. | ||||
|      * @return Promise resolved with true if ws is available, false otherwise. | ||||
|      * @since 3.4 | ||||
|      */ | ||||
|     canGetAvailableInContextInSite(site?: CoreSite): boolean { | ||||
|         site = site || CoreSites.instance.getCurrentSite(); | ||||
| 
 | ||||
|         return !!(site?.wsAvailable('core_filters_get_available_in_context')); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns whether or not we can get the available filters: the WS is available and the feature isn't disabled. | ||||
|      * | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with boolean: whethe can get filters. | ||||
|      */ | ||||
|     async canGetFilters(siteId?: string): Promise<boolean> { | ||||
|         const wsAvailable = await this.canGetAvailableInContext(siteId); | ||||
|         const disabled = await this.checkFiltersDisabled(siteId); | ||||
| 
 | ||||
|         return wsAvailable && !disabled; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns whether or not we can get the available filters: the WS is available and the feature isn't disabled. | ||||
|      * | ||||
|      * @param site Site. If not defined, current site. | ||||
|      * @return Promise resolved with boolean: whethe can get filters. | ||||
|      */ | ||||
|     canGetFiltersInSite(site?: CoreSite): boolean { | ||||
|         return this.canGetAvailableInContextInSite(site) && this.checkFiltersDisabledInSite(site); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns whether or not checking the available filters is disabled in the site. | ||||
|      * | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with boolean: whether it's disabled. | ||||
|      */ | ||||
|     async checkFiltersDisabled(siteId?: string): Promise<boolean> { | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
| 
 | ||||
|         return this.checkFiltersDisabledInSite(site); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns whether or not checking the available filters is disabled in the site. | ||||
|      * | ||||
|      * @param site Site. If not defined, current site. | ||||
|      * @return Whether it's disabled. | ||||
|      */ | ||||
|     checkFiltersDisabledInSite(site?: CoreSite): boolean { | ||||
|         site = site || CoreSites.instance.getCurrentSite(); | ||||
| 
 | ||||
|         return !!(site?.isFeatureDisabled('CoreFilterDelegate')); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Classify a list of filters into each context. | ||||
|      * | ||||
|      * @param contexts List of contexts. | ||||
|      * @param filters List of filters. | ||||
|      * @param hadSystemContext Whether the list of contexts originally had system context. | ||||
|      * @param hadSiteHomeContext Whether the list of contexts originally had site home context. | ||||
|      * @param site Site instance. | ||||
|      * @return Classified filters. | ||||
|      */ | ||||
|     protected classifyFilters( | ||||
|         contexts: CoreFiltersGetAvailableInContextWSParamContext[], | ||||
|         filters: CoreFilterFilter[], | ||||
|         hadSystemContext: boolean, | ||||
|         hadSiteHomeContext: boolean, | ||||
|         site: CoreSite, | ||||
|     ): CoreFilterClassifiedFilters { | ||||
|         const classified: CoreFilterClassifiedFilters = {}; | ||||
| 
 | ||||
|         // Initialize all contexts.
 | ||||
|         contexts.forEach((context) => { | ||||
|             classified[context.contextlevel] = classified[context.contextlevel] || {}; | ||||
|             classified[context.contextlevel][context.instanceid] = []; | ||||
|         }); | ||||
| 
 | ||||
|         if (contexts.length == 1 && !hadSystemContext) { | ||||
|             // Only 1 context, no need to iterate over the filters.
 | ||||
|             classified[contexts[0].contextlevel][contexts[0].instanceid] = filters; | ||||
| 
 | ||||
|             return classified; | ||||
|         } | ||||
| 
 | ||||
|         filters.forEach((filter) => { | ||||
|             if (hadSystemContext && filter.contextlevel == 'course' && filter.instanceid == site.getSiteHomeId()) { | ||||
|                 if (hadSiteHomeContext) { | ||||
|                     // We need to return both site home and system. Add site home first.
 | ||||
|                     classified[filter.contextlevel][filter.instanceid].push(filter); | ||||
| 
 | ||||
|                     // Now copy the object so it can be modified.
 | ||||
|                     filter = Object.assign({}, filter); | ||||
|                 } | ||||
| 
 | ||||
|                 // Simulate the system context based on the inherited data.
 | ||||
|                 filter.contextlevel = 'system'; | ||||
|                 filter.instanceid = 0; | ||||
|                 filter.contextid = -1; | ||||
|                 filter.localstate = filter.inheritedstate; | ||||
|             } | ||||
| 
 | ||||
|             classified[filter.contextlevel][filter.instanceid].push(filter); | ||||
|         }); | ||||
| 
 | ||||
|         return classified; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Given some HTML code, this function returns the text as safe HTML. | ||||
|      * | ||||
|      * @param text The text to be formatted. | ||||
|      * @param options Formatting options. | ||||
|      * @param filters The filters to apply. Required if filter is set to true. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with the formatted text. | ||||
|      */ | ||||
|     async formatText( | ||||
|         text: string, | ||||
|         options?: CoreFilterFormatTextOptions, | ||||
|         filters?: CoreFilterFilter[], | ||||
|         siteId?: string, | ||||
|     ): Promise<string> { | ||||
| 
 | ||||
|         if (!text || typeof text != 'string') { | ||||
|             // No need to do any filters and cleaning.
 | ||||
|             return ''; | ||||
|         } | ||||
| 
 | ||||
|         // Clone object if needed so we can modify it.
 | ||||
|         options = options ? Object.assign({}, options) : {}; | ||||
| 
 | ||||
|         if (typeof options.clean == 'undefined') { | ||||
|             options.clean = false; | ||||
|         } | ||||
| 
 | ||||
|         if (typeof options.filter == 'undefined') { | ||||
|             options.filter = true; | ||||
|         } | ||||
| 
 | ||||
|         if (!options.contextLevel) { | ||||
|             options.filter = false; | ||||
|         } | ||||
| 
 | ||||
|         if (options.filter) { | ||||
|             text = await CoreFilterDelegate.instance.filterText(text, filters, options, [], siteId); | ||||
|         } | ||||
| 
 | ||||
|         if (options.clean) { | ||||
|             text = CoreTextUtils.instance.cleanTags(text, options.singleLine); | ||||
|         } | ||||
| 
 | ||||
|         if (options.shortenLength && options.shortenLength > 0) { | ||||
|             text = CoreTextUtils.instance.shortenText(text, options.shortenLength); | ||||
|         } | ||||
| 
 | ||||
|         if (options.highlight) { | ||||
|             text = CoreTextUtils.instance.highlightText(text, options.highlight); | ||||
|         } | ||||
| 
 | ||||
|         return text; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get cache key for available in contexts WS calls. | ||||
|      * | ||||
|      * @param contexts The contexts to check. | ||||
|      * @return Cache key. | ||||
|      */ | ||||
|     protected getAvailableInContextsCacheKey(contexts: CoreFiltersGetAvailableInContextWSParamContext[]): string { | ||||
|         return this.getAvailableInContextsPrefixCacheKey() + JSON.stringify(contexts); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get prefixed cache key for available in contexts WS calls. | ||||
|      * | ||||
|      * @return Cache key. | ||||
|      */ | ||||
|     protected getAvailableInContextsPrefixCacheKey(): string { | ||||
|         return this.ROOT_CACHE_KEY + 'availableInContexts:'; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the filters available in several contexts. | ||||
|      * | ||||
|      * @param contexts The contexts to check. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with the filters classified by context. | ||||
|      */ | ||||
|     async getAvailableInContexts( | ||||
|         contexts: CoreFiltersGetAvailableInContextWSParamContext[], | ||||
|         siteId?: string, | ||||
|     ): Promise<CoreFilterClassifiedFilters> { | ||||
| 
 | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
| 
 | ||||
|         siteId = site.getId(); | ||||
| 
 | ||||
|         const cacheResult = this.getFromMemoryCache(contexts, site); | ||||
| 
 | ||||
|         if (cacheResult) { | ||||
|             return cacheResult; | ||||
|         } | ||||
| 
 | ||||
|         const contextsToSend = contexts.slice(); // Copy the contexts array to be able to modify it.
 | ||||
| 
 | ||||
|         const { hadSystemContext, hadSiteHomeContext } = this.replaceSystemContext(contextsToSend, site); | ||||
| 
 | ||||
|         const data: CoreFiltersGetAvailableInContextWSParams = { | ||||
|             contexts: contextsToSend, | ||||
|         }; | ||||
|         const preSets = { | ||||
|             cacheKey: this.getAvailableInContextsCacheKey(contextsToSend), | ||||
|             updateFrequency: CoreSite.FREQUENCY_RARELY, | ||||
|             splitRequest: { | ||||
|                 param: 'contexts', | ||||
|                 maxLength: 300, | ||||
|             }, | ||||
|         }; | ||||
| 
 | ||||
|         const result = await site.read<CoreFilterGetAvailableInContextResult>( | ||||
|             'core_filters_get_available_in_context', | ||||
|             data, | ||||
|             preSets, | ||||
|         ); | ||||
| 
 | ||||
|         const classified = this.classifyFilters(contexts, result.filters, hadSystemContext, hadSiteHomeContext, site); | ||||
| 
 | ||||
|         this.storeInMemoryCache(classified, siteId); | ||||
| 
 | ||||
|         return classified; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the filters available in a certain context. | ||||
|      * | ||||
|      * @param contextLevel The context level to check: system, user, coursecat, course, module, block, ... | ||||
|      * @param instanceId The instance ID. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with the filters. | ||||
|      */ | ||||
|     async getAvailableInContext(contextLevel: string, instanceId: number, siteId?: string): Promise<CoreFilterFilter[]> { | ||||
|         const result = await this.getAvailableInContexts([{ contextlevel: contextLevel, instanceid: instanceId }], siteId); | ||||
| 
 | ||||
|         return result[contextLevel][instanceId] || []; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get contexts filters from the memory cache. | ||||
|      * | ||||
|      * @param contexts Contexts to get. | ||||
|      * @param site Site. | ||||
|      * @return The filters classified by context and instance. | ||||
|      */ | ||||
|     protected getFromMemoryCache( | ||||
|         contexts: CoreFiltersGetAvailableInContextWSParamContext[], | ||||
|         site: CoreSite, | ||||
|     ): CoreFilterClassifiedFilters | undefined { | ||||
| 
 | ||||
|         if (!this.contextsCache[site.getId()]) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // Check if we have the contexts in the memory cache.
 | ||||
|         const siteContexts = this.contextsCache[site.getId()]; | ||||
|         const isOnline = CoreApp.instance.isOnline(); | ||||
|         const result: CoreFilterClassifiedFilters = {}; | ||||
|         let allFound = true; | ||||
| 
 | ||||
|         for (let i = 0; i < contexts.length; i++) { | ||||
|             const context = contexts[i]; | ||||
|             const cachedCtxt = siteContexts[context.contextlevel]?.[context.instanceid]; | ||||
| 
 | ||||
|             // Check the context isn't "expired". The time stored in this cache will not match the one in the site cache.
 | ||||
|             if (cachedCtxt && (!isOnline || | ||||
|                     Date.now() <= cachedCtxt.time + site.getExpirationDelay(CoreSite.FREQUENCY_RARELY))) { | ||||
| 
 | ||||
|                 result[context.contextlevel] = result[context.contextlevel] || {}; | ||||
|                 result[context.contextlevel][context.instanceid] = cachedCtxt.filters; | ||||
|             } else { | ||||
|                 allFound = false; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (allFound) { | ||||
|             return result; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Invalidates all available in context WS calls. | ||||
|      * | ||||
|      * @param siteId Site ID (empty for current site). | ||||
|      * @return Promise resolved when the data is invalidated. | ||||
|      */ | ||||
|     async invalidateAllAvailableInContext(siteId?: string): Promise<void> { | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
| 
 | ||||
|         await site.invalidateWsCacheForKeyStartingWith(this.getAvailableInContextsPrefixCacheKey()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Invalidates available in context WS call. | ||||
|      * | ||||
|      * @param contexts The contexts to check. | ||||
|      * @param siteId Site ID (empty for current site). | ||||
|      * @return Promise resolved when the data is invalidated. | ||||
|      */ | ||||
|     async invalidateAvailableInContexts( | ||||
|         contexts: CoreFiltersGetAvailableInContextWSParamContext[], | ||||
|         siteId?: string, | ||||
|     ): Promise<void> { | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
| 
 | ||||
|         await site.invalidateWsCacheForKey(this.getAvailableInContextsCacheKey(contexts)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Invalidates available in context WS call. | ||||
|      * | ||||
|      * @param contextLevel The context level to check. | ||||
|      * @param instanceId The instance ID. | ||||
|      * @param siteId Site ID (empty for current site). | ||||
|      * @return Promise resolved when the data is invalidated. | ||||
|      */ | ||||
|     async invalidateAvailableInContext(contextLevel: string, instanceId: number, siteId?: string): Promise<void> { | ||||
|         await this.invalidateAvailableInContexts([{ contextlevel: contextLevel, instanceid: instanceId }], siteId); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Given a list of context to send to core_filters_get_available_in_context, search if the system context is in the list | ||||
|      * and, if so, replace it with a workaround. | ||||
|      * | ||||
|      * @param contexts The contexts to check. | ||||
|      * @param site Site instance. | ||||
|      * @return Whether the filters had system context and whether they had the site home context. | ||||
|      */ | ||||
|     protected replaceSystemContext( | ||||
|         contexts: CoreFiltersGetAvailableInContextWSParamContext[], | ||||
|         site: CoreSite, | ||||
|     ): { hadSystemContext: boolean; hadSiteHomeContext: boolean } { | ||||
|         const result = { | ||||
|             hadSystemContext: false, | ||||
|             hadSiteHomeContext: false, | ||||
|         }; | ||||
| 
 | ||||
|         // Check if any of the contexts is "system". We cannot use system context, so we'll have to use a wrokaround.
 | ||||
|         for (let i = 0; i < contexts.length; i++) { | ||||
|             const context = contexts[i]; | ||||
| 
 | ||||
|             if (context.contextlevel != 'system') { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             result.hadSystemContext = true; | ||||
| 
 | ||||
|             // Use course site home instead. Check if it's already in the list.
 | ||||
|             result.hadSiteHomeContext = contexts.some((context) => | ||||
|                 context.contextlevel == 'course' && context.instanceid == site.getSiteHomeId()); | ||||
| 
 | ||||
|             if (result.hadSiteHomeContext) { | ||||
|                 // Site home is already in list, remove this context from the list.
 | ||||
|                 contexts.splice(i, 1); | ||||
|             } else { | ||||
|                 // Site home not in list, use it instead of system.
 | ||||
|                 contexts[i] = { | ||||
|                     contextlevel: 'course', | ||||
|                     instanceid: site.getSiteHomeId(), | ||||
|                 }; | ||||
|             } | ||||
| 
 | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Store filters in the memory cache. | ||||
|      * | ||||
|      * @param filters Filters to store, classified by contextlevel and instanceid | ||||
|      * @param siteId Site ID. | ||||
|      */ | ||||
|     protected storeInMemoryCache(filters: CoreFilterClassifiedFilters, siteId: string): void { | ||||
|         this.contextsCache[siteId] = this.contextsCache[siteId] || {}; | ||||
| 
 | ||||
|         for (const contextLevel in filters) { | ||||
|             this.contextsCache[siteId][contextLevel] = this.contextsCache[siteId][contextLevel] || {}; | ||||
| 
 | ||||
|             for (const instanceId in filters[contextLevel]) { | ||||
|                 this.contextsCache[siteId][contextLevel][instanceId] = { | ||||
|                     filters: filters[contextLevel][instanceId], | ||||
|                     time: Date.now(), | ||||
|                 }; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreFilter extends makeSingleton(CoreFilterProvider) {} | ||||
| 
 | ||||
| /** | ||||
|  * Params of core_filters_get_available_in_context WS. | ||||
|  */ | ||||
| export type CoreFiltersGetAvailableInContextWSParams = { | ||||
|     contexts: CoreFiltersGetAvailableInContextWSParamContext[]; // The list of contexts to check.
 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Data about a context sent to core_filters_get_available_in_context. | ||||
|  */ | ||||
| export type CoreFiltersGetAvailableInContextWSParamContext = { | ||||
|     contextlevel: string; // The context level where the filters are: (coursecat, course, module).
 | ||||
|     instanceid: number; // The instance id of item associated with the context.
 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Filter object returned by core_filters_get_available_in_context. | ||||
|  */ | ||||
| export type CoreFilterFilter = { | ||||
|     contextlevel: string; // The context level where the filters are: (coursecat, course, module).
 | ||||
|     instanceid: number; // The instance id of item associated with the context.
 | ||||
|     contextid: number; // The context id.
 | ||||
|     filter: string; // Filter plugin name.
 | ||||
|     localstate: number; // Filter state: 1 for on, -1 for off, 0 if inherit.
 | ||||
|     inheritedstate: number; // 1 or 0 to use when localstate is set to inherit.
 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Result of core_filters_get_available_in_context. | ||||
|  */ | ||||
| export type CoreFilterGetAvailableInContextResult = { | ||||
|     filters: CoreFilterFilter[]; // Available filters.
 | ||||
|     warnings: CoreWSExternalWarning[]; // List of warnings.
 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Options that can be passed to format text. | ||||
|  */ | ||||
| export type CoreFilterFormatTextOptions = { | ||||
|     contextLevel?: string; // The context level where the text is.
 | ||||
|     instanceId?: number; // The instance id related to the context.
 | ||||
|     clean?: boolean; // If true all HTML will be removed. Default false.
 | ||||
|     filter?: boolean; // If true the string will be run through applicable filters as well. Default true.
 | ||||
|     singleLine?: boolean; // If true then new lines will be removed (all the text in a single line).
 | ||||
|     shortenLength?: number; // Number of characters to shorten the text.
 | ||||
|     highlight?: string; // Text to highlight.
 | ||||
|     wsNotFiltered?: boolean; // If true it means the WS didn't filter the text for some reason.
 | ||||
|     courseId?: number; // Course ID the text belongs to. It can be used to improve performance.
 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Filters classified by context and instance. | ||||
|  */ | ||||
| export type CoreFilterClassifiedFilters = { | ||||
|     [contextlevel: string]: { | ||||
|         [instanceid: number]: CoreFilterFilter[]; | ||||
|     }; | ||||
| }; | ||||
							
								
								
									
										94
									
								
								src/core/features/filter/services/handlers/default-filter.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/core/features/filter/services/handlers/default-filter.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | ||||
| // (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, ViewContainerRef } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreFilterHandler } from '../filter-delegate'; | ||||
| import { CoreFilterFilter, CoreFilterFormatTextOptions } from '../filter'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| 
 | ||||
| /** | ||||
|  * Default handler used when the module doesn't have a specific implementation. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreFilterDefaultHandler implements CoreFilterHandler { | ||||
| 
 | ||||
|     name = 'CoreFilterDefaultHandler'; | ||||
|     filterName = 'default'; | ||||
| 
 | ||||
|     /** | ||||
|      * Filter some text. | ||||
|      * | ||||
|      * @param text The text to filter. | ||||
|      * @param filter The filter. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Filtered text (or promise resolved with the filtered text). | ||||
|      */ | ||||
|     filter( | ||||
|         text: string, | ||||
|         filter: CoreFilterFilter, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         options: CoreFilterFormatTextOptions, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         siteId?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|     ): string | Promise<string> { | ||||
|         return text; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Handle HTML. This function is called after "filter", and it will receive an HTMLElement containing the text that was | ||||
|      * filtered. | ||||
|      * | ||||
|      * @param container The HTML container to handle. | ||||
|      * @param filter The filter. | ||||
|      * @param options Options passed to the filters. | ||||
|      * @param viewContainerRef The ViewContainerRef where the container is. | ||||
|      * @param component Component. | ||||
|      * @param componentId Component ID. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return If async, promise resolved when done. | ||||
|      */ | ||||
|     handleHtml( | ||||
|         container: HTMLElement, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         filter: CoreFilterFilter, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         options: CoreFilterFormatTextOptions, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         viewContainerRef: ViewContainerRef, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         component?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         componentId?: string | number, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|         siteId?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
 | ||||
|     ): void | Promise<void> { | ||||
|         // To be overridden.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Whether or not the handler is enabled on a site level. | ||||
|      * | ||||
|      * @return Whether or not the handler is enabled on a site level. | ||||
|      */ | ||||
|     async isEnabled(): Promise<boolean> { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the filter should be applied in a certain site based on some filter options. | ||||
|      * | ||||
|      * @param options Options. | ||||
|      * @param site Site. | ||||
|      * @return Whether filter should be applied. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -25,7 +25,7 @@ import { resolveModuleRoutes } from '@/app/app-routing.module'; | ||||
| 
 | ||||
| import { MAIN_MENU_ROUTES } from './mainmenu-routing.module'; | ||||
| import { CoreMainMenuPage } from './pages/menu/menu'; | ||||
| import { CoreMainMenuHomeHandler } from './services/handlers/mainmenu'; | ||||
| import { CoreMainMenuHomeHandlerService } from './services/handlers/mainmenu'; | ||||
| 
 | ||||
| function buildRoutes(injector: Injector): Routes { | ||||
|     const routes = resolveModuleRoutes(injector, MAIN_MENU_ROUTES); | ||||
| @ -38,10 +38,10 @@ function buildRoutes(injector: Injector): Routes { | ||||
|                 { | ||||
|                     path: '', | ||||
|                     pathMatch: 'full', | ||||
|                     redirectTo: CoreMainMenuHomeHandler.PAGE_NAME, | ||||
|                     redirectTo: CoreMainMenuHomeHandlerService.PAGE_NAME, | ||||
|                 }, | ||||
|                 { | ||||
|                     path: CoreMainMenuHomeHandler.PAGE_NAME, | ||||
|                     path: CoreMainMenuHomeHandlerService.PAGE_NAME, | ||||
|                     loadChildren: () => import('./pages/home/home.module').then(m => m.CoreMainMenuHomePageModule), | ||||
|                 }, | ||||
|                 { | ||||
| @ -68,7 +68,6 @@ function buildRoutes(injector: Injector): Routes { | ||||
|         CoreMainMenuPage, | ||||
|     ], | ||||
|     providers: [ | ||||
|         CoreMainMenuHomeHandler, | ||||
|         { provide: ROUTES, multi: true, useFactory: buildRoutes, deps: [Injector] }, | ||||
|     ], | ||||
| }) | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { APP_INITIALIZER, NgModule } from '@angular/core'; | ||||
| import { Routes } from '@angular/router'; | ||||
| import { AuthGuard } from '@guards/auth'; | ||||
| 
 | ||||
| @ -37,14 +37,15 @@ const appRoutes: Routes = [ | ||||
| 
 | ||||
| @NgModule({ | ||||
|     imports: [AppRoutingModule.forChild(appRoutes)], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => { | ||||
|                 CoreMainMenuDelegate.instance.registerHandler(CoreMainMenuHomeHandler.instance); | ||||
|             }, | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class CoreMainMenuModule { | ||||
| 
 | ||||
|     constructor( | ||||
|         mainMenuDelegate: CoreMainMenuDelegate, | ||||
|         homeMainMenuHandler: CoreMainMenuHomeHandler, | ||||
|     ) { | ||||
|         mainMenuDelegate.registerHandler(homeMainMenuHandler); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| export class CoreMainMenuModule {} | ||||
|  | ||||
| @ -40,15 +40,13 @@ export class CoreMainMenuHomePage implements OnInit { | ||||
|     protected subscription?: Subscription; | ||||
|     protected updateSiteObserver?: CoreEventObserver; | ||||
| 
 | ||||
|     constructor(protected homeDelegate: CoreMainMenuHomeDelegate) {} | ||||
| 
 | ||||
|     /** | ||||
|      * Initialize the component. | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|         this.loadSiteName(); | ||||
| 
 | ||||
|         this.subscription = this.homeDelegate.getHandlersObservable().subscribe((handlers) => { | ||||
|         this.subscription = CoreMainMenuHomeDelegate.instance.getHandlersObservable().subscribe((handlers) => { | ||||
|             handlers && this.initHandlers(handlers); | ||||
|         }); | ||||
| 
 | ||||
| @ -90,7 +88,7 @@ export class CoreMainMenuHomePage implements OnInit { | ||||
| 
 | ||||
|         this.tabs = newTabs; | ||||
| 
 | ||||
|         this.loaded = this.homeDelegate.areHandlersLoaded(); | ||||
|         this.loaded = CoreMainMenuHomeDelegate.instance.areHandlersLoaded(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -57,7 +57,6 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { | ||||
|     constructor( | ||||
|         protected route: ActivatedRoute, | ||||
|         protected navCtrl: NavController, | ||||
|         protected menuDelegate: CoreMainMenuDelegate, | ||||
|         protected changeDetector: ChangeDetectorRef, | ||||
|         protected router: Router, | ||||
|     ) { | ||||
| @ -98,7 +97,7 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         this.subscription = this.menuDelegate.getHandlersObservable().subscribe((handlers) => { | ||||
|         this.subscription = CoreMainMenuDelegate.instance.getHandlersObservable().subscribe((handlers) => { | ||||
|             // Remove the handlers that should only appear in the More menu.
 | ||||
|             this.allHandlers = handlers.filter((handler) => !handler.onlyInMore); | ||||
| 
 | ||||
| @ -164,7 +163,7 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { | ||||
|             // Sort them by priority so new handlers are in the right position.
 | ||||
|             this.tabs.sort((a, b) => (b.priority || 0) - (a.priority || 0)); | ||||
| 
 | ||||
|             this.loaded = this.menuDelegate.areHandlersLoaded(); | ||||
|             this.loaded = CoreMainMenuDelegate.instance.areHandlersLoaded(); | ||||
| 
 | ||||
|             if (this.loaded && this.mainTabs && !this.mainTabs.getSelected()) { | ||||
|                 // Select the first tab.
 | ||||
|  | ||||
| @ -49,9 +49,7 @@ export class CoreMainMenuMorePage implements OnInit, OnDestroy { | ||||
|     protected langObserver: CoreEventObserver; | ||||
|     protected updateSiteObserver: CoreEventObserver; | ||||
| 
 | ||||
|     constructor( | ||||
|         protected menuDelegate: CoreMainMenuDelegate, | ||||
|     ) { | ||||
|     constructor() { | ||||
| 
 | ||||
|         this.langObserver = CoreEvents.on(CoreEvents.LANGUAGE_CHANGED, this.loadSiteInfo.bind(this)); | ||||
|         this.updateSiteObserver = CoreEvents.on( | ||||
| @ -69,7 +67,7 @@ export class CoreMainMenuMorePage implements OnInit, OnDestroy { | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|         // Load the handlers.
 | ||||
|         this.subscription = this.menuDelegate.getHandlersObservable().subscribe((handlers) => { | ||||
|         this.subscription = CoreMainMenuDelegate.instance.getHandlersObservable().subscribe((handlers) => { | ||||
|             this.allHandlers = handlers; | ||||
| 
 | ||||
|             this.initHandlers(); | ||||
| @ -104,7 +102,7 @@ export class CoreMainMenuMorePage implements OnInit, OnDestroy { | ||||
|         // Get only the handlers that don't appear in the main view.
 | ||||
|         this.handlers = this.allHandlers.filter((handler) => mainHandlers.indexOf(handler) == -1); | ||||
| 
 | ||||
|         this.handlersLoaded = this.menuDelegate.areHandlersLoaded(); | ||||
|         this.handlersLoaded = CoreMainMenuDelegate.instance.areHandlersLoaded(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -13,13 +13,14 @@ | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '../mainmenu-delegate'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to add Home into main menu. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreMainMenuHomeHandler implements CoreMainMenuHandler { | ||||
| export class CoreMainMenuHomeHandlerService implements CoreMainMenuHandler { | ||||
| 
 | ||||
|     static readonly PAGE_NAME = 'home'; | ||||
| 
 | ||||
| @ -56,10 +57,12 @@ export class CoreMainMenuHomeHandler implements CoreMainMenuHandler { | ||||
|         return { | ||||
|             icon: 'fa-home', | ||||
|             title: 'core.mainmenu.home', | ||||
|             page: CoreMainMenuHomeHandler.PAGE_NAME, | ||||
|             page: CoreMainMenuHomeHandlerService.PAGE_NAME, | ||||
|             // @todo: subPage? The page can change due to core-tabs.
 | ||||
|             class: 'core-home-handler', | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreMainMenuHomeHandler extends makeSingleton(CoreMainMenuHomeHandlerService) {} | ||||
|  | ||||
| @ -17,6 +17,7 @@ import { Params } from '@angular/router'; | ||||
| 
 | ||||
| import { CoreDelegateDisplayHandler, CoreDelegateToDisplay } from '@classes/delegate'; | ||||
| import { CoreSortedDelegate } from '@classes/delegate-sorted'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Interface that all home handlers must implement. | ||||
| @ -85,7 +86,7 @@ export interface CoreMainMenuHomeHandlerToDisplay extends CoreDelegateToDisplay, | ||||
| @Injectable({ | ||||
|     providedIn: 'root', | ||||
| }) | ||||
| export class CoreMainMenuHomeDelegate extends CoreSortedDelegate<CoreMainMenuHomeHandlerToDisplay, CoreMainMenuHomeHandler> { | ||||
| export class CoreMainMenuHomeDelegateService extends CoreSortedDelegate<CoreMainMenuHomeHandlerToDisplay, CoreMainMenuHomeHandler> { | ||||
| 
 | ||||
|     protected featurePrefix = 'CoreMainMenuHomeDelegate_'; | ||||
| 
 | ||||
| @ -94,3 +95,5 @@ export class CoreMainMenuHomeDelegate extends CoreSortedDelegate<CoreMainMenuHom | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreMainMenuHomeDelegate extends makeSingleton(CoreMainMenuHomeDelegateService) {} | ||||
|  | ||||
| @ -17,6 +17,7 @@ import { Params } from '@angular/router'; | ||||
| 
 | ||||
| import { CoreDelegateDisplayHandler, CoreDelegateToDisplay } from '@classes/delegate'; | ||||
| import { CoreSortedDelegate } from '@classes/delegate-sorted'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Interface that all main menu handlers must implement. | ||||
| @ -97,7 +98,7 @@ export interface CoreMainMenuHandlerToDisplay extends CoreDelegateToDisplay, Cor | ||||
| @Injectable({ | ||||
|     providedIn: 'root', | ||||
| }) | ||||
| export class CoreMainMenuDelegate extends CoreSortedDelegate<CoreMainMenuHandlerToDisplay, CoreMainMenuHandler> { | ||||
| export class CoreMainMenuDelegateService extends CoreSortedDelegate<CoreMainMenuHandlerToDisplay, CoreMainMenuHandler> { | ||||
| 
 | ||||
|     protected featurePrefix = 'CoreMainMenuDelegate_'; | ||||
| 
 | ||||
| @ -106,3 +107,5 @@ export class CoreMainMenuDelegate extends CoreSortedDelegate<CoreMainMenuHandler | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreMainMenuDelegate extends makeSingleton(CoreMainMenuDelegateService) {} | ||||
|  | ||||
| @ -35,7 +35,7 @@ export class CoreMainMenuProvider { | ||||
| 
 | ||||
|     protected tablet = false; | ||||
| 
 | ||||
|     constructor(protected menuDelegate: CoreMainMenuDelegate) { | ||||
|     constructor() { | ||||
|         this.tablet = !!(window?.innerWidth && window.innerWidth >= 576 && window.innerHeight >= 576); | ||||
|     } | ||||
| 
 | ||||
| @ -47,7 +47,7 @@ export class CoreMainMenuProvider { | ||||
|     getCurrentMainMenuHandlers(): Promise<CoreMainMenuHandlerToDisplay[]> { | ||||
|         const deferred = CoreUtils.instance.promiseDefer<CoreMainMenuHandlerToDisplay[]>(); | ||||
| 
 | ||||
|         const subscription = this.menuDelegate.getHandlersObservable().subscribe((handlers) => { | ||||
|         const subscription = CoreMainMenuDelegate.instance.getHandlersObservable().subscribe((handlers) => { | ||||
|             subscription?.unsubscribe(); | ||||
| 
 | ||||
|             // Remove the handlers that should only appear in the More menu.
 | ||||
|  | ||||
| @ -57,7 +57,6 @@ export class CoreSitePreferencesPage implements OnInit, OnDestroy { | ||||
|     protected isDestroyed = false; | ||||
| 
 | ||||
|     constructor( | ||||
|         protected settingsDelegate: CoreSettingsDelegate, | ||||
|         protected route: ActivatedRoute, | ||||
|         protected router: Router, // Will be removed when splitview is implemented
 | ||||
|     ) { | ||||
| @ -97,7 +96,7 @@ export class CoreSitePreferencesPage implements OnInit, OnDestroy { | ||||
|      * Fetch Data. | ||||
|      */ | ||||
|     protected async fetchData(): Promise<void> { | ||||
|         this.handlers = this.settingsDelegate.getHandlers(); | ||||
|         this.handlers = CoreSettingsDelegate.instance.getHandlers(); | ||||
| 
 | ||||
|         const currentSite = CoreSites.instance.getCurrentSite(); | ||||
|         this.siteInfo = currentSite!.getInfo(); | ||||
|  | ||||
| @ -17,6 +17,7 @@ import { Params } from '@angular/router'; | ||||
| 
 | ||||
| import { CoreDelegateDisplayHandler, CoreDelegateToDisplay } from '@classes/delegate'; | ||||
| import { CoreSortedDelegate } from '@classes/delegate-sorted'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Interface that all settings handlers must implement. | ||||
| @ -65,10 +66,12 @@ export type CoreSettingsHandlerToDisplay = CoreDelegateToDisplay & CoreSettingsH | ||||
| @Injectable({ | ||||
|     providedIn: 'root', | ||||
| }) | ||||
| export class CoreSettingsDelegate extends CoreSortedDelegate<CoreSettingsHandlerToDisplay, CoreSettingsHandler> { | ||||
| export class CoreSettingsDelegateService extends CoreSortedDelegate<CoreSettingsHandlerToDisplay, CoreSettingsHandler> { | ||||
| 
 | ||||
|     constructor() { | ||||
|         super('CoreSettingsDelegate'); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreSettingsDelegate extends makeSingleton(CoreSettingsDelegateService) {} | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreApp } from '@services/app'; | ||||
| import { CoreCron } from '@services/cron'; | ||||
| import { CoreCronDelegate } from '@services/cron'; | ||||
| import { CoreEvents } from '@singletons/events'; | ||||
| import { CoreFilepool } from '@services/filepool'; | ||||
| import { CoreSite } from '@classes/site'; | ||||
| @ -277,7 +277,7 @@ export class CoreSettingsHelperProvider { | ||||
|         } | ||||
| 
 | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
|         const hasSyncHandlers = CoreCron.instance.hasManualSyncHandlers(); | ||||
|         const hasSyncHandlers = CoreCronDelegate.instance.hasManualSyncHandlers(); | ||||
| 
 | ||||
|         if (site.isLoggedOut()) { | ||||
|             // Cannot sync logged out sites.
 | ||||
| @ -296,7 +296,7 @@ export class CoreSettingsHelperProvider { | ||||
|             site.invalidateWsCache(), | ||||
|             this.checkSiteLocalMobile(site), | ||||
|             CoreSites.instance.updateSiteInfo(site.getId()), | ||||
|             CoreCron.instance.forceSyncExecution(site.getId()), | ||||
|             CoreCronDelegate.instance.forceSyncExecution(site.getId()), | ||||
|         // eslint-disable-next-line arrow-body-style
 | ||||
|         ]).then(() => { | ||||
|             return; | ||||
|  | ||||
| @ -19,12 +19,13 @@ import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base | ||||
| import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper'; | ||||
| import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate'; | ||||
| import { CoreSiteHome } from '../sitehome'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to treat links to site home index. | ||||
|  */ | ||||
| Injectable(); | ||||
| export class CoreSiteHomeIndexLinkHandler extends CoreContentLinksHandlerBase { | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreSiteHomeIndexLinkHandlerService extends CoreContentLinksHandlerBase { | ||||
| 
 | ||||
|     name = 'CoreSiteHomeIndexLinkHandler'; | ||||
|     featureName = 'CoreMainMenuDelegate_CoreSiteHome'; | ||||
| @ -73,3 +74,5 @@ export class CoreSiteHomeIndexLinkHandler extends CoreContentLinksHandlerBase { | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreSiteHomeIndexLinkHandler extends makeSingleton(CoreSiteHomeIndexLinkHandlerService) {} | ||||
|  | ||||
| @ -16,12 +16,13 @@ import { Injectable } from '@angular/core'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreMainMenuHomeHandler, CoreMainMenuHomeHandlerToDisplay } from '@features/mainmenu/services/home-delegate'; | ||||
| import { CoreSiteHome } from '../sitehome'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to add site home into home page. | ||||
|  */ | ||||
| Injectable(); | ||||
| export class CoreSiteHomeHomeHandler implements CoreMainMenuHomeHandler { | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreSiteHomeHomeHandlerService implements CoreMainMenuHomeHandler { | ||||
| 
 | ||||
|     static readonly PAGE_NAME = 'site'; | ||||
| 
 | ||||
| @ -58,7 +59,7 @@ export class CoreSiteHomeHomeHandler implements CoreMainMenuHomeHandler { | ||||
| 
 | ||||
|         return { | ||||
|             title: 'core.sitehome.sitehome', | ||||
|             page: CoreSiteHomeHomeHandler.PAGE_NAME, | ||||
|             page: CoreSiteHomeHomeHandlerService.PAGE_NAME, | ||||
|             class: 'core-sitehome-dashboard-handler', | ||||
|             icon: 'fas-home', | ||||
|             selectPriority: displaySiteHome ? 1100 : 900, | ||||
| @ -66,3 +67,5 @@ export class CoreSiteHomeHomeHandler implements CoreMainMenuHomeHandler { | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreSiteHomeHomeHandler extends makeSingleton(CoreSiteHomeHomeHandlerService) {} | ||||
|  | ||||
| @ -12,18 +12,18 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { APP_INITIALIZER, NgModule } from '@angular/core'; | ||||
| import { Routes } from '@angular/router'; | ||||
| 
 | ||||
| import { CoreSiteHomeIndexLinkHandler } from './services/handlers/index-link'; | ||||
| import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate'; | ||||
| import { CoreSiteHomeHomeHandler } from './services/handlers/sitehome-home'; | ||||
| import { CoreSiteHomeHomeHandler, CoreSiteHomeHomeHandlerService } from './services/handlers/sitehome-home'; | ||||
| import { CoreMainMenuHomeDelegate } from '@features/mainmenu/services/home-delegate'; | ||||
| import { CoreMainMenuHomeRoutingModule } from '@features/mainmenu/pages/home/home-routing.module'; | ||||
| 
 | ||||
| const mainMenuHomeRoutes: Routes = [ | ||||
|     { | ||||
|         path: CoreSiteHomeHomeHandler.PAGE_NAME, | ||||
|         path: CoreSiteHomeHomeHandlerService.PAGE_NAME, | ||||
|         loadChildren: () => import('./pages/index/index.module').then(m => m.CoreSiteHomeIndexPageModule), | ||||
|     }, | ||||
| ]; | ||||
| @ -32,20 +32,15 @@ const mainMenuHomeRoutes: Routes = [ | ||||
|     imports: [CoreMainMenuHomeRoutingModule.forChild({ children: mainMenuHomeRoutes })], | ||||
|     exports: [CoreMainMenuHomeRoutingModule], | ||||
|     providers: [ | ||||
|         CoreSiteHomeIndexLinkHandler, | ||||
|         CoreSiteHomeHomeHandler, | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => { | ||||
|                 CoreContentLinksDelegate.instance.registerHandler(CoreSiteHomeIndexLinkHandler.instance); | ||||
|                 CoreMainMenuHomeDelegate.instance.registerHandler(CoreSiteHomeHomeHandler.instance); | ||||
|             }, | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class CoreSiteHomeModule { | ||||
| 
 | ||||
|     constructor( | ||||
|         contentLinksDelegate: CoreContentLinksDelegate, | ||||
|         homeDelegate: CoreMainMenuHomeDelegate, | ||||
|         siteHomeIndexLinkHandler: CoreSiteHomeIndexLinkHandler, | ||||
|         siteHomeDashboardHandler: CoreSiteHomeHomeHandler, | ||||
|     ) { | ||||
|         contentLinksDelegate.registerHandler(siteHomeIndexLinkHandler); | ||||
|         homeDelegate.registerHandler(siteHomeDashboardHandler); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| export class CoreSiteHomeModule {} | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
| 
 | ||||
| import { CoreApp } from '@services/app'; | ||||
| import { CoreConfig } from '@services/config'; | ||||
| import { CoreCron } from '@services/cron'; | ||||
| import { CoreCronDelegate } from '@services/cron'; | ||||
| import { CoreFilepool } from '@services/filepool'; | ||||
| import { CoreLocalNotifications } from '@services/local-notifications'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| @ -23,7 +23,7 @@ export default async function(): Promise<void> { | ||||
|     await Promise.all([ | ||||
|         CoreApp.instance.initialiseDatabase(), | ||||
|         CoreConfig.instance.initialiseDatabase(), | ||||
|         CoreCron.instance.initialiseDatabase(), | ||||
|         CoreCronDelegate.instance.initialiseDatabase(), | ||||
|         CoreFilepool.instance.initialiseDatabase(), | ||||
|         CoreLocalNotifications.instance.initialiseDatabase(), | ||||
|         CoreSites.instance.initialiseDatabase(), | ||||
|  | ||||
| @ -14,19 +14,19 @@ | ||||
| 
 | ||||
| import { ApplicationRef } from '@angular/core'; | ||||
| import { CoreApp, CoreAppProvider } from '@services/app'; | ||||
| import { CoreCron, CoreCronDelegate } from '@services/cron'; | ||||
| import { CoreCronDelegate, CoreCronDelegateService } from '@services/cron'; | ||||
| import { Application } from '@singletons'; | ||||
| 
 | ||||
| type AutomatedTestsWindow = Window & { | ||||
|     appRef?: ApplicationRef; | ||||
|     appProvider?: CoreAppProvider; | ||||
|     cronProvider?: CoreCronDelegate; | ||||
|     cronProvider?: CoreCronDelegateService; | ||||
| }; | ||||
| 
 | ||||
| function initializeAutomatedTestsWindow(window: AutomatedTestsWindow) { | ||||
|     window.appRef = Application.instance; | ||||
|     window.appProvider = CoreApp.instance; | ||||
|     window.cronProvider = CoreCron.instance; | ||||
|     window.cronProvider = CoreCronDelegate.instance; | ||||
| } | ||||
| 
 | ||||
| export default function(): void { | ||||
|  | ||||
| @ -29,7 +29,7 @@ import { APP_SCHEMA, CRON_TABLE_NAME, CronDBEntry } from '@services/database/cro | ||||
|  * Service to handle cron processes. The registered processes will be executed every certain time. | ||||
| */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CoreCronDelegate { | ||||
| export class CoreCronDelegateService { | ||||
| 
 | ||||
|     // Constants.
 | ||||
|     static readonly DEFAULT_INTERVAL = 3600000; // Default interval is 1 hour.
 | ||||
| @ -108,7 +108,7 @@ export class CoreCronDelegate { | ||||
|                 // Cannot execute in this network connection, retry soon.
 | ||||
|                 const message = `Cannot execute handler because device is using limited connection: ${name}`; | ||||
|                 this.logger.debug(message); | ||||
|                 this.scheduleNextExecution(name, CoreCronDelegate.MIN_INTERVAL); | ||||
|                 this.scheduleNextExecution(name, CoreCronDelegateService.MIN_INTERVAL); | ||||
| 
 | ||||
|                 throw new CoreError(message); | ||||
|             } | ||||
| @ -130,7 +130,7 @@ export class CoreCronDelegate { | ||||
|                 // Handler call failed. Retry soon.
 | ||||
|                 const message = `Execution of handler '${name}' failed.`; | ||||
|                 this.logger.error(message, error); | ||||
|                 this.scheduleNextExecution(name, CoreCronDelegate.MIN_INTERVAL); | ||||
|                 this.scheduleNextExecution(name, CoreCronDelegateService.MIN_INTERVAL); | ||||
| 
 | ||||
|                 throw new CoreError(message); | ||||
|             } | ||||
| @ -160,7 +160,7 @@ export class CoreCronDelegate { | ||||
|                 // The handler took too long. Resolve because we don't want to retry soon.
 | ||||
|                 this.logger.debug(`Resolving execution of handler '${name}' because it took too long.`); | ||||
|                 resolve(); | ||||
|             }, CoreCronDelegate.MAX_TIME_PROCESS); | ||||
|             }, CoreCronDelegateService.MAX_TIME_PROCESS); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -215,15 +215,15 @@ export class CoreCronDelegate { | ||||
|     protected getHandlerInterval(name: string): number { | ||||
|         if (!this.handlers[name] || !this.handlers[name].getInterval) { | ||||
|             // Invalid, return default.
 | ||||
|             return CoreCronDelegate.DEFAULT_INTERVAL; | ||||
|             return CoreCronDelegateService.DEFAULT_INTERVAL; | ||||
|         } | ||||
| 
 | ||||
|         // Don't allow intervals lower than the minimum.
 | ||||
|         const minInterval = CoreCronDelegate.MIN_INTERVAL; | ||||
|         const minInterval = CoreCronDelegateService.MIN_INTERVAL; | ||||
|         const handlerInterval = this.handlers[name].getInterval!(); | ||||
| 
 | ||||
|         if (!handlerInterval) { | ||||
|             return CoreCronDelegate.DEFAULT_INTERVAL; | ||||
|             return CoreCronDelegateService.DEFAULT_INTERVAL; | ||||
|         } else { | ||||
|             return Math.max(minInterval, handlerInterval); | ||||
|         } | ||||
| @ -476,7 +476,7 @@ export class CoreCronDelegate { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CoreCron extends makeSingleton(CoreCronDelegate) {} | ||||
| export class CoreCronDelegate extends makeSingleton(CoreCronDelegateService) {} | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
| @ -499,7 +499,7 @@ export interface CoreCronHandler { | ||||
|     timeout?: number; | ||||
| 
 | ||||
|     /** | ||||
|      * Returns handler's interval in milliseconds. Defaults to CoreCronDelegate.DEFAULT_INTERVAL. | ||||
|      * Returns handler's interval in milliseconds. Defaults to CoreCronDelegateService.DEFAULT_INTERVAL. | ||||
|      * | ||||
|      * @return Interval time (in milliseconds). | ||||
|      */ | ||||
|  | ||||
| @ -18,7 +18,7 @@ import { Md5 } from 'ts-md5/dist/md5'; | ||||
| import { CoreApp } from '@services/app'; | ||||
| import { CoreEvents } from '@singletons/events'; | ||||
| import { CoreFile } from '@services/file'; | ||||
| import { CorePluginFile } from '@services/plugin-file-delegate'; | ||||
| import { CorePluginFileDelegate } from '@services/plugin-file-delegate'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreWS, CoreWSExternalFile } from '@services/ws'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| @ -697,7 +697,7 @@ export class CoreFilepoolProvider { | ||||
| 
 | ||||
|             const entry = await CoreWS.instance.downloadFile(fileUrl, path, addExtension, onProgress); | ||||
|             const fileEntry = entry; | ||||
|             await CorePluginFile.instance.treatDownloadedFile(fileUrl, fileEntry, siteId, onProgress); | ||||
|             await CorePluginFileDelegate.instance.treatDownloadedFile(fileUrl, fileEntry, siteId, onProgress); | ||||
| 
 | ||||
|             await this.addFileToPool(siteId, fileId, { | ||||
|                 downloadTime: Date.now(), | ||||
| @ -1062,7 +1062,7 @@ export class CoreFilepoolProvider { | ||||
|         } | ||||
| 
 | ||||
|         // Now get other files from plugin file handlers.
 | ||||
|         urls = urls.concat(CorePluginFile.instance.getDownloadableFilesFromHTML(element)); | ||||
|         urls = urls.concat(CorePluginFileDelegate.instance.getDownloadableFilesFromHTML(element)); | ||||
| 
 | ||||
|         return urls; | ||||
|     } | ||||
| @ -1159,7 +1159,7 @@ export class CoreFilepoolProvider { | ||||
|      * @return Promise resolved with the file data to use. | ||||
|      */ | ||||
|     protected async fixPluginfileURL(siteId: string, fileUrl: string, timemodified: number = 0): Promise<CoreWSExternalFile> { | ||||
|         const file = await CorePluginFile.instance.getDownloadableFile({ fileurl: fileUrl, timemodified }); | ||||
|         const file = await CorePluginFileDelegate.instance.getDownloadableFile({ fileurl: fileUrl, timemodified }); | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
| 
 | ||||
|         file.fileurl = await site.checkAndFixPluginfileURL(file.fileurl); | ||||
| @ -1918,7 +1918,7 @@ export class CoreFilepoolProvider { | ||||
|             return 0; | ||||
|         } | ||||
| 
 | ||||
|         const revisionRegex = CorePluginFile.instance.getComponentRevisionRegExp(args); | ||||
|         const revisionRegex = CorePluginFileDelegate.instance.getComponentRevisionRegExp(args); | ||||
|         if (!revisionRegex) { | ||||
|             return 0; | ||||
|         } | ||||
| @ -2662,7 +2662,7 @@ export class CoreFilepoolProvider { | ||||
|         this.notifyFileDeleted(siteId, fileId, links); | ||||
| 
 | ||||
|         if (fileUrl) { | ||||
|             await CoreUtils.instance.ignoreErrors(CorePluginFile.instance.fileDeleted(fileUrl, path, siteId)); | ||||
|             await CoreUtils.instance.ignoreErrors(CorePluginFileDelegate.instance.fileDeleted(fileUrl, path, siteId)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -2710,7 +2710,7 @@ export class CoreFilepoolProvider { | ||||
|             return url; | ||||
|         } | ||||
| 
 | ||||
|         return CorePluginFile.instance.removeRevisionFromUrl(url, args); | ||||
|         return CorePluginFileDelegate.instance.removeRevisionFromUrl(url, args); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -42,7 +42,7 @@ export class CoreSiteInfoCronHandler implements CoreCronHandler { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns handler's interval in milliseconds. Defaults to CoreCronDelegate.DEFAULT_INTERVAL. | ||||
|      * Returns handler's interval in milliseconds. Defaults to CoreCronDelegateService.DEFAULT_INTERVAL. | ||||
|      * | ||||
|      * @return Interval time (in milliseconds). | ||||
|      */ | ||||
|  | ||||
| @ -25,7 +25,7 @@ import { makeSingleton } from '@singletons'; | ||||
|  * Delegate to register pluginfile information handlers. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class CorePluginFileDelegate extends CoreDelegate<CorePluginFileHandler> { | ||||
| export class CorePluginFileDelegateService extends CoreDelegate<CorePluginFileHandler> { | ||||
| 
 | ||||
|     protected handlerNameProperty = 'component'; | ||||
| 
 | ||||
| @ -288,7 +288,7 @@ export class CorePluginFileDelegate extends CoreDelegate<CorePluginFileHandler> | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class CorePluginFile extends makeSingleton(CorePluginFileDelegate) {} | ||||
| export class CorePluginFileDelegate extends makeSingleton(CorePluginFileDelegateService) {} | ||||
| 
 | ||||
| /** | ||||
|  * Interface that all plugin file handlers must implement. | ||||
|  | ||||
| @ -255,7 +255,7 @@ export class CoreUrlUtilsProvider { | ||||
|      * @param  url URL | ||||
|      * @return Youtube Embed Video URL or null if not found. | ||||
|      */ | ||||
|     getYoutubeEmbedUrl(url: string): string | void { | ||||
|     getYoutubeEmbedUrl(url?: string): string | void { | ||||
|         if (!url) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user