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 { Keyboard } from '@ionic-native/keyboard'; | ||||||
| import { ScreenOrientation } from '@ionic-native/screen-orientation'; | import { ScreenOrientation } from '@ionic-native/screen-orientation'; | ||||||
| import { CoreLoginSitesPage } from '@core/login/pages/sites/sites'; | import { CoreLoginSitesPage } from '@core/login/pages/sites/sites'; | ||||||
|  | import { CoreWindow } from '@singletons/window'; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|     templateUrl: 'app.html' |     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.
 |         // Load custom lang strings. This cannot be done inside the lang provider because it causes circular dependencies.
 | ||||||
|         const loadCustomStrings = (): void => { |         const loadCustomStrings = (): void => { | ||||||
|             const currentSite = this.sitesProvider.getCurrentSite(), |             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 core classes that can be useful for site plugins.
 | ||||||
| import { CoreSyncBaseProvider } from '@classes/base-sync'; | import { CoreSyncBaseProvider } from '@classes/base-sync'; | ||||||
|  | import { CoreArray } from '@singletons/array'; | ||||||
| import { CoreUrl } from '@singletons/url'; | import { CoreUrl } from '@singletons/url'; | ||||||
|  | import { CoreWindow } from '@singletons/window'; | ||||||
| import { CoreCache } from '@classes/cache'; | import { CoreCache } from '@classes/cache'; | ||||||
| import { CoreDelegate } from '@classes/delegate'; | import { CoreDelegate } from '@classes/delegate'; | ||||||
| import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler'; | import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler'; | ||||||
| @ -270,7 +272,9 @@ export class CoreCompileProvider { | |||||||
|         instance['moment'] = moment; |         instance['moment'] = moment; | ||||||
|         instance['Md5'] = Md5; |         instance['Md5'] = Md5; | ||||||
|         instance['CoreSyncBaseProvider'] = CoreSyncBaseProvider; |         instance['CoreSyncBaseProvider'] = CoreSyncBaseProvider; | ||||||
|  |         instance['CoreArray'] = CoreArray; | ||||||
|         instance['CoreUrl'] = CoreUrl; |         instance['CoreUrl'] = CoreUrl; | ||||||
|  |         instance['CoreWindow'] = CoreWindow; | ||||||
|         instance['CoreCache'] = CoreCache; |         instance['CoreCache'] = CoreCache; | ||||||
|         instance['CoreDelegate'] = CoreDelegate; |         instance['CoreDelegate'] = CoreDelegate; | ||||||
|         instance['CoreContentLinksHandlerBase'] = CoreContentLinksHandlerBase; |         instance['CoreContentLinksHandlerBase'] = CoreContentLinksHandlerBase; | ||||||
|  | |||||||
| @ -447,6 +447,8 @@ export class CoreFormatTextDirective implements OnChanges { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         }).then((formatted) => { |         }).then((formatted) => { | ||||||
|  |             formatted = this.treatWindowOpen(formatted); | ||||||
|  | 
 | ||||||
|             const div = document.createElement('div'), |             const div = document.createElement('div'), | ||||||
|                 canTreatVimeo = site && site.isVersionGreaterEqualThan(['3.3.4', '3.4']), |                 canTreatVimeo = site && site.isVersionGreaterEqualThan(['3.3.4', '3.4']), | ||||||
|                 navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl; |                 navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl; | ||||||
| @ -740,4 +742,26 @@ export class CoreFormatTextDirective implements OnChanges { | |||||||
| 
 | 
 | ||||||
|         this.iframeUtils.treatFrame(iframe, false, navCtrl); |         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 the event prevented default action, do nothing.
 | ||||||
|             if (!event.defaultPrevented) { |             if (!event.defaultPrevented) { | ||||||
|                 let href = this.element.getAttribute('href'); |                 let href = this.element.getAttribute('href'); | ||||||
|                 if (href) { |                 if (href && this.urlUtils.getUrlScheme(href) != 'javascript') { | ||||||
|                     event.preventDefault(); |                     event.preventDefault(); | ||||||
|                     event.stopPropagation(); |                     event.stopPropagation(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -27,6 +27,7 @@ import { CoreUtilsProvider } from './utils'; | |||||||
| import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; | import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; | ||||||
| import { makeSingleton } from '@singletons/core.singletons'; | import { makeSingleton } from '@singletons/core.singletons'; | ||||||
| import { CoreUrl } from '@singletons/url'; | import { CoreUrl } from '@singletons/url'; | ||||||
|  | import { CoreWindow } from '@singletons/window'; | ||||||
| import { WKUserScriptWindow, WKUserScriptInjectionTime } from 'cordova-plugin-wkuserscript'; | import { WKUserScriptWindow, WKUserScriptInjectionTime } from 'cordova-plugin-wkuserscript'; | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
| @ -387,17 +388,9 @@ export class CoreIframeUtilsProvider { | |||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             // It's an external link, check if it can be opened in the app.
 |             // 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); |             await CoreWindow.open(url, name, { | ||||||
| 
 |                 navCtrl, | ||||||
|             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); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										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