| /* |
| * Copyright (c) 2014-2018 BSI Business Systems Integration AG. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * BSI Business Systems Integration AG - initial API and implementation |
| */ |
| scout.IFrame = function() { |
| scout.IFrame.parent.call(this); |
| |
| this.location = null; |
| this.sandboxEnabled = true; |
| this.sandboxPermissions = null; |
| this.scrollBarEnabled = true; |
| this.trackLocation = false; |
| // Iframe on iOS is always as big as its content. Workaround it by using a wrapper div with overflow: auto |
| // Don't wrap it when running in the chrome emulator (in that case isIosPlatform returns false) |
| this.wrapIframe = scout.device.isIosPlatform(); |
| this.$iframe = null; |
| this._loadHandler = this._onLoad.bind(this); |
| this.mutationObserver = null; |
| }; |
| scout.inherits(scout.IFrame, scout.Widget); |
| |
| scout.IFrame.prototype._render = function() { |
| if (this.wrapIframe) { |
| this.$container = this.$parent.appendDiv('iframe-wrapper'); |
| this.$iframe = this.$container.appendElement('<iframe>', 'iframe'); |
| } else { |
| this.$iframe = this.$parent.appendElement('<iframe>', 'iframe'); |
| this.$container = this.$iframe; |
| } |
| this.htmlComp = scout.HtmlComponent.install(this.$container, this.session); |
| |
| this.$iframe.one('remove', function() { |
| if (!this.rendered || this.removing) { |
| return; |
| } |
| this.mutationObserver = new MutationObserver(this._onDomMutation.bind(this)); |
| this.mutationObserver.observe(this.$iframe.document(true), { |
| subtree: true, |
| childList: true |
| }); |
| }.bind(this)); |
| }; |
| |
| scout.IFrame.prototype._remove = function() { |
| if (this.mutationObserver) { |
| this.mutationObserver.disconnect(); |
| this.mutationObserver = null; |
| } |
| scout.IFrame.parent.prototype._remove.call(this); |
| }; |
| |
| /** |
| * @override ValueField.js |
| */ |
| scout.IFrame.prototype._renderProperties = function() { |
| scout.IFrame.parent.prototype._renderProperties.call(this); |
| this._renderScrollBarEnabled(); // Needs to be before _renderLocation, see comment in _renderScrollBarEnabled |
| this._renderLocation(); |
| this._renderSandboxEnabled(); // includes _renderSandboxPermissions() |
| this._renderTrackLocationChange(); |
| }; |
| |
| scout.IFrame.prototype.setLocation = function(location) { |
| this.setProperty('location', location); |
| }; |
| |
| scout.IFrame.prototype._renderLocation = function() { |
| // Convert empty locations to 'about:blank', because in Firefox (maybe others, too?), |
| // empty locations simply remove the src attribute but don't remove the old content. |
| var location = this.location || 'about:blank'; |
| this.$iframe.attr('src', location); |
| }; |
| |
| scout.IFrame.prototype.setTrackLocationChange = function(trackLocation) { |
| this.setProperty('trackLocation', trackLocation); |
| }; |
| |
| scout.IFrame.prototype._renderTrackLocationChange = function(trackLocation) { |
| if (this.trackLocation) { |
| this.$iframe.on('load', this._loadHandler); |
| } else { |
| this.$iframe.off('load', this._loadHandler); |
| } |
| }; |
| |
| scout.IFrame.prototype._onDomMutation = function(mutationList) { |
| mutationList.forEach(function(mutation) { |
| for (var i = 0; i < mutation.addedNodes.length; i++) { |
| var elem = mutation.addedNodes[i]; |
| var $elem = $(elem); |
| if ($elem.isOrHas(this.$iframe)) { |
| this._onNodeAdded(); |
| } |
| } |
| }, this); |
| }; |
| |
| scout.IFrame.prototype._onDomMutation = function() { |
| this._renderLocation(); |
| }; |
| |
| scout.IFrame.prototype._onLoad = function(event) { |
| if (!this.rendered) { // check needed, because this is an async callback |
| return; |
| } |
| |
| if (this.trackLocation) { |
| var doc = this.$iframe[0].contentDocument; |
| if (!doc) { |
| // Doc can be null if website cannot be loaded or if website is not from same origin |
| return; |
| } |
| var location = doc.location.href; |
| if (location === 'about:blank') { |
| location = null; |
| } |
| this._setProperty('location', location); |
| } |
| }; |
| |
| scout.IFrame.prototype.setScrollBarEnabled = function(scrollBarEnabled) { |
| this.setProperty('scrollBarEnabled', scrollBarEnabled); |
| }; |
| |
| scout.IFrame.prototype._renderScrollBarEnabled = function() { |
| this.$container.toggleClass('no-scrolling', !this.scrollBarEnabled); |
| // According to http://stackoverflow.com/a/18470016, setting 'overflow: hidden' via |
| // CSS should be enough. However, if the inner page sets 'overflow' to another value, |
| // scroll bars are shown again. Therefore, we add the legacy 'scrolling' attribute, |
| // which is deprecated in HTML5, but seems to do the trick. |
| this.$iframe.attr('scrolling', (this.scrollBarEnabled ? 'yes' : 'no')); |
| |
| // re-render location otherwise the attribute change would have no effect, see |
| // https://html.spec.whatwg.org/multipage/embedded-content.html#attr-iframe-sandbox |
| if (this.rendered) { |
| this._renderLocation(); |
| } |
| }; |
| |
| scout.IFrame.prototype.setSandboxEnabled = function(sandboxEnabled) { |
| this.setProperty('sandboxEnabled', sandboxEnabled); |
| }; |
| |
| scout.IFrame.prototype._renderSandboxEnabled = function() { |
| if (this.sandboxEnabled) { |
| this._renderSandboxPermissions(); |
| } else { |
| this.$iframe.removeAttr('sandbox'); |
| this.$iframe.removeAttr('security'); |
| } |
| // re-render location otherwise the attribute change would have no effect, see |
| // https://html.spec.whatwg.org/multipage/embedded-content.html#attr-iframe-sandbox |
| this._renderLocation(); |
| }; |
| |
| scout.IFrame.prototype.setSandboxPermissions = function(sandboxPermissions) { |
| this.setProperty('sandboxPermissions', sandboxPermissions); |
| }; |
| |
| scout.IFrame.prototype._renderSandboxPermissions = function() { |
| if (!this.sandboxEnabled) { |
| return; |
| } |
| this.$iframe.attr('sandbox', scout.nvl(this.sandboxPermissions, '')); |
| if (scout.device.requiresIframeSecurityAttribute()) { |
| this.$iframe.attr('security', 'restricted'); |
| } |
| // re-render location otherwise the attribute change would have no effect, see |
| // https://html.spec.whatwg.org/multipage/embedded-content.html#attr-iframe-sandbox |
| this._renderLocation(); |
| }; |