From d774adf1abe9d9f09d5107f95e8980f49a096f01 Mon Sep 17 00:00:00 2001 From: tanglei02 Date: Tue, 30 Oct 2018 12:28:38 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20https=20=E5=88=A4?= =?UTF-8?q?=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/mip/src/components/mip-iframe.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/mip/src/components/mip-iframe.js b/packages/mip/src/components/mip-iframe.js index 607921d1..a1c5ebc9 100755 --- a/packages/mip/src/components/mip-iframe.js +++ b/packages/mip/src/components/mip-iframe.js @@ -16,13 +16,20 @@ let attrList = ['allowfullscreen', 'allowtransparency', 'sandbox'] class MipIframe extends CustomElement { build () { - this.handlePageResize = this.handlePageResize.bind(this) - this.notifyRootPage = this.notifyRootPage.bind(this) + this.bindedHandlePageResize = this.handlePageResize.bind(this) + this.bindedHnotifyRootPage = this.notifyRootPage.bind(this) + let element = this.element - let src = element.getAttribute('src') + + let src let srcdoc = element.getAttribute('srcdoc') if (srcdoc) { src = 'data:text/html;charset=utf-8;base64,' + window.btoa(srcdoc) + } else { + src = element.getAttribute('src') || '' + if ('https://' !== src.slice(0, 8)) { + return + } } let height = element.getAttribute('height') From 6c42891524c736e3f10d8fed1bf7fd831a2f0b72 Mon Sep 17 00:00:00 2001 From: tanglei02 Date: Thu, 1 Nov 2018 10:38:14 +0800 Subject: [PATCH 2/3] =?UTF-8?q?mip-iframe=20https=20=E5=8F=8A=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/mip/src/components/mip-iframe.js | 119 ++++++++++++++---- .../test/specs/components/mip-iframe.spec.js | 63 +++++++++- 2 files changed, 153 insertions(+), 29 deletions(-) diff --git a/packages/mip/src/components/mip-iframe.js b/packages/mip/src/components/mip-iframe.js index a1c5ebc9..4b06c379 100755 --- a/packages/mip/src/components/mip-iframe.js +++ b/packages/mip/src/components/mip-iframe.js @@ -1,9 +1,11 @@ /** * @file mip-iframe * @author zhangzhiqiang(zhiqiangzhang37@163.com) + * clark-t (clarktanglei@163.com) */ import util from '../util/index' +import fn from '../util/fn' import CustomElement from '../custom-element' import viewport from '../viewport' import { @@ -12,50 +14,106 @@ import { MESSAGE_PAGE_RESIZE } from '../page/const' -let attrList = ['allowfullscreen', 'allowtransparency', 'sandbox'] +const ATTR_LIST = [ + 'allowfullscreen', + 'allowtransparency', + 'sandbox', + 'referrerpolicy' +] + +function encode (str) { + let arr + if (typeof TextEncoder !== 'undefined') { + arr = new TextEncoder('utf-8').encode(str) + } else { + arr = new Uint8Array(str.length) + str = unescape(encodeURIComponent(str)) + for (let i = 0; i < str.length; i++) { + arr[i] = str.charCodeAt(i) + } + } + // 不能直接 arr.map().join() + let output = new Array(arr.length) + for (let i = 0; i < arr.length; i++) { + output[i] = String.fromCharCode(arr[i]) + } + return output.join('') +} class MipIframe extends CustomElement { - build () { - this.bindedHandlePageResize = this.handlePageResize.bind(this) - this.bindedHnotifyRootPage = this.notifyRootPage.bind(this) + constructor (...args) { + super(...args) - let element = this.element + this._src = null + this.updateIframeSrc = fn.throttle(this.setIframeSrc.bind(this)) + } - let src - let srcdoc = element.getAttribute('srcdoc') - if (srcdoc) { - src = 'data:text/html;charset=utf-8;base64,' + window.btoa(srcdoc) + static get observedAttributes () { + return ['src', 'srcdoc'] + } + + attributeChangedCallback (name, oldValue, newValue) { + if (this.isBuilt) { + this[name] = newValue + this.updateIframeSrc() + } + } + + set src (value) { + // 当 srcdoc 存在时,优先展示 srcdoc 的内容 + if (this.element.getAttribute('srcdoc')) { + return + } + // url 必须是 https + if (value == null || value.slice(0, 8) === 'https://') { + this._src = value } else { - src = element.getAttribute('src') || '' - if ('https://' !== src.slice(0, 8)) { - return + this.srcdoc = `Invalid <mip-iframe> src. Must start with https://` + } + } + + set srcdoc (value) { + // 当删除 srcdoc 属性时,显示 src 的内容 + if (value == null) { + this.src = this.element.getAttribute('src') + } else if (this._srcdoc !== value) { + this._srcdoc = value + // 兼容 mip1 + if (this.element.getAttribute('encode')) { + value = encode(value) } + this._src = 'data:text/html;charset=utf-8;base64,' + window.btoa(value) } + } - let height = element.getAttribute('height') - let width = element.getAttribute('width') || '100%' + setIframeSrc () { + if (!this._src) { + return + } - if (!src || !height) { + if (this.iframe) { + if (this.iframe.src !== this._src) { + this.iframe.src = this._src + } return } - // window.addEventListener('message', ) - window.addEventListener('message', this.notifyRootPage.bind(this)) + let height = this.element.getAttribute('height') + let width = this.element.getAttribute('width') || '100%' let iframe = document.createElement('iframe') iframe.frameBorder = '0' iframe.scrolling = util.platform.isIos() ? /* istanbul ignore next */ 'no' : 'yes' + util.css(iframe, { width, height }) this.applyFillContent(iframe) - iframe.src = src - - this.expendAttr(attrList, iframe) - element.appendChild(iframe) - + this.expendAttr(ATTR_LIST, iframe) + iframe.src = this._src + this.element.appendChild(iframe) this.iframe = iframe /** @@ -77,13 +135,24 @@ class MipIframe extends CustomElement { } } + build () { + this.bindedHandlePageResize = this.handlePageResize.bind(this) + this.bindedNotifyRootPage = this.notifyRootPage.bind(this) + + window.addEventListener('message', this.bindedNotifyRootPage) + + this.srcdoc = this.element.getAttribute('srcdoc') + this.setIframeSrc() + this.isBuilt = true + } + firstInviewCallback () { - window.addEventListener(CUSTOM_EVENT_RESIZE_PAGE, this.handlePageResize.bind(this)) + window.addEventListener(CUSTOM_EVENT_RESIZE_PAGE, this.bindedHandlePageResize) } disconnectedCallback () { - window.removeEventListener(CUSTOM_EVENT_RESIZE_PAGE, this.handlePageResize.bind(this)) - window.removeEventListener('message', this.notifyRootPage.bind(this)) + window.removeEventListener(CUSTOM_EVENT_RESIZE_PAGE, this.bindedHandlePageResize) + window.removeEventListener('message', this.bindedNotifyRootPage) } notifyRootPage ({data}) { diff --git a/packages/mip/test/specs/components/mip-iframe.spec.js b/packages/mip/test/specs/components/mip-iframe.spec.js index a7e0f7fb..719d1ae2 100644 --- a/packages/mip/test/specs/components/mip-iframe.spec.js +++ b/packages/mip/test/specs/components/mip-iframe.spec.js @@ -13,11 +13,11 @@ import { import viewport from 'src/viewport' -describe('mip-iframe', function () { - let mipIframe - let iframe - +describe.only('mip-iframe', function () { describe('iframe with default width and attrs', function () { + let mipIframe + let iframe + this.timeout(1200) before(function () { mipIframe = document.createElement('mip-iframe') @@ -50,6 +50,9 @@ describe('mip-iframe', function () { }) describe('iframe with set width and height', function () { + let mipIframe + let iframe + before(function () { mipIframe = document.createElement('mip-iframe') mipIframe.setAttribute('srcdoc', '

Hello MIP!

') @@ -107,6 +110,9 @@ describe('mip-iframe', function () { }) describe('iframe with no src and height', function () { + let mipIframe + let iframe + before(function () { mipIframe = document.createElement('mip-iframe') document.body.appendChild(mipIframe) @@ -121,4 +127,53 @@ describe('mip-iframe', function () { document.body.removeChild(mipIframe) }) }) + + describe('iframe src is HTTP', function () { + let mipIframe + let iframe + + before(function () { + mipIframe = document.createElement('mip-iframe') + mipIframe.setAttribute('width', '300px') + mipIframe.setAttribute('height', '400px') + mipIframe.setAttribute('layout', 'fixed') + mipIframe.setAttribute('src', 'http://www.baidu.com') + document.body.appendChild(mipIframe) + }) + + it('should alert HTTPS request', function () { + iframe = mipIframe.querySelector('iframe') + expect(iframe.src).to.equal('data:text/html;charset=utf-8;base64,' + window.btoa('Invalid <mip-iframe> src. Must start with https://')) + }) + + after(function () { + document.body.removeChild(mipIframe) + }) + }) + + + describe('iframe srcdoc with Chinese', function () { + this.timeout(1200) + let mipIframe + + it('should show chinese words', function (done) { + expect( + function () { + mipIframe = document.createElement('mip-iframe') + mipIframe.setAttribute('width', '300px') + mipIframe.setAttribute('height', '400px') + mipIframe.setAttribute('layout', 'fixed') + mipIframe.setAttribute('srcdoc', '

你好

') + mipIframe.setAttribute('encode', 'true') + document.body.appendChild(mipIframe) + + setTimeout(done, 1000) + } + ).to.not.throw() + }) + + after(function () { + document.body.removeChild(mipIframe) + }) + }) }) From 015aa7f8b09bc3ad6e7a5ae04d0286fb4ac2df63 Mon Sep 17 00:00:00 2001 From: tanglei02 Date: Thu, 1 Nov 2018 11:00:46 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/extensions/builtin/mip-iframe.md | 85 ++++++++++++------- .../builtin-components/mip-iframe.html | 26 ++++++ packages/mip/src/components/mip-iframe.js | 7 +- 3 files changed, 85 insertions(+), 33 deletions(-) diff --git a/docs/extensions/builtin/mip-iframe.md b/docs/extensions/builtin/mip-iframe.md index 76f6f067..5c633be8 100755 --- a/docs/extensions/builtin/mip-iframe.md +++ b/docs/extensions/builtin/mip-iframe.md @@ -7,7 +7,7 @@ 标题|内容 ----|---- 类型|通用 -支持布局|responsive, fixed-height, fixed +支持布局|responsive, fixed-height, fixed, fill, container 所需脚本|无 ## 示例 @@ -59,63 +59,88 @@ ``` +### 加 `encode` 转码中文字符 + +```html + + +``` + ## 属性 ### src -说明:与原生 `