forked from CIT/Vmeda.Online
		
	
						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