forked from EVOgeek/Vmeda.Online
		
	Merge pull request #2477 from dpalou/MOBILE-3465
MOBILE-3465 core: Handle window.open outside of iframes
This commit is contained in:
		
						commit
						940f5bbeaf
					
				| @ -27,6 +27,7 @@ import { CoreLoginHelperProvider } from '@core/login/providers/helper'; | ||||
| import { Keyboard } from '@ionic-native/keyboard'; | ||||
| import { ScreenOrientation } from '@ionic-native/screen-orientation'; | ||||
| import { CoreLoginSitesPage } from '@core/login/pages/sites/sites'; | ||||
| import { CoreWindow } from '@singletons/window'; | ||||
| 
 | ||||
| @Component({ | ||||
|     templateUrl: 'app.html' | ||||
| @ -207,6 +208,11 @@ export class MoodleMobileApp implements OnInit { | ||||
|             }); | ||||
|         }; | ||||
| 
 | ||||
|         // "Expose" CoreWindow.open.
 | ||||
|         (<any> window).openWindowSafely = (url: string, name?: string, windowFeatures?: string): void => { | ||||
|             CoreWindow.open(url, name); | ||||
|         }; | ||||
| 
 | ||||
|         // Load custom lang strings. This cannot be done inside the lang provider because it causes circular dependencies.
 | ||||
|         const loadCustomStrings = (): void => { | ||||
|             const currentSite = this.sitesProvider.getCurrentSite(), | ||||
|  | ||||
| @ -57,7 +57,9 @@ import { Md5 } from 'ts-md5/dist/md5'; | ||||
| 
 | ||||
| // Import core classes that can be useful for site plugins.
 | ||||
| import { CoreSyncBaseProvider } from '@classes/base-sync'; | ||||
| import { CoreArray } from '@singletons/array'; | ||||
| import { CoreUrl } from '@singletons/url'; | ||||
| import { CoreWindow } from '@singletons/window'; | ||||
| import { CoreCache } from '@classes/cache'; | ||||
| import { CoreDelegate } from '@classes/delegate'; | ||||
| import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler'; | ||||
| @ -270,7 +272,9 @@ export class CoreCompileProvider { | ||||
|         instance['moment'] = moment; | ||||
|         instance['Md5'] = Md5; | ||||
|         instance['CoreSyncBaseProvider'] = CoreSyncBaseProvider; | ||||
|         instance['CoreArray'] = CoreArray; | ||||
|         instance['CoreUrl'] = CoreUrl; | ||||
|         instance['CoreWindow'] = CoreWindow; | ||||
|         instance['CoreCache'] = CoreCache; | ||||
|         instance['CoreDelegate'] = CoreDelegate; | ||||
|         instance['CoreContentLinksHandlerBase'] = CoreContentLinksHandlerBase; | ||||
|  | ||||
| @ -447,6 +447,8 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
|             } | ||||
| 
 | ||||
|         }).then((formatted) => { | ||||
|             formatted = this.treatWindowOpen(formatted); | ||||
| 
 | ||||
|             const div = document.createElement('div'), | ||||
|                 canTreatVimeo = site && site.isVersionGreaterEqualThan(['3.3.4', '3.4']), | ||||
|                 navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl; | ||||
| @ -740,4 +742,26 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
| 
 | ||||
|         this.iframeUtils.treatFrame(iframe, false, navCtrl); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Convert window.open to window.openWindowSafely inside HTML tags. | ||||
|      * | ||||
|      * @param text Text to treat. | ||||
|      * @return Treated text. | ||||
|      */ | ||||
|     protected treatWindowOpen(text: string): string { | ||||
|         // Get HTML tags that include window.open. Script tags aren't executed so there's no need to treat them.
 | ||||
|         const matches = text.match(/<[^>]+window\.open\([^\)]*\)[^>]*>/g); | ||||
| 
 | ||||
|         if (matches) { | ||||
|             matches.forEach((match) => { | ||||
|                 // Replace all the window.open inside the tag.
 | ||||
|                 const treated = match.replace(/window\.open\(/g, 'window.openWindowSafely('); | ||||
| 
 | ||||
|                 text = text.replace(match, treated); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         return text; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -71,7 +71,7 @@ export class CoreLinkDirective implements OnInit { | ||||
|             // If the event prevented default action, do nothing.
 | ||||
|             if (!event.defaultPrevented) { | ||||
|                 let href = this.element.getAttribute('href'); | ||||
|                 if (href) { | ||||
|                 if (href && this.urlUtils.getUrlScheme(href) != 'javascript') { | ||||
|                     event.preventDefault(); | ||||
|                     event.stopPropagation(); | ||||
| 
 | ||||
|  | ||||
| @ -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 { CoreWindow } from '@singletons/window'; | ||||
| import { WKUserScriptWindow, WKUserScriptInjectionTime } from 'cordova-plugin-wkuserscript'; | ||||
| 
 | ||||
| /* | ||||
| @ -387,17 +388,9 @@ export class CoreIframeUtilsProvider { | ||||
|             } | ||||
|         } 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); | ||||
|                 } | ||||
|             } | ||||
|             await CoreWindow.open(url, name, { | ||||
|                 navCtrl, | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										67
									
								
								src/singletons/window.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/singletons/window.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | ||||
| // (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 { NavController } from 'ionic-angular'; | ||||
| import { CoreSites } from '@providers/sites'; | ||||
| import { CoreUrlUtils } from '@providers/utils/url'; | ||||
| import { CoreUtils } from '@providers/utils/utils'; | ||||
| import { CoreContentLinksHelper } from '@core/contentlinks/providers/helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Options for the open function. | ||||
|  */ | ||||
| export type CoreWindowOpenOptions = { | ||||
|     /** | ||||
|      * NavController to use when opening the link in the app. | ||||
|      */ | ||||
|     navCtrl?: NavController; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Singleton with helper functions for windows. | ||||
|  */ | ||||
| export class CoreWindow { | ||||
| 
 | ||||
|     /** | ||||
|      * "Safe" implementation of window.open. It will open the URL without overriding the app. | ||||
|      * | ||||
|      * @param url URL to open. | ||||
|      * @param name Name of the browsing context into which to load the URL. | ||||
|      * @param options Other options. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     static async open(url: string, name?: string, options?: CoreWindowOpenOptions): Promise<void> { | ||||
|         if (CoreUrlUtils.instance.isLocalFileUrl(url)) { | ||||
|             await CoreUtils.instance.openFile(url); | ||||
|         } else { | ||||
|             let treated: boolean; | ||||
|             options = options || {}; | ||||
| 
 | ||||
|             if (name != '_system') { | ||||
|                 // Check if it can be opened in the app.
 | ||||
|                 treated = await CoreContentLinksHelper.instance.handleLink(url, undefined, options.navCtrl, true, true); | ||||
|             } | ||||
| 
 | ||||
|             if (!treated) { | ||||
|                 // Not opened in the app, open with browser. Check if we need to auto-login
 | ||||
|                 if (!CoreSites.instance.isLoggedIn()) { | ||||
|                     // Not logged in, cannot auto-login.
 | ||||
|                     CoreUtils.instance.openInBrowser(url); | ||||
|                 } else { | ||||
|                     await CoreSites.instance.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(url); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user