forked from EVOgeek/Vmeda.Online
		
	
						commit
						7abc385935
					
				
							
								
								
									
										122
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										122
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -3768,8 +3768,12 @@ | ||||
|       "resolved": "https://registry.npmjs.org/cordova-plugin-whitelist/-/cordova-plugin-whitelist-1.3.4.tgz", | ||||
|       "integrity": "sha512-EYC5eQFVkoYXq39l7tYKE6lEjHJ04mvTmKXxGL7quHLdFPfJMNzru/UYpn92AOfpl3PQaZmou78C7EgmFOwFQQ==" | ||||
|     }, | ||||
|     "cordova-plugin-wkuserscript": { | ||||
|       "version": "git+https://github.com/moodlemobile/cordova-plugin-wkuserscript.git#6413f4bb3c2565f353e690b5c1450b69ad9e860e", | ||||
|       "from": "git+https://github.com/moodlemobile/cordova-plugin-wkuserscript.git" | ||||
|     }, | ||||
|     "cordova-plugin-wkwebview-cookies": { | ||||
|       "version": "git+https://github.com/moodlemobile/cordova-plugin-wkwebview-cookies.git#8e319b9cc5887611bd8972152e4377757986d570", | ||||
|       "version": "git+https://github.com/moodlemobile/cordova-plugin-wkwebview-cookies.git#8c3a289e29b33edecff15f470c1630baf4ec3e88", | ||||
|       "from": "git+https://github.com/moodlemobile/cordova-plugin-wkwebview-cookies.git" | ||||
|     }, | ||||
|     "cordova-plugin-zip": { | ||||
| @ -6232,8 +6236,7 @@ | ||||
|         "ansi-regex": { | ||||
|           "version": "2.1.1", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", | ||||
|           "optional": true | ||||
|           "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" | ||||
|         }, | ||||
|         "aproba": { | ||||
|           "version": "1.2.0", | ||||
| @ -6254,14 +6257,12 @@ | ||||
|         "balanced-match": { | ||||
|           "version": "1.0.0", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", | ||||
|           "optional": true | ||||
|           "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" | ||||
|         }, | ||||
|         "brace-expansion": { | ||||
|           "version": "1.1.11", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "balanced-match": "^1.0.0", | ||||
|             "concat-map": "0.0.1" | ||||
| @ -6276,20 +6277,17 @@ | ||||
|         "code-point-at": { | ||||
|           "version": "1.1.0", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", | ||||
|           "optional": true | ||||
|           "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" | ||||
|         }, | ||||
|         "concat-map": { | ||||
|           "version": "0.0.1", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", | ||||
|           "optional": true | ||||
|           "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" | ||||
|         }, | ||||
|         "console-control-strings": { | ||||
|           "version": "1.1.0", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", | ||||
|           "optional": true | ||||
|           "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" | ||||
|         }, | ||||
|         "core-util-is": { | ||||
|           "version": "1.0.2", | ||||
| @ -6414,8 +6412,7 @@ | ||||
|         "inherits": { | ||||
|           "version": "2.0.3", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", | ||||
|           "optional": true | ||||
|           "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" | ||||
|         }, | ||||
|         "ini": { | ||||
|           "version": "1.3.5", | ||||
| @ -6427,7 +6424,6 @@ | ||||
|           "version": "1.0.0", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "number-is-nan": "^1.0.0" | ||||
|           } | ||||
| @ -6442,7 +6438,6 @@ | ||||
|           "version": "3.0.4", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "brace-expansion": "^1.1.7" | ||||
|           } | ||||
| @ -6486,7 +6481,6 @@ | ||||
|           "version": "0.5.1", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "minimist": "0.0.8" | ||||
|           }, | ||||
| @ -6494,8 +6488,7 @@ | ||||
|             "minimist": { | ||||
|               "version": "0.0.8", | ||||
|               "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", | ||||
|               "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", | ||||
|               "optional": true | ||||
|               "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
| @ -6594,8 +6587,7 @@ | ||||
|         "number-is-nan": { | ||||
|           "version": "1.0.1", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", | ||||
|           "optional": true | ||||
|           "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" | ||||
|         }, | ||||
|         "object-assign": { | ||||
|           "version": "4.1.1", | ||||
| @ -6607,7 +6599,6 @@ | ||||
|           "version": "1.4.0", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "wrappy": "1" | ||||
|           } | ||||
| @ -6729,7 +6720,6 @@ | ||||
|           "version": "1.0.2", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "code-point-at": "^1.0.0", | ||||
|             "is-fullwidth-code-point": "^1.0.0", | ||||
| @ -6749,7 +6739,6 @@ | ||||
|           "version": "3.0.1", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "ansi-regex": "^2.0.0" | ||||
|           } | ||||
| @ -6805,8 +6794,7 @@ | ||||
|         "wrappy": { | ||||
|           "version": "1.0.2", | ||||
|           "resolved": false, | ||||
|           "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", | ||||
|           "optional": true | ||||
|           "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" | ||||
|         }, | ||||
|         "yallist": { | ||||
|           "version": "3.0.3", | ||||
| @ -7290,8 +7278,7 @@ | ||||
|               "version": "2.1.1", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "aproba": { | ||||
|               "version": "1.2.0", | ||||
| @ -7315,15 +7302,13 @@ | ||||
|               "version": "1.0.0", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "brace-expansion": { | ||||
|               "version": "1.1.11", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "balanced-match": "^1.0.0", | ||||
|                 "concat-map": "0.0.1" | ||||
| @ -7340,22 +7325,19 @@ | ||||
|               "version": "1.1.0", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "concat-map": { | ||||
|               "version": "0.0.1", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "console-control-strings": { | ||||
|               "version": "1.1.0", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "core-util-is": { | ||||
|               "version": "1.0.2", | ||||
| @ -7486,8 +7468,7 @@ | ||||
|               "version": "2.0.3", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "ini": { | ||||
|               "version": "1.3.5", | ||||
| @ -7501,7 +7482,6 @@ | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "number-is-nan": "^1.0.0" | ||||
|               } | ||||
| @ -7518,7 +7498,6 @@ | ||||
|               "resolved": false, | ||||
|               "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "brace-expansion": "^1.1.7" | ||||
|               } | ||||
| @ -7527,15 +7506,13 @@ | ||||
|               "version": "0.0.8", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "minipass": { | ||||
|               "version": "2.3.5", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "safe-buffer": "^5.1.2", | ||||
|                 "yallist": "^3.0.0" | ||||
| @ -7556,7 +7533,6 @@ | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "minimist": "0.0.8" | ||||
|               } | ||||
| @ -7645,8 +7621,7 @@ | ||||
|               "version": "1.0.1", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "object-assign": { | ||||
|               "version": "4.1.1", | ||||
| @ -7660,7 +7635,6 @@ | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "wrappy": "1" | ||||
|               } | ||||
| @ -7756,8 +7730,7 @@ | ||||
|               "version": "5.1.2", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "safer-buffer": { | ||||
|               "version": "2.1.2", | ||||
| @ -7799,7 +7772,6 @@ | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "code-point-at": "^1.0.0", | ||||
|                 "is-fullwidth-code-point": "^1.0.0", | ||||
| @ -7821,7 +7793,6 @@ | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "ansi-regex": "^2.0.0" | ||||
|               } | ||||
| @ -7870,15 +7841,13 @@ | ||||
|               "version": "1.0.2", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "yallist": { | ||||
|               "version": "3.0.3", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
| @ -14940,8 +14909,7 @@ | ||||
|               "version": "2.1.1", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "aproba": { | ||||
|               "version": "1.2.0", | ||||
| @ -14965,15 +14933,13 @@ | ||||
|               "version": "1.0.0", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "brace-expansion": { | ||||
|               "version": "1.1.11", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "balanced-match": "^1.0.0", | ||||
|                 "concat-map": "0.0.1" | ||||
| @ -14990,22 +14956,19 @@ | ||||
|               "version": "1.1.0", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "concat-map": { | ||||
|               "version": "0.0.1", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "console-control-strings": { | ||||
|               "version": "1.1.0", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "core-util-is": { | ||||
|               "version": "1.0.2", | ||||
| @ -15136,8 +15099,7 @@ | ||||
|               "version": "2.0.3", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "ini": { | ||||
|               "version": "1.3.5", | ||||
| @ -15151,7 +15113,6 @@ | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "number-is-nan": "^1.0.0" | ||||
|               } | ||||
| @ -15168,7 +15129,6 @@ | ||||
|               "resolved": false, | ||||
|               "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "brace-expansion": "^1.1.7" | ||||
|               } | ||||
| @ -15177,15 +15137,13 @@ | ||||
|               "version": "0.0.8", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "minipass": { | ||||
|               "version": "2.3.5", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "safe-buffer": "^5.1.2", | ||||
|                 "yallist": "^3.0.0" | ||||
| @ -15206,7 +15164,6 @@ | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "minimist": "0.0.8" | ||||
|               } | ||||
| @ -15295,8 +15252,7 @@ | ||||
|               "version": "1.0.1", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "object-assign": { | ||||
|               "version": "4.1.1", | ||||
| @ -15310,7 +15266,6 @@ | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "wrappy": "1" | ||||
|               } | ||||
| @ -15406,8 +15361,7 @@ | ||||
|               "version": "5.1.2", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "safer-buffer": { | ||||
|               "version": "2.1.2", | ||||
| @ -15449,7 +15403,6 @@ | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "code-point-at": "^1.0.0", | ||||
|                 "is-fullwidth-code-point": "^1.0.0", | ||||
| @ -15471,7 +15424,6 @@ | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", | ||||
|               "dev": true, | ||||
|               "optional": true, | ||||
|               "requires": { | ||||
|                 "ansi-regex": "^2.0.0" | ||||
|               } | ||||
| @ -15520,15 +15472,13 @@ | ||||
|               "version": "1.0.2", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             }, | ||||
|             "yallist": { | ||||
|               "version": "3.0.3", | ||||
|               "resolved": false, | ||||
|               "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", | ||||
|               "dev": true, | ||||
|               "optional": true | ||||
|               "dev": true | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|  | ||||
| @ -112,6 +112,7 @@ | ||||
|     "cordova-plugin-splashscreen": "5.0.3", | ||||
|     "cordova-plugin-statusbar": "2.4.3", | ||||
|     "cordova-plugin-whitelist": "1.3.4", | ||||
|     "cordova-plugin-wkuserscript": "git+https://github.com/moodlemobile/cordova-plugin-wkuserscript.git", | ||||
|     "cordova-plugin-wkwebview-cookies": "git+https://github.com/moodlemobile/cordova-plugin-wkwebview-cookies.git", | ||||
|     "cordova-plugin-zip": "3.1.0", | ||||
|     "cordova-sqlite-storage": "4.0.0", | ||||
| @ -211,7 +212,8 @@ | ||||
|       }, | ||||
|       "cordova-plugin-wkwebview-cookies": {}, | ||||
|       "cordova-plugin-qrscanner": {}, | ||||
|       "cordova-plugin-chooser": {} | ||||
|       "cordova-plugin-chooser": {}, | ||||
|       "cordova-plugin-wkuserscript": {} | ||||
|     } | ||||
|   }, | ||||
|   "main": "desktop/electron.js", | ||||
|  | ||||
| @ -407,7 +407,7 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv | ||||
|      * @return Whether it's an XAPI post statement of the current activity. | ||||
|      */ | ||||
|     protected isCurrentXAPIPost(data: any): boolean { | ||||
|         if (data.context != 'moodleapp' || data.action != 'xapi_post_statement' || !data.statements) { | ||||
|         if (data.environment != 'moodleapp' || data.context != 'h5p' || data.action != 'xapi_post_statement' || !data.statements) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										42
									
								
								src/assets/js/iframe-recaptcha.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/assets/js/iframe-recaptcha.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| // (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.
 | ||||
| 
 | ||||
| (function () { | ||||
|     var url = location.href; | ||||
| 
 | ||||
|     if (!url.match(/^https?:\/\//i) || !url.match(/\/webservice\/recaptcha\.php/i)) { | ||||
|         // Not the recaptcha script, stop.
 | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // Define recaptcha callbacks.
 | ||||
|     window.recaptchacallback = function(value) { | ||||
|         window.parent.postMessage({ | ||||
|             environment: 'moodleapp', | ||||
|             context: 'recaptcha', | ||||
|             action: 'callback', | ||||
|             frameUrl: location.href, | ||||
|             value: value, | ||||
|         }, '*'); | ||||
|     }; | ||||
| 
 | ||||
|     window.recaptchaexpiredcallback = function() { | ||||
|         window.parent.postMessage({ | ||||
|             environment: 'moodleapp', | ||||
|             context: 'recaptcha', | ||||
|             action: 'expired', | ||||
|             frameUrl: location.href, | ||||
|         }, '*'); | ||||
|     }; | ||||
| })(); | ||||
							
								
								
									
										210
									
								
								src/assets/js/iframe-treat-links.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								src/assets/js/iframe-treat-links.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,210 @@ | ||||
| // (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.
 | ||||
| 
 | ||||
| (function () { | ||||
|     var url = location.href; | ||||
| 
 | ||||
|     if (url.match(/^moodleappfs:\/\/localhost/i) || !url.match(/^[a-z0-9]+:\/\//i)) { | ||||
|         // Same domain as the app, stop.
 | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // Redefine window.open.
 | ||||
|     window.open = function(url, name, specs) { | ||||
|         if (name == '_self') { | ||||
|             // Link should be loaded in the same frame.
 | ||||
|             location.href = toAbsolute(url); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         getRootWindow(window).postMessage({ | ||||
|             environment: 'moodleapp', | ||||
|             context: 'iframe', | ||||
|             action: 'window_open', | ||||
|             frameUrl: location.href, | ||||
|             url: url, | ||||
|             name: name, | ||||
|             specs: specs, | ||||
|         }, '*'); | ||||
|     }; | ||||
| 
 | ||||
|     // Handle link clicks.
 | ||||
|     document.addEventListener('click', (event) => { | ||||
|         if (event.defaultPrevented) { | ||||
|             // Event already prevented by some other code.
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // Find the link being clicked.
 | ||||
|         var el = event.target; | ||||
|         while (el && el.tagName !== 'A') { | ||||
|             el = el.parentElement; | ||||
|         } | ||||
| 
 | ||||
|         if (!el || el.treated) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // Add click listener to the link, this way if the iframe has added a listener to the link it will be executed first.
 | ||||
|         el.treated = true; | ||||
|         el.addEventListener('click', function(event) { | ||||
|             linkClicked(el, event); | ||||
|         }); | ||||
|     }, { | ||||
|         capture: true // Use capture to fix this listener not called if the element clicked is too deep in the DOM.
 | ||||
|     }); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Concatenate two paths, adding a slash between them if needed. | ||||
|      * | ||||
|      * @param leftPath Left path. | ||||
|      * @param rightPath Right path. | ||||
|      * @return Concatenated path. | ||||
|      */ | ||||
|     function concatenatePaths(leftPath, rightPath) { | ||||
|         if (!leftPath) { | ||||
|             return rightPath; | ||||
|         } else if (!rightPath) { | ||||
|             return leftPath; | ||||
|         } | ||||
| 
 | ||||
|         var lastCharLeft = leftPath.slice(-1); | ||||
|         var firstCharRight = rightPath.charAt(0); | ||||
| 
 | ||||
|         if (lastCharLeft === '/' && firstCharRight === '/') { | ||||
|             return leftPath + rightPath.substr(1); | ||||
|         } else if (lastCharLeft !== '/' && firstCharRight !== '/') { | ||||
|             return leftPath + '/' + rightPath; | ||||
|         } else { | ||||
|             return leftPath + rightPath; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the root window. | ||||
|      * | ||||
|      * @param win Current window to check. | ||||
|      * @return Root window. | ||||
|      */ | ||||
|     function getRootWindow(win) { | ||||
|         if (win.parent === win) { | ||||
|             return win; | ||||
|         } | ||||
| 
 | ||||
|         return getRootWindow(win.parent); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the scheme from a URL. | ||||
|      * | ||||
|      * @param url URL to treat. | ||||
|      * @return Scheme, undefined if no scheme found. | ||||
|      */ | ||||
|     function getUrlScheme(url) { | ||||
|         if (!url) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         var matches = url.match(/^([a-z][a-z0-9+\-.]*):/); | ||||
|         if (matches && matches[1]) { | ||||
|             return matches[1]; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if a URL is absolute. | ||||
|      * | ||||
|      * @param url URL to treat. | ||||
|      * @return Whether it's absolute. | ||||
|      */ | ||||
|     function isAbsoluteUrl(url) { | ||||
|         return /^[^:]{2,}:\/\//i.test(url); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check whether a URL scheme belongs to a local file. | ||||
|      * | ||||
|      * @param scheme Scheme to check. | ||||
|      * @return Whether the scheme belongs to a local file. | ||||
|      */ | ||||
|     function isLocalFileUrlScheme(scheme) { | ||||
|         if (scheme) { | ||||
|             scheme = scheme.toLowerCase(); | ||||
|         } | ||||
| 
 | ||||
|         return scheme == 'cdvfile' || | ||||
|                 scheme == 'file' || | ||||
|                 scheme == 'filesystem' || | ||||
|                 scheme == 'moodleappfs'; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Handle a click on an anchor element. | ||||
|      * | ||||
|      * @param link Anchor element clicked. | ||||
|      * @param event Click event. | ||||
|      */ | ||||
|     function linkClicked(link, event) { | ||||
|         if (event.defaultPrevented) { | ||||
|             // Event already prevented by some other code.
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         var linkScheme = getUrlScheme(link.href); | ||||
|         var pageScheme = getUrlScheme(location.href); | ||||
|         var isTargetSelf = !link.target || link.target == '_self'; | ||||
| 
 | ||||
|         if (!link.href || linkScheme == 'javascript') { | ||||
|             // Links with no URL and Javascript links are ignored.
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         event.preventDefault(); | ||||
| 
 | ||||
|         if (isTargetSelf && (isLocalFileUrlScheme(linkScheme) || !isLocalFileUrlScheme(pageScheme))) { | ||||
|             // Link should be loaded in the same frame. Don't do it if link is online and frame is local.
 | ||||
|             location.href = toAbsolute(link.href); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         getRootWindow(window).postMessage({ | ||||
|             environment: 'moodleapp', | ||||
|             context: 'iframe', | ||||
|             action: 'link_clicked', | ||||
|             frameUrl: location.href, | ||||
|             link: {href: link.href, target: link.target}, | ||||
|         }, '*'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Convert a URL to an absolute URL if needed using the frame src. | ||||
|      * | ||||
|      * @param url URL to convert. | ||||
|      * @return Absolute URL. | ||||
|      */ | ||||
|     function toAbsolute(url) { | ||||
|         if (isAbsoluteUrl(url)) { | ||||
|             return url; | ||||
|         } | ||||
| 
 | ||||
|         // It's a relative URL, use the frame src to create the full URL.
 | ||||
|         var pathToDir = location.href.substring(0, location.href.lastIndexOf('/')); | ||||
| 
 | ||||
|         return concatenatePaths(pathToDir, url); | ||||
|     } | ||||
| })(); | ||||
| @ -1,5 +1,7 @@ | ||||
| <div [class.core-loading-container]="loading" [ngStyle]="{'width': iframeWidth, 'height': iframeHeight}"> | ||||
|     <iframe #iframe [hidden]="loading" class="core-iframe" [ngStyle]="{'width': iframeWidth, 'height': iframeHeight}" [src]="safeUrl" [attr.allowfullscreen]="allowFullscreen ? 'allowfullscreen' : null"></iframe> | ||||
| <div [class.core-loading-container]="loading || !safeUrl" [ngStyle]="{'width': iframeWidth, 'height': iframeHeight}"> | ||||
|     <!-- Don't add the iframe until the safeUrl is set, adding an iframe with null as src causes the iframe to load the whole app. --> | ||||
|     <iframe #iframe *ngIf="safeUrl" [hidden]="loading" class="core-iframe" [ngStyle]="{'width': iframeWidth, 'height': iframeHeight}" [src]="safeUrl" [attr.allowfullscreen]="allowFullscreen ? 'allowfullscreen' : null"></iframe> | ||||
| 
 | ||||
|     <span class="core-loading-spinner"> | ||||
|         <ion-spinner *ngIf="loading"></ion-spinner> | ||||
|     </span> | ||||
|  | ||||
| @ -13,7 +13,7 @@ | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { | ||||
|     Component, Input, Output, OnInit, ViewChild, ElementRef, EventEmitter, OnChanges, SimpleChange, Optional | ||||
|     Component, Input, Output, ViewChild, ElementRef, EventEmitter, OnChanges, SimpleChange, Optional | ||||
| } from '@angular/core'; | ||||
| import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; | ||||
| import { NavController, Platform } from 'ionic-angular'; | ||||
| @ -25,12 +25,13 @@ import { CoreIframeUtilsProvider } from '@providers/utils/iframe'; | ||||
| import { CoreUtilsProvider } from '@providers/utils/utils'; | ||||
| import { CoreSplitViewComponent } from '@components/split-view/split-view'; | ||||
| import { CoreUrl } from '@singletons/url'; | ||||
| import { WKWebViewCookiesWindow } from 'cordova-plugin-wkwebview-cookies'; | ||||
| 
 | ||||
| @Component({ | ||||
|     selector: 'core-iframe', | ||||
|     templateUrl: 'core-iframe.html' | ||||
| }) | ||||
| export class CoreIframeComponent implements OnInit, OnChanges { | ||||
| export class CoreIframeComponent implements OnChanges { | ||||
| 
 | ||||
|     @ViewChild('iframe') iframe: ElementRef; | ||||
|     @Input() src: string; | ||||
| @ -43,6 +44,7 @@ export class CoreIframeComponent implements OnInit, OnChanges { | ||||
| 
 | ||||
|     protected logger; | ||||
|     protected IFRAME_TIMEOUT = 15000; | ||||
|     protected initialized = false; | ||||
| 
 | ||||
|     constructor(logger: CoreLoggerProvider, | ||||
|             protected iframeUtils: CoreIframeUtilsProvider, | ||||
| @ -59,9 +61,15 @@ export class CoreIframeComponent implements OnInit, OnChanges { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      * Init the data. | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|     protected init(): void { | ||||
|         if (this.initialized) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.initialized = true; | ||||
| 
 | ||||
|         const iframe: HTMLIFrameElement = this.iframe && this.iframe.nativeElement; | ||||
| 
 | ||||
|         this.iframeWidth = this.domUtils.formatPixelsSize(this.iframeWidth) || '100%'; | ||||
| @ -101,7 +109,7 @@ export class CoreIframeComponent implements OnInit, OnChanges { | ||||
|             if (this.platform.is('ios') && !this.urlUtils.isLocalFileUrl(url)) { | ||||
|                 // Save a "fake" cookie for the iframe's domain to fix a bug in WKWebView.
 | ||||
|                 try { | ||||
|                     const win = <any> window; | ||||
|                     const win = <WKWebViewCookiesWindow> window; | ||||
|                     const urlParts = CoreUrl.parse(url); | ||||
| 
 | ||||
|                     await win.WKWebViewCookies.setCookie({ | ||||
| @ -116,6 +124,11 @@ export class CoreIframeComponent implements OnInit, OnChanges { | ||||
|             } | ||||
| 
 | ||||
|             this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(CoreFile.instance.convertFileSrc(url)); | ||||
| 
 | ||||
|             // Now that the URL has been set, initialize the iframe. Wait for the iframe to the added to the DOM.
 | ||||
|             setTimeout(() => { | ||||
|                 this.init(); | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component } from '@angular/core'; | ||||
| import { Component, OnDestroy } from '@angular/core'; | ||||
| import { ViewController, NavParams } from 'ionic-angular'; | ||||
| 
 | ||||
| /** | ||||
| @ -22,13 +22,19 @@ import { ViewController, NavParams } from 'ionic-angular'; | ||||
|     selector: 'core-recaptcha-modal', | ||||
|     templateUrl: 'core-recaptchamodal.html' | ||||
| }) | ||||
| export class CoreRecaptchaModalComponent { | ||||
| export class CoreRecaptchaModalComponent implements OnDestroy { | ||||
|     expired = false; | ||||
|     value = ''; | ||||
|     src: string; | ||||
| 
 | ||||
|     protected messageListenerFunction: (event: MessageEvent) => Promise<void>; | ||||
| 
 | ||||
|     constructor(protected viewCtrl: ViewController, params: NavParams) { | ||||
|         this.src = params.get('src'); | ||||
| 
 | ||||
|         // Listen for messages from the iframe.
 | ||||
|         this.messageListenerFunction = this.onIframeMessage.bind(this); | ||||
|         window.addEventListener('message', this.messageListenerFunction); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -51,18 +57,63 @@ export class CoreRecaptchaModalComponent { | ||||
|         const contentWindow = iframe && iframe.contentWindow; | ||||
| 
 | ||||
|         if (contentWindow) { | ||||
|             try { | ||||
|                 // Set the callbacks we're interested in.
 | ||||
|             contentWindow['recaptchacallback'] = (value): void => { | ||||
|                 contentWindow['recaptchacallback'] = this.onRecaptchaCallback.bind(this); | ||||
|                 contentWindow['recaptchaexpiredcallback'] = this.onRecaptchaExpiredCallback.bind(this); | ||||
|             } catch (error) { | ||||
|                 // Cannot access the window.
 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Treat an iframe message event. | ||||
|      * | ||||
|      * @param event Event. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected async onIframeMessage(event: MessageEvent): Promise<void> { | ||||
|         if (!event.data || event.data.environment != 'moodleapp' || event.data.context != 'recaptcha') { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         switch (event.data.action) { | ||||
|             case 'callback': | ||||
|                 this.onRecaptchaCallback(event.data.value); | ||||
|                 break; | ||||
|             case 'expired': | ||||
|                 this.onRecaptchaExpiredCallback(); | ||||
|                 break; | ||||
| 
 | ||||
|             default: | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Recapcha callback called. | ||||
|      * | ||||
|      * @param value Value received. | ||||
|      */ | ||||
|     protected onRecaptchaCallback(value: any): void { | ||||
|         this.expired = false; | ||||
|         this.value = value; | ||||
|         this.closeModal(); | ||||
|             }; | ||||
|     } | ||||
| 
 | ||||
|             contentWindow['recaptchaexpiredcallback'] = (): void => { | ||||
|                 // Verification expired. Check the checkbox again.
 | ||||
|     /** | ||||
|      * Recapcha expired callback called. | ||||
|      */ | ||||
|     protected onRecaptchaExpiredCallback(): void { | ||||
|         this.expired = true; | ||||
|         this.value = ''; | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component destroyed. | ||||
|      */ | ||||
|     ngOnDestroy(): void { | ||||
|         window.removeEventListener('message', this.messageListenerFunction); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -80,7 +80,8 @@ H5PEmbedCommunicator = (function() { | ||||
|          */ | ||||
|         self.post = function(component, statements) { | ||||
|             window.parent.postMessage({ | ||||
|                 context: 'moodleapp', | ||||
|                 environment: 'moodleapp', | ||||
|                 context: 'h5p', | ||||
|                 action: 'xapi_post_statement', | ||||
|                 component: component, | ||||
|                 statements: statements, | ||||
|  | ||||
| @ -1229,7 +1229,7 @@ export class CoreFileProvider { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the full path to the www folder at runtime. | ||||
|      * Get the path to the www folder at runtime based on the WebView URL. | ||||
|      * | ||||
|      * @return Path. | ||||
|      */ | ||||
| @ -1243,6 +1243,20 @@ export class CoreFileProvider { | ||||
|         return window.location.href; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the full path to the www folder. | ||||
|      * | ||||
|      * @return Path. | ||||
|      */ | ||||
|     getWWWAbsolutePath(): string { | ||||
|         if (cordova && cordova.file && cordova.file.applicationDirectory) { | ||||
|             return this.textUtils.concatenatePaths(cordova.file.applicationDirectory, 'www'); | ||||
|         } | ||||
| 
 | ||||
|         // Cannot use Cordova to get it, use the WebView URL.
 | ||||
|         return this.getWWWPath(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Helper function to call Ionic WebView convertFileSrc only in the needed platforms. | ||||
|      * This is needed to make files work with the Ionic WebView plugin. | ||||
|  | ||||
| @ -27,6 +27,7 @@ import { CoreUtilsProvider } from './utils'; | ||||
| import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; | ||||
| import { makeSingleton } from '@singletons/core.singletons'; | ||||
| import { CoreUrl } from '@singletons/url'; | ||||
| import { WKUserScriptWindow, WKUserScriptInjectionTime } from 'cordova-plugin-wkuserscript'; | ||||
| 
 | ||||
| /* | ||||
|  * "Utils" service with helper functions for iframes, embed and similar. | ||||
| @ -43,6 +44,27 @@ export class CoreIframeUtilsProvider { | ||||
|             private translate: TranslateService, private network: Network, private zone: NgZone, private config: Config, | ||||
|             private contentLinksHelper: CoreContentLinksHelperProvider) { | ||||
|         this.logger = logger.getInstance('CoreUtilsProvider'); | ||||
| 
 | ||||
|         const win = <WKUserScriptWindow> window; | ||||
| 
 | ||||
|         if (platform.is('ios') && win.WKUserScript) { | ||||
|             platform.ready().then(() => { | ||||
|                 // Inject code to the iframes because we cannot access the online ones.
 | ||||
|                 const wwwPath = fileProvider.getWWWAbsolutePath(); | ||||
|                 const linksPath = textUtils.concatenatePaths(wwwPath, 'assets/js/iframe-treat-links.js'); | ||||
|                 const recaptchaPath = textUtils.concatenatePaths(wwwPath, 'assets/js/iframe-recaptcha.js'); | ||||
| 
 | ||||
|                 win.WKUserScript.addScript({id: 'CoreIframeUtilsLinksScript', file: linksPath}); | ||||
|                 win.WKUserScript.addScript({ | ||||
|                     id: 'CoreIframeUtilsRecaptchaScript', | ||||
|                     file: recaptchaPath, | ||||
|                     injectionTime: WKUserScriptInjectionTime.END, | ||||
|                 }); | ||||
| 
 | ||||
|                 // Handle post messages received by iframes.
 | ||||
|                 window.addEventListener('message', this.handleIframeMessage.bind(this)); | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -186,6 +208,30 @@ export class CoreIframeUtilsProvider { | ||||
|         return { window: contentWindow, document: contentDocument }; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Handle some iframe messages. | ||||
|      * | ||||
|      * @param event Message event. | ||||
|      */ | ||||
|     handleIframeMessage(event: MessageEvent): void { | ||||
|         if (!event.data || event.data.environment != 'moodleapp' || event.data.context != 'iframe') { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         switch (event.data.action) { | ||||
|             case 'window_open': | ||||
|                 this.windowOpen(event.data.url, event.data.name); | ||||
|                 break; | ||||
| 
 | ||||
|             case 'link_clicked': | ||||
|                 this.linkClicked(event.data.link); | ||||
|                 break; | ||||
| 
 | ||||
|             default: | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Redefine the open method in the contentWindow of an element and the sub frames. | ||||
|      * Please notice that the element should be an iframe, embed or similar. | ||||
| @ -198,56 +244,10 @@ export class CoreIframeUtilsProvider { | ||||
|     redefineWindowOpen(element: any, contentWindow: Window, contentDocument: Document, navCtrl?: NavController): void { | ||||
|         if (contentWindow) { | ||||
|             // Intercept window.open.
 | ||||
|             contentWindow.open = (url: string, target: string): Window => { | ||||
|                 const scheme = this.urlUtils.getUrlScheme(url); | ||||
|                 if (!scheme) { | ||||
|                     // It's a relative URL, use the frame src to create the full URL.
 | ||||
|                     const src = element.src || element.data; | ||||
|                     if (src) { | ||||
|                         const dirAndFile = this.fileProvider.getFileAndDirectoryFromPath(src); | ||||
|                         if (dirAndFile.directory) { | ||||
|                             url = this.textUtils.concatenatePaths(dirAndFile.directory, url); | ||||
|                         } else { | ||||
|                             this.logger.warn('Cannot get iframe dir path to open relative url', url, element); | ||||
|             contentWindow.open = (url: string, name: string): Window => { | ||||
|                 this.windowOpen(url, name, element, navCtrl); | ||||
| 
 | ||||
|                 return null; | ||||
|                         } | ||||
|                     } else { | ||||
|                         this.logger.warn('Cannot get iframe src to open relative url', url, element); | ||||
| 
 | ||||
|                         return null; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (target == '_self') { | ||||
|                     // Link should be loaded in the same frame.
 | ||||
|                     if (element.tagName.toLowerCase() == 'object') { | ||||
|                         element.setAttribute('data', url); | ||||
|                     } else { | ||||
|                         element.setAttribute('src', url); | ||||
|                     } | ||||
|                 } else if (this.urlUtils.isLocalFileUrl(url)) { | ||||
|                     // It's a local file.
 | ||||
|                     this.utils.openFile(url).catch((error) => { | ||||
|                         this.domUtils.showErrorModal(error); | ||||
|                     }); | ||||
|                 } else { | ||||
|                     // It's an external link, check if it can be opened in the app.
 | ||||
|                     this.contentLinksHelper.handleLink(url, undefined, navCtrl, true, true).then((treated) => { | ||||
|                         if (!treated) { | ||||
|                             // Not opened in the app, open with browser. Check if we need to auto-login
 | ||||
|                             if (!this.sitesProvider.isLoggedIn()) { | ||||
|                                 // Not logged in, cannot auto-login.
 | ||||
|                                 this.utils.openInBrowser(url); | ||||
|                             } else { | ||||
|                                 this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(url); | ||||
|                             } | ||||
|                         } | ||||
|                     }); | ||||
|                 } | ||||
| 
 | ||||
|                  // We cannot create new Window objects directly, return null which is a valid return value for Window.open().
 | ||||
|                 return null; | ||||
|             }; | ||||
|         } | ||||
| 
 | ||||
| @ -329,21 +329,88 @@ export class CoreIframeUtilsProvider { | ||||
| 
 | ||||
|             // Add click listener to the link, this way if the iframe has added a listener to the link it will be executed first.
 | ||||
|             link.treated = true; | ||||
|             link.addEventListener('click', this.linkClicked.bind(this, element, link)); | ||||
|             link.addEventListener('click', this.linkClicked.bind(this, link, element)); | ||||
|         }, { | ||||
|             capture: true // Use capture to fix this listener not called if the element clicked is too deep in the DOM.
 | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Handle a window.open called by a frame. | ||||
|      * | ||||
|      * @param url URL passed to window.open. | ||||
|      * @param name Name passed to window.open. | ||||
|      * @param element HTML element of the frame. | ||||
|      * @param navCtrl NavController to use if a link can be opened in the app. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected async windowOpen(url: string, name: string, element?: any, navCtrl?: NavController): Promise<void> { | ||||
|         const scheme = this.urlUtils.getUrlScheme(url); | ||||
|         if (!scheme) { | ||||
|             // It's a relative URL, use the frame src to create the full URL.
 | ||||
|             const src = element && (element.src || element.data); | ||||
|             if (src) { | ||||
|                 const dirAndFile = this.fileProvider.getFileAndDirectoryFromPath(src); | ||||
|                 if (dirAndFile.directory) { | ||||
|                     url = this.textUtils.concatenatePaths(dirAndFile.directory, url); | ||||
|                 } else { | ||||
|                     this.logger.warn('Cannot get iframe dir path to open relative url', url, element); | ||||
| 
 | ||||
|                     return; | ||||
|                 } | ||||
|             } else { | ||||
|                 this.logger.warn('Cannot get iframe src to open relative url', url, element); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (name == '_self') { | ||||
|             // Link should be loaded in the same frame.
 | ||||
|             if (!element) { | ||||
|                 this.logger.warn('Cannot load URL in iframe because the element was not supplied', url); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (element.tagName.toLowerCase() == 'object') { | ||||
|                 element.setAttribute('data', url); | ||||
|             } else { | ||||
|                 element.setAttribute('src', url); | ||||
|             } | ||||
|         } else if (this.urlUtils.isLocalFileUrl(url)) { | ||||
|             // It's a local file.
 | ||||
|             try { | ||||
|                 await this.utils.openFile(url); | ||||
|             } catch (error) { | ||||
|                 this.domUtils.showErrorModal(error); | ||||
|             } | ||||
|         } else { | ||||
|             // It's an external link, check if it can be opened in the app.
 | ||||
|             const treated = await this.contentLinksHelper.handleLink(url, undefined, navCtrl, true, true); | ||||
| 
 | ||||
|             if (!treated) { | ||||
|                 // Not opened in the app, open with browser. Check if we need to auto-login
 | ||||
|                 if (!this.sitesProvider.isLoggedIn()) { | ||||
|                     // Not logged in, cannot auto-login.
 | ||||
|                     this.utils.openInBrowser(url); | ||||
|                 } else { | ||||
|                     await this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(url); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * A link inside a frame was clicked. | ||||
|      * | ||||
|      * @param link Data of the link clicked. | ||||
|      * @param element Frame element. | ||||
|      * @param link Link clicked. | ||||
|      * @param event Click event. | ||||
|      */ | ||||
|     protected linkClicked(element: HTMLFrameElement | HTMLObjectElement, link: HTMLAnchorElement, event: Event): void { | ||||
|         if (event.defaultPrevented) { | ||||
|     protected linkClicked(link: {href: string, target?: string}, element?: HTMLFrameElement | HTMLObjectElement, event?: Event) | ||||
|             : void { | ||||
|         if (event && event.defaultPrevented) { | ||||
|             // Event already prevented by some other code.
 | ||||
|             return; | ||||
|         } | ||||
| @ -356,12 +423,12 @@ export class CoreIframeUtilsProvider { | ||||
| 
 | ||||
|         if (!this.urlUtils.isLocalFileUrlScheme(urlParts.protocol, urlParts.domain)) { | ||||
|             // Scheme suggests it's an external resource.
 | ||||
|             event.preventDefault(); | ||||
|             event && event.preventDefault(); | ||||
| 
 | ||||
|             const frameSrc = (<HTMLFrameElement> element).src || (<HTMLObjectElement> element).data; | ||||
|             const frameSrc = element && ((<HTMLFrameElement> element).src || (<HTMLObjectElement> element).data); | ||||
| 
 | ||||
|             // If the frame is not local, check the target to identify how to treat the link.
 | ||||
|             if (!this.urlUtils.isLocalFileUrl(frameSrc) && (!link.target || link.target == '_self')) { | ||||
|             if (element && !this.urlUtils.isLocalFileUrl(frameSrc) && (!link.target || link.target == '_self')) { | ||||
|                 // Load the link inside the frame itself.
 | ||||
|                 if (element.tagName.toLowerCase() == 'object') { | ||||
|                     element.setAttribute('data', link.href); | ||||
| @ -380,13 +447,13 @@ export class CoreIframeUtilsProvider { | ||||
|             } | ||||
|         } else if (link.target == '_parent' || link.target == '_top' || link.target == '_blank') { | ||||
|             // Opening links with _parent, _top or _blank can break the app. We'll open it in InAppBrowser.
 | ||||
|             event.preventDefault(); | ||||
|             event && event.preventDefault(); | ||||
|             this.utils.openFile(link.href).catch((error) => { | ||||
|                 this.domUtils.showErrorModal(error); | ||||
|             }); | ||||
|         } else if (this.platform.is('ios') && (!link.target || link.target == '_self')) { | ||||
|         } else if (this.platform.is('ios') && (!link.target || link.target == '_self') && element) { | ||||
|             // In cordova ios 4.1.0 links inside iframes stopped working. We'll manually treat them.
 | ||||
|             event.preventDefault(); | ||||
|             event && event.preventDefault(); | ||||
|             if (element.tagName.toLowerCase() == 'object') { | ||||
|                 element.setAttribute('data', link.href); | ||||
|             } else { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user