From 5bf639128951fce2c9248c97c13ab1fd151d9adb Mon Sep 17 00:00:00 2001 From: xch1029 <158972928@qq.com> Date: Wed, 1 Feb 2023 11:02:24 +0800 Subject: [PATCH 01/13] fix: jquery not work in plugin demo --- dev/plugin.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dev/plugin.html b/dev/plugin.html index 9469fd75..d05cdcd9 100644 --- a/dev/plugin.html +++ b/dev/plugin.html @@ -10,6 +10,7 @@ +
@@ -94,7 +95,7 @@ function newTabUseJQuery() { console.info('newTabUseJQuery() Start'); - var tab = new window.vConsole.VConsolePlugin('tab4', 'Tab4'); + var tab = new window.VConsole.VConsolePlugin('tab4', 'Tab4'); var $html = $('
Alert
'); $html.find('a').click(function() { alert('OK'); @@ -108,7 +109,7 @@ function newTabUseDOM() { console.info('newTabUseDOM() Start'); - var tab = new window.vConsole.VConsolePlugin('tab5', 'Tab5'); + var tab = new window.VConsole.VConsolePlugin('tab5', 'Tab5'); var $elm = document.createElement('DIV'); $elm.innerHTML = '

It works

'; tab.on('renderTab', function(cb) { @@ -136,4 +137,4 @@ console.info('removePlugin() End'); } - \ No newline at end of file + From be8a4786a2e9281007e4bba61e4dc2739a86fec8 Mon Sep 17 00:00:00 2001 From: novlan1 <1576271227@qq.com> Date: Thu, 18 May 2023 17:48:58 +0800 Subject: [PATCH 02/13] feat(network): add network hide option --- src/core/options.interface.ts | 1 + src/network/network.model.ts | 7 ++++++- src/network/network.ts | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/core/options.interface.ts b/src/core/options.interface.ts index 7c63c842..27a38013 100644 --- a/src/core/options.interface.ts +++ b/src/core/options.interface.ts @@ -5,6 +5,7 @@ export interface VConsoleLogOptions { export interface VConsoleNetworkOptions { maxNetworkNumber?: number; + hideUrlRegexp?: RegExp; } export type VConsoleAvailableStorage = 'cookies' | 'localStorage' | 'sessionStorage' | 'wxStorage'; diff --git a/src/network/network.model.ts b/src/network/network.model.ts index 5a039354..4a4f7fe8 100644 --- a/src/network/network.model.ts +++ b/src/network/network.model.ts @@ -18,8 +18,9 @@ export const requestList = writable<{ [id: string]: VConsoleNetworkRequestItem } */ export class VConsoleNetworkModel extends VConsoleModel { public maxNetworkNumber: number = 1000; + public hideUrlRegexp?: RegExp protected itemCounter: number = 0; - + constructor() { super(); this.mockXHR(); @@ -49,6 +50,10 @@ export class VConsoleNetworkModel extends VConsoleModel { * Add or update a request item by request ID. */ public updateRequest(id: string, data: VConsoleNetworkRequestItem) { + const { url } = data; + if (url && this.hideUrlRegexp?.test(url)) { + return; + } const reqList = get(requestList); const hasItem = !!reqList[id]; if (hasItem) { diff --git a/src/network/network.ts b/src/network/network.ts index 67451d85..db1bee85 100644 --- a/src/network/network.ts +++ b/src/network/network.ts @@ -41,5 +41,8 @@ export class VConsoleNetworkPlugin extends VConsoleSveltePlugin { if (this.vConsole.option.network?.maxNetworkNumber !== this.model.maxNetworkNumber) { this.model.maxNetworkNumber = Number(this.vConsole.option.network?.maxNetworkNumber) || MAX_NETWORK_NUMBER; } + if (this.vConsole.option.network?.hideUrlRegexp) { + this.model.hideUrlRegexp = this.vConsole.option.network.hideUrlRegexp + } } } From b91591703490e032451f7734212f6458bde9be6a Mon Sep 17 00:00:00 2001 From: Maiz Date: Mon, 22 May 2023 20:17:07 +0800 Subject: [PATCH 03/13] Fix(core): Fix prototype pollution in `vConsole.setOption()`. (issue #616 #621) --- dev/common.html | 5 +++++ src/core/core.ts | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/dev/common.html b/dev/common.html index 7d55a8fb..d6a398f0 100644 --- a/dev/common.html +++ b/dev/common.html @@ -93,6 +93,11 @@ vConsole.setOption('log.maxLogNumber', 20); vConsole.setOption({ network: { maxNetworkNumber: 30 }}); vConsole.setOption({ network: { b: 123 }}); // overwrite previous line + vConsole.setOption({ '__proto__': { a: 1 }, 'prototype': { b: 2 }, 'constructor': 3 }); + vConsole.setOption('__proto__.noOrig', 1); + vConsole.setOption('prototype.noOrig', 2); + vConsole.setOption('constructor', () => { console.log('hack') }); + vConsole.setOption('log.__proto__.noOrig', 1); console.log(vConsole.option); } diff --git a/src/core/core.ts b/src/core/core.ts index 843db2bf..481504ab 100644 --- a/src/core/core.ts +++ b/src/core/core.ts @@ -517,21 +517,32 @@ export class VConsole { * @example `setOption({ log: { maxLogNumber: 20 }})`: overwrite 'log' object. */ public setOption(keyOrObj: any, value?: any) { + if (typeof keyOrObj === 'string') { // parse `a.b = val` to `a: { b: val }` const keys = keyOrObj.split('.'); let opt: any = this.option; - for (let i = 0; i < keys.length - 1; i++) { + for (let i = 0; i < keys.length; i++) { + if (keys[i] === '__proto__' || keys[i] === 'constructor' || keys[i] === 'prototype') { + console.debug(`[vConsole] Cannot set \`${keys[i]}\` in \`vConsole.setOption()\`.`); + return; + } if (opt[keys[i]] === undefined) { opt[keys[i]] = {}; } + if (i === keys.length - 1) { + opt[keys[i]] = value; + } opt = opt[keys[i]]; } - opt[keys[keys.length - 1]] = value; this._triggerPluginsEvent('updateOption'); this._updateComponentByOptions(); } else if (tool.isObject(keyOrObj)) { for (let k in keyOrObj) { + if (k === '__proto__' || k === 'constructor' || k === 'prototype') { + console.debug(`[vConsole] Cannot set \`${k}\` in \`vConsole.setOption()\`.`); + continue; + } this.option[k] = keyOrObj[k]; } this._triggerPluginsEvent('updateOption'); From 56efb35cef04977b05f49f3c6520a75d8341bb7e Mon Sep 17 00:00:00 2001 From: Maiz Date: Mon, 22 May 2023 20:34:11 +0800 Subject: [PATCH 04/13] chore: rename hideUrlRegexp to ignoreUrlRegExp --- CHANGELOG.md | 8 +++++++- CHANGELOG_CN.md | 8 +++++++- doc/public_properties_methods.md | 1 + doc/public_properties_methods_CN.md | 1 + package.json | 2 +- src/core/options.interface.ts | 2 +- src/network/network.model.ts | 4 ++-- src/network/network.ts | 4 ++-- 8 files changed, 22 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09ac340e..d35e2d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ English | [简体中文](./CHANGELOG_CN.md) +## 3.16.0 (2023-05-??) + +- `Feat(Netwrk)` Add new option `network.ignoreUrlRegExp` to skip some requests. (PR #623) +- `Fix(Core)` Fix prototype pollution in `vConsole.setOption()`. (issue #616 #621) + + ## 3.15.0 (2022-11-02) - `Feat(Log)` Add recycle scrolling to imporove performance, and add scroll to top/bottom buttons. (PR #570) @@ -77,7 +83,7 @@ English | [简体中文](./CHANGELOG_CN.md) ## 3.13.0 (2022-03-15) -- `Feat(Log)` Add new option `log.showTimestames`, see [Public Properties & Methods](./doc/public_properties_methods.md). +- `Feat(Log)` Add new option `log.showTimestamps`, see [Public Properties & Methods](./doc/public_properties_methods.md). - `Fix(Core)` Use polyfill `click` event to prevent raw click event not working in some cases. - `Fix(style)` Fix CSS transition failure in WeChat webview by using `bottom` instead of `transform`. - `Fix(Core)` Fix error when calling vConsole method in `onReady` callback. (issue #516) diff --git a/CHANGELOG_CN.md b/CHANGELOG_CN.md index 120f82b7..c8e1d82d 100644 --- a/CHANGELOG_CN.md +++ b/CHANGELOG_CN.md @@ -1,5 +1,11 @@ [English](./CHANGELOG.md) | 简体中文 +## 3.16.0 (2023-05-??) + +- `Feat(Netwrk)` 新增配置项 `network.ignoreUrlRegExp` 以跳过一些请求。 (PR #623) +- `Fix(Core)` 修复 `vConsole.setOption()` 中可能存在的原型污染问题。 (issue #616 #621) + + ## 3.15.0 (2022-11-02) - `Feat(Log)` 新增虚拟滚动列表以提升性能,并支持快速滚动到顶部/底部。 (PR #570) @@ -77,7 +83,7 @@ ## 3.13.0 (2022-03-15) -- `Feat(Log)` 新增配置项 `log.showTimestames`,见 [公共属性及方法](./doc/public_properties_methods_CN.md)。 +- `Feat(Log)` 新增配置项 `log.showTimestamps`,见 [公共属性及方法](./doc/public_properties_methods_CN.md)。 - `Fix(Core)` 使用模拟的 `click` 事件以避免某些场景下原生 click 事件不生效的问题。 - `Fix(style)` 修复微信 Webview 中的 CSS transition 失效的问题,通过使用 `bottom` 而非 `transform`。 - `Fix(Core)` 修复在 `onReady` 回调中调用 vConsole 方法导致报错的问题。 (issue #516) diff --git a/doc/public_properties_methods.md b/doc/public_properties_methods.md index 82899395..9fc60127 100644 --- a/doc/public_properties_methods.md +++ b/doc/public_properties_methods.md @@ -57,6 +57,7 @@ target | String, HTMLElement | true | `document.documentElement` log.maxLogNumber | Number | true | 1000 | Overflow logs will be removed from log panels. log.showTimestamps | Boolean | true | false | Display timestamps of logs. network.maxNetworkNumber | Number | true | 1000 | Overflow requests will be removed from Netowrk panel. +network.ignoreUrlRegExp | RegExp | true | | Skip the requests which url match the RegExp. storage.defaultStorages | Array | true | ['cookies', 'localStorage', 'sessionStorage'] | Listed storage(s) will be available in Storage panel. Example: diff --git a/doc/public_properties_methods_CN.md b/doc/public_properties_methods_CN.md index 89f660db..0c65ea74 100644 --- a/doc/public_properties_methods_CN.md +++ b/doc/public_properties_methods_CN.md @@ -56,6 +56,7 @@ target | String, HTMLElement | true | `document.documentElement` log.maxLogNumber | Number | true | 1000 | 超出数量上限的日志会被自动清除。 log.showTimestamps | Boolean | true | false | 显示日志的输出时间 log.maxNetworkNumber | Number | true | 1000 | 超出数量上限的请求记录会被自动清除。 +network.ignoreUrlRegExp | RegExp | true | | 不展示 URL 匹配正则表达式的请求。 storage.defaultStorages | Array | true | ['cookies', 'localStorage', 'sessionStorage'] | 在 Storage 面板中要加载的 storage 类型。 例子: diff --git a/package.json b/package.json index ecf0395b..0389237b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vconsole", - "version": "3.15.0", + "version": "3.16.0-alpha", "description": "A lightweight, extendable front-end developer tool for mobile web page.", "homepage": "https://github.com/Tencent/vConsole", "files": [ diff --git a/src/core/options.interface.ts b/src/core/options.interface.ts index 27a38013..0b1b1fbb 100644 --- a/src/core/options.interface.ts +++ b/src/core/options.interface.ts @@ -5,7 +5,7 @@ export interface VConsoleLogOptions { export interface VConsoleNetworkOptions { maxNetworkNumber?: number; - hideUrlRegexp?: RegExp; + ignoreUrlRegExp?: RegExp; } export type VConsoleAvailableStorage = 'cookies' | 'localStorage' | 'sessionStorage' | 'wxStorage'; diff --git a/src/network/network.model.ts b/src/network/network.model.ts index 4a4f7fe8..47c5b9ef 100644 --- a/src/network/network.model.ts +++ b/src/network/network.model.ts @@ -18,7 +18,7 @@ export const requestList = writable<{ [id: string]: VConsoleNetworkRequestItem } */ export class VConsoleNetworkModel extends VConsoleModel { public maxNetworkNumber: number = 1000; - public hideUrlRegexp?: RegExp + public ignoreUrlRegExp: RegExp = undefined; protected itemCounter: number = 0; constructor() { @@ -51,7 +51,7 @@ export class VConsoleNetworkModel extends VConsoleModel { */ public updateRequest(id: string, data: VConsoleNetworkRequestItem) { const { url } = data; - if (url && this.hideUrlRegexp?.test(url)) { + if (url && this.ignoreUrlRegExp?.test(url)) { return; } const reqList = get(requestList); diff --git a/src/network/network.ts b/src/network/network.ts index db1bee85..04d10a89 100644 --- a/src/network/network.ts +++ b/src/network/network.ts @@ -41,8 +41,8 @@ export class VConsoleNetworkPlugin extends VConsoleSveltePlugin { if (this.vConsole.option.network?.maxNetworkNumber !== this.model.maxNetworkNumber) { this.model.maxNetworkNumber = Number(this.vConsole.option.network?.maxNetworkNumber) || MAX_NETWORK_NUMBER; } - if (this.vConsole.option.network?.hideUrlRegexp) { - this.model.hideUrlRegexp = this.vConsole.option.network.hideUrlRegexp + if (this.vConsole.option.network?.ignoreUrlRegExp) { + this.model.ignoreUrlRegExp = this.vConsole.option.network.ignoreUrlRegExp; } } } From d5ed216eb28c4549748b54368727c5b794a56d6a Mon Sep 17 00:00:00 2001 From: Maiz Date: Mon, 22 May 2023 20:55:15 +0800 Subject: [PATCH 05/13] fix: Fix possible "Cannot read property" error by `sendBeacon`. (issue #615) --- CHANGELOG.md | 1 + CHANGELOG_CN.md | 1 + src/network/network.model.ts | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d35e2d38..17fdaee8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ English | [简体中文](./CHANGELOG_CN.md) - `Feat(Netwrk)` Add new option `network.ignoreUrlRegExp` to skip some requests. (PR #623) - `Fix(Core)` Fix prototype pollution in `vConsole.setOption()`. (issue #616 #621) +- `Fix(Network)` Fix possible "Cannot read property" error by `sendBeacon`. (issue #615) ## 3.15.0 (2022-11-02) diff --git a/CHANGELOG_CN.md b/CHANGELOG_CN.md index c8e1d82d..0ede0301 100644 --- a/CHANGELOG_CN.md +++ b/CHANGELOG_CN.md @@ -4,6 +4,7 @@ - `Feat(Netwrk)` 新增配置项 `network.ignoreUrlRegExp` 以跳过一些请求。 (PR #623) - `Fix(Core)` 修复 `vConsole.setOption()` 中可能存在的原型污染问题。 (issue #616 #621) +- `Fix(Network)` 修复可能由 `sendBeacon` 引发的 "Cannot read property" 错误。 (issue #615) ## 3.15.0 (2022-11-02) diff --git a/src/network/network.model.ts b/src/network/network.model.ts index 47c5b9ef..65e7764f 100644 --- a/src/network/network.model.ts +++ b/src/network/network.model.ts @@ -105,7 +105,7 @@ export class VConsoleNetworkModel extends VConsoleModel { * @private */ private mockSendBeacon() { - if (!window.navigator.sendBeacon) { + if (!window?.navigator?.sendBeacon) { return; } window.navigator.sendBeacon = BeaconProxy.create((item: VConsoleNetworkRequestItem) => { From 81c104e726b4eefeb6956c85f8ca0bdb8b3d084e Mon Sep 17 00:00:00 2001 From: Maiz Date: Tue, 23 May 2023 19:34:12 +0800 Subject: [PATCH 06/13] fix(Log): Reset group state when `console.clear()` is called. (issue #611) --- CHANGELOG.md | 1 + CHANGELOG_CN.md | 1 + dev/log.html | 11 +++++++-- src/log/log.model.ts | 59 +++++++++++++++++--------------------------- 4 files changed, 34 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17fdaee8..1ce8d11d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ English | [简体中文](./CHANGELOG_CN.md) - `Feat(Netwrk)` Add new option `network.ignoreUrlRegExp` to skip some requests. (PR #623) - `Fix(Core)` Fix prototype pollution in `vConsole.setOption()`. (issue #616 #621) +- `Fix(Log)` Reset group state when `console.clear()` is called. (issue #611) - `Fix(Network)` Fix possible "Cannot read property" error by `sendBeacon`. (issue #615) diff --git a/CHANGELOG_CN.md b/CHANGELOG_CN.md index 0ede0301..6f5974fe 100644 --- a/CHANGELOG_CN.md +++ b/CHANGELOG_CN.md @@ -4,6 +4,7 @@ - `Feat(Netwrk)` 新增配置项 `network.ignoreUrlRegExp` 以跳过一些请求。 (PR #623) - `Fix(Core)` 修复 `vConsole.setOption()` 中可能存在的原型污染问题。 (issue #616 #621) +- `Fix(Log)` 修复调用 `console.clear()` 时没有重置 group 层级的问题。 (issue #611) - `Fix(Network)` 修复可能由 `sendBeacon` 引发的 "Cannot read property" 错误。 (issue #615) diff --git a/dev/log.html b/dev/log.html index 9d2aa6cd..3ccfd0e2 100644 --- a/dev/log.html +++ b/dev/log.html @@ -141,8 +141,8 @@ } function styling() { - console.log('%c blue %c red', 'color:blue', 'color:red'); // blue red - console.log('%c FOO', 'font-weight:bold', 'bar'); // FOO bar + console.log('%c blue %c red', 'color:blue', 'color:red', 'Foo'); // blue red Foo + console.log('%c FOO', 'font-weight:bold; font-size:18px; background-color:#00FF00; padding:3px;', 'bar'); // FOO bar console.log('%c Foo %c bar', 'color:red'); // Foo %c bar } @@ -180,6 +180,13 @@ console.log('Back to level 2'); console.groupEnd(); console.log('Back to the outer level'); + + // console.group(); + // console.log('Level 2'); + // console.group(aa); + // console.log('Level 3'); + // console.clear(); + // console.log('Now console.clear() is called.'); } function formattingLog() { diff --git a/src/log/log.model.ts b/src/log/log.model.ts index ea8b2cd3..39089cc4 100644 --- a/src/log/log.model.ts +++ b/src/log/log.model.ts @@ -1,4 +1,3 @@ -import { writable, get } from 'svelte/store'; import * as tool from '../lib/tool'; import { VConsoleModel } from '../lib/model'; import { contentStore } from '../core/core.model'; @@ -39,18 +38,6 @@ export interface IVConsoleAddLogOptions { cmdType?: 'input' | 'output'; } -// export interface IVConsoleLogStore { -// logList: IVConsoleLog[]; -// } - - -/********************************** - * Stores - **********************************/ - -// export const logStore = writable<{ [pluginId: string]: IVConsoleLogStore }>({}); - - /********************************** * Model @@ -85,12 +72,6 @@ export class VConsoleLogModel extends VConsoleModel { this.mockConsole(); } - // logStore.update((store) => { - // store[pluginId] = { - // logList: [], - // }; - // return store; - // }); Store.create(pluginId); this.ADDED_LOG_PLUGIN_ID.push(pluginId); @@ -221,6 +202,7 @@ export class VConsoleLogModel extends VConsoleModel { protected _mockConsoleClear() { window.console.clear = ((...args) => { + this.resetGroup(); this.clearLog(); this.callOriginalConsole('clear', ...args); }).bind(window.console); @@ -249,22 +231,22 @@ export class VConsoleLogModel extends VConsoleModel { } } + /** + * Reset groups by `console.group()`. + */ + public resetGroup() { + while (this.groupLevel > 0) { + console.groupEnd(); + } + } + /** * Remove all logs. */ public clearLog() { - // logStore.update((store) => { - // for (const id in store) { - // store[id].logList = []; - // } - // return store; - // }); const stores = Store.getAll(); for (let id in stores) { - stores[id].update((store) => { - store.logList = []; - return store; - }); + this.clearPluginLog(id); } } @@ -272,16 +254,21 @@ export class VConsoleLogModel extends VConsoleModel { * Remove a plugin's logs. */ public clearPluginLog(pluginId: string) { - // logStore.update((store) => { - // if (store[pluginId]) { - // store[pluginId].logList = []; - // } - // return store; - // }); + // clear logs in the queue + const logQueue = this.logQueue; + this.logQueue = []; + for (const log of logQueue) { + const logPluginId = this._extractPluginIdByLog(log); + if (logPluginId !== pluginId) { + this.logQueue.push(log); + } + } + // clear logs in the store Store.get(pluginId).update((store) => { - store.logList = []; + store.logList.length = 0; return store; }); + contentStore.updateTime(); } /** From 2e4feb3348482ede514ffba32227dd43a1a5b233 Mon Sep 17 00:00:00 2001 From: Maiz Date: Tue, 23 May 2023 20:01:22 +0800 Subject: [PATCH 07/13] fix(Log): Fix fatal error caused by iOS (less than 13.4) which is not support `ResizeObserver` interface. (issue #610) --- CHANGELOG.md | 1 + CHANGELOG_CN.md | 1 + .../recycleScroller/recycleItem.svelte | 3 ++- .../recycleScroller/recycleScroller.svelte | 3 ++- .../recycleScroller/resizeObserver.ts | 23 +++++++++++++++++++ 5 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 src/component/recycleScroller/resizeObserver.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ce8d11d..7c22c62b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ English | [简体中文](./CHANGELOG_CN.md) - `Feat(Netwrk)` Add new option `network.ignoreUrlRegExp` to skip some requests. (PR #623) - `Fix(Core)` Fix prototype pollution in `vConsole.setOption()`. (issue #616 #621) - `Fix(Log)` Reset group state when `console.clear()` is called. (issue #611) +- `Fix(Log)` Fix fatal error caused by iOS (less than 13.4) which is not support `ResizeObserver` interface. (issue #610) - `Fix(Network)` Fix possible "Cannot read property" error by `sendBeacon`. (issue #615) diff --git a/CHANGELOG_CN.md b/CHANGELOG_CN.md index 6f5974fe..b820d1c2 100644 --- a/CHANGELOG_CN.md +++ b/CHANGELOG_CN.md @@ -5,6 +5,7 @@ - `Feat(Netwrk)` 新增配置项 `network.ignoreUrlRegExp` 以跳过一些请求。 (PR #623) - `Fix(Core)` 修复 `vConsole.setOption()` 中可能存在的原型污染问题。 (issue #616 #621) - `Fix(Log)` 修复调用 `console.clear()` 时没有重置 group 层级的问题。 (issue #611) +- `Fix(Log)` 修复因 iOS(小于 13.4)不支持 `ResizeObserver` 接口导致的致命错误 (issue #610) - `Fix(Network)` 修复可能由 `sendBeacon` 引发的 "Cannot read property" 错误。 (issue #615) diff --git a/src/component/recycleScroller/recycleItem.svelte b/src/component/recycleScroller/recycleItem.svelte index 5dd718bb..3b284ecc 100644 --- a/src/component/recycleScroller/recycleItem.svelte +++ b/src/component/recycleScroller/recycleItem.svelte @@ -1,5 +1,6 @@ + +
+
\ No newline at end of file From 5229e8eb42f098d8818233482f0be11af6358b08 Mon Sep 17 00:00:00 2001 From: Maiz Date: Wed, 24 May 2023 18:58:01 +0800 Subject: [PATCH 09/13] fix: add debug info to EmptyResizeObserver --- src/component/recycleScroller/resizeObserver.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/component/recycleScroller/resizeObserver.ts b/src/component/recycleScroller/resizeObserver.ts index c7daadfe..9e42045b 100644 --- a/src/component/recycleScroller/resizeObserver.ts +++ b/src/component/recycleScroller/resizeObserver.ts @@ -4,7 +4,11 @@ */ class EmptyResizeObserver { constructor(callback: (entries: any[], observer?: EmptyResizeObserver) => void) { - // do nothing + console.debug('[vConsole] `ResizeObserver` is not supported in the browser, vConsole cannot render correctly.'); + const entries = [{ + contentRect: { height: 60 }, + }]; + callback(entries, this); } public disconnect() { @@ -20,4 +24,5 @@ class EmptyResizeObserver { } } +// export const ResizeObserverPolyfill = EmptyResizeObserver; export const ResizeObserverPolyfill = window.ResizeObserver || EmptyResizeObserver; From 289dd761c12a32685d5719d62ae90663fac97163 Mon Sep 17 00:00:00 2001 From: Maiz Date: Wed, 24 May 2023 18:59:27 +0800 Subject: [PATCH 10/13] chore: fix typings --- src/log/log.svelte | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/log/log.svelte b/src/log/log.svelte index d7d5734f..c545ee32 100644 --- a/src/log/log.svelte +++ b/src/log/log.svelte @@ -1,21 +1,21 @@ -
diff --git a/src/component/recycleScroller/recycleScroller.less b/src/component/recycleScroller/recycleScroller.less index 2c9a73c4..80e74106 100644 --- a/src/component/recycleScroller/recycleScroller.less +++ b/src/component/recycleScroller/recycleScroller.less @@ -20,6 +20,10 @@ left: 0; right: 0; } +.vc-scroller-viewport.static .vc-scroller-item { + display: block; + position: static; +} .vc-scroller-footer { diff --git a/src/component/recycleScroller/recycleScroller.svelte b/src/component/recycleScroller/recycleScroller.svelte index aa1c5d6e..79210be2 100644 --- a/src/component/recycleScroller/recycleScroller.svelte +++ b/src/component/recycleScroller/recycleScroller.svelte @@ -4,7 +4,7 @@ import ScrollHandler from './scroll/scrollHandler'; import TouchTracker from './scroll/touchTracker'; import Style from './recycleScroller.less'; - import { ResizeObserverPolyfill } from './resizeObserver'; + import { useResizeObserver, hasResizeObserver } from './resizeObserver'; import createRecycleManager from './recycleManager'; // props @@ -40,33 +40,141 @@ let visible: { key: number; index: number; show: boolean }[] = []; const updateVisible = createRecycleManager(); - - const getScrollExtent = () => - Math.max(0, frameHeight + headerHeight + footerHeight - viewportHeight); + const getScrollExtent = () => { + return Math.max(0, frameHeight + headerHeight + footerHeight - viewportHeight); + }; + const emptyEvent = () => {}; let isOnBottom = true; let avoidRefresh = false; - const scrollHandler = new ScrollHandler(getScrollExtent, async (pos) => { - // if (pos < 0) { - // ;(window as any)._vcOrigConsole.error('invalid pos', pos, new Error().stack); - // debugger - // } - const scrollExtent = getScrollExtent(); - isOnBottom = Math.abs(pos - scrollExtent) <= 1; + let oldItems = []; + let isMounted = false; + let isInited = false; + let isObservable = hasResizeObserver(); + let scrollHandler: ScrollHandler; + let touchTracker: TouchTracker; - contents.style.transform = `translateY(${-pos}px) translateZ(0)`; - // (window as any)._vcOrigConsole.log('pos', pos); - refreshScrollbar(); + const registerHeightObserver = ( + getElem: () => HTMLElement | null, + heightUpdater: (height: number) => void + ) => { + let observer: ResizeObserver | null; - if (avoidRefresh) { - avoidRefresh = false; - } else { - await new Promise((resolve) => setTimeout(resolve, 0)); + onMount(() => { + const elem = getElem(); + if (elem) { + heightUpdater(elem.getBoundingClientRect().height); + if (observer) observer.disconnect(); + const ResizeObserverPolyfill = useResizeObserver(); + observer = new ResizeObserverPolyfill((entries) => { + const entry = entries[0]; + heightUpdater(entry.contentRect.height); + }); - refresh(items, pos, viewportHeight); - } - }); + observer.observe(elem); + } else { + heightUpdater(0); + if (observer) { + observer.disconnect(); + observer = null; + } + } + }); + + onDestroy(() => { + if (observer) { + observer.disconnect(); + observer = null; + } + }); + }; + + const initHandler = () => { + if (!isObservable) { return; } + scrollHandler = scrollHandler || new ScrollHandler(getScrollExtent, async (pos) => { + // if (pos < 0) { + // ;(window as any)._vcOrigConsole.error('invalid pos', pos, new Error().stack); + // debugger + // } + const scrollExtent = getScrollExtent(); + isOnBottom = Math.abs(pos - scrollExtent) <= 1; + + contents.style.transform = `translateY(${-pos}px) translateZ(0)`; + // (window as any)._vcOrigConsole.log('pos', pos); + refreshScrollbar(); + + if (avoidRefresh) { + avoidRefresh = false; + } else { + await new Promise((resolve) => setTimeout(resolve, 0)); + + refresh(items, pos, viewportHeight); + } + }); + + touchTracker = touchTracker || new TouchTracker(scrollHandler); + }; + + const initRegisterHeightObserver = () => { + if (isInited || !isObservable) { return; } + + registerHeightObserver( + () => viewport, + async (height) => { + if (viewportHeight === height) return; + // (window as any)._vcOrigConsole.log("viewport height resize", height); + viewportHeight = height; + + let y = 0 + for (let i = 0; i < items.length; i += 1) { + y += heightMap[i]; + } + frameHeight = Math.max(y, viewportHeight - footerHeight); + frame.style.height = `${frameHeight}px`; + + // setTimeout to avoid ResizeObserver loop limit exceeded error + await new Promise((resolve) => setTimeout(resolve, 0)); + + initItems(items); + refresh(items, scrollHandler.getPosition(), viewportHeight); + if (viewportHeight !== 0) scrollToBottom(isOnBottom && stickToBottom); + refreshScrollbar(); + } + ); + + registerHeightObserver( + () => footer, + (height) => { + if (footerHeight === height) return; + // ;(window as any)._vcOrigConsole.log('footer height resize', height); + // no need to fresh + footerHeight = height; + + let y = 0 + for (let i = 0; i < items.length; i += 1) { + y += heightMap[i]; + } + frameHeight = Math.max(y, viewportHeight - headerHeight - footerHeight); + frame.style.height = `${frameHeight}px`; + + if (viewportHeight !== 0) scrollToBottom(isOnBottom && stickToBottom); + refreshScrollbar(); + } + ); + + registerHeightObserver( + () => header, + (height) => { + if (headerHeight === height) return; + // ;(window as any)._vcOrigConsole.log('header height resize', height); + // no need to fresh + headerHeight = height; + initItems(items); + refreshScrollbar(); + } + ); + }; const refreshScrollbar = () => { const pos = scrollHandler.getPosition(); @@ -88,21 +196,28 @@ } }; - function initItems(items) { - return init(items, viewportHeight, itemHeight); - } - - let oldItems = []; - let mounted; + const initItems = (items) => { + init(items, viewportHeight, itemHeight); + }; // whenever `items` or `itemHeight` changes, refresh the viewport - $: if (mounted) initItems(items); + $: { + if (isMounted) { + if (!isObservable) { + // hack: When the ResizeObserver is not available, use native scrolling. + // At this time, the parent container should have an automatic height instead of a fixed height + viewport.parentElement.style.height = 'auto'; + } + initItems(items); + isInited = true; + } + } function init(items, viewportHeight, itemHeight) { // preserve heightMap const itemsHeightMap = new Map(); - // (window as any)._vcOrigConsole.log("init"); + // (window as any)._vcOrigConsole.log('init', isObservable); // let reuseHeightCount = 0; for (let i = 0; i < oldItems.length; i += 1) { @@ -136,10 +251,14 @@ oldItems = items; - refresh(items, scrollHandler.getPosition(), viewportHeight); - frame.style.height = `${frameHeight}px`; - scrollToBottom(isOnBottom && stickToBottom); - refreshScrollbar(); + if (isObservable) { + refresh(items, scrollHandler.getPosition(), viewportHeight); + frame.style.height = `${frameHeight}px`; + scrollToBottom(isOnBottom && stickToBottom); + refreshScrollbar(); + } else { + refresh(items, 0, 9000000); + } } function refresh(items: any[], scrollTop: number, viewportHeight: number) { @@ -167,96 +286,6 @@ visible = updateVisible(items.length, start, end); } - const registerHeightObserver = ( - getElem: () => HTMLElement | null, - heightUpdater: (height: number) => void - ) => { - let observer: ResizeObserver | null; - - onMount(() => { - const elem = getElem(); - if (elem) { - heightUpdater(elem.getBoundingClientRect().height); - if (observer) observer.disconnect(); - observer = new ResizeObserverPolyfill((entries) => { - const entry = entries[0]; - heightUpdater(entry.contentRect.height); - }); - - observer.observe(elem); - } else { - heightUpdater(0); - if (observer) { - observer.disconnect(); - observer = null; - } - } - }); - - onDestroy(() => { - if (observer) { - observer.disconnect(); - observer = null; - } - }); - }; - - registerHeightObserver( - () => viewport, - async (height) => { - if (viewportHeight === height) return; - // (window as any)._vcOrigConsole.log("viewport height resize", height); - viewportHeight = height; - - let y = 0 - for (let i = 0; i < items.length; i += 1) { - y += heightMap[i]; - } - frameHeight = Math.max(y, viewportHeight - footerHeight); - frame.style.height = `${frameHeight}px`; - - // setTimeout to avoid ResizeObserver loop limit exceeded error - await new Promise((resolve) => setTimeout(resolve, 0)); - - initItems(items); - refresh(items, scrollHandler.getPosition(), viewportHeight); - if (viewportHeight !== 0) scrollToBottom(isOnBottom && stickToBottom); - refreshScrollbar(); - } - ); - - registerHeightObserver( - () => footer, - (height) => { - if (footerHeight === height) return; - // ;(window as any)._vcOrigConsole.log('footer height resize', height); - // no need to fresh - footerHeight = height; - - let y = 0 - for (let i = 0; i < items.length; i += 1) { - y += heightMap[i]; - } - frameHeight = Math.max(y, viewportHeight - headerHeight - footerHeight); - frame.style.height = `${frameHeight}px`; - - if (viewportHeight !== 0) scrollToBottom(isOnBottom && stickToBottom); - refreshScrollbar(); - } - ); - - registerHeightObserver( - () => header, - (height) => { - if (headerHeight === height) return; - // ;(window as any)._vcOrigConsole.log('header height resize', height); - // no need to fresh - headerHeight = height; - initItems(items); - refreshScrollbar(); - } - ); - const onRowResize = async (index: number, height: number) => { if (heightMap[index] === height || viewportHeight === 0) return; @@ -303,7 +332,7 @@ // trigger initial refresh onMount(() => { - mounted = true; + isMounted = true; Style.use(); }); @@ -311,10 +340,14 @@ Style.unuse(); }); - const touchTracker = new TouchTracker(scrollHandler); + if (isObservable) { + initHandler(); + initRegisterHeightObserver(); + } export const handler = { scrollTo: (index: number) => { + if (!isObservable) { return; } const itemPos = topMap[Math.max(0, Math.min(items.length - 1, index))]; const scrollPos = Math.min(getScrollExtent(), itemPos); @@ -336,12 +369,13 @@
{#if $$slots.header} diff --git a/src/component/recycleScroller/resizeObserver.ts b/src/component/recycleScroller/resizeObserver.ts index 9e42045b..93f12984 100644 --- a/src/component/recycleScroller/resizeObserver.ts +++ b/src/component/recycleScroller/resizeObserver.ts @@ -6,7 +6,7 @@ class EmptyResizeObserver { constructor(callback: (entries: any[], observer?: EmptyResizeObserver) => void) { console.debug('[vConsole] `ResizeObserver` is not supported in the browser, vConsole cannot render correctly.'); const entries = [{ - contentRect: { height: 60 }, + contentRect: { height: 30 }, }]; callback(entries, this); } @@ -24,5 +24,12 @@ class EmptyResizeObserver { } } -// export const ResizeObserverPolyfill = EmptyResizeObserver; -export const ResizeObserverPolyfill = window.ResizeObserver || EmptyResizeObserver; +export const hasResizeObserver = () => { + // return false; + return typeof window.ResizeObserver === 'function'; +}; + +export const useResizeObserver = () => { + // return EmptyResizeObserver; + return window.ResizeObserver || EmptyResizeObserver; +}; diff --git a/src/core/core.svelte b/src/core/core.svelte index 4e20ea42..e00097ad 100644 --- a/src/core/core.svelte +++ b/src/core/core.svelte @@ -168,6 +168,7 @@ } }; const onContentTouchStart = (e) => { + // (window as any)._vcOrigConsole.log('onContentTouchStart', e.target.tagName, e.target.className); // skip inputs let isInputElement = e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA'; if (isInputElement) { @@ -177,9 +178,10 @@ let isScrollElement = false; if (typeof window.getComputedStyle === 'function') { const style = window.getComputedStyle(e.target); - if (style.overflow === 'auto' || style.overflow === 'scroll') { + if (style.overflow === 'auto' || style.overflow === 'initial' || style.overflow === 'scroll') { isScrollElement = true; } + // (window as any)._vcOrigConsole.log('onContentTouchStart isScrollElement', style.overflow); } if (isScrollElement) { // (window as any)._vcOrigConsole.log('onContentTouchStart isScrollElement', isScrollElement); @@ -188,6 +190,7 @@ const top = divContent.scrollTop, totalScroll = divContent.scrollHeight, currentScroll = top + divContent.offsetHeight; + // (window as any)._vcOrigConsole.log('onContentTouchStart', `top=${top}`, `totalScroll=${totalScroll}`, `currentScroll=${currentScroll}`); if (top === 0) { // when content is on the top, // reset scrollTop to lower position to prevent iOS apply scroll action to background From 84b4c2200b6b4658fef258ac9937d91b7aa62824 Mon Sep 17 00:00:00 2001 From: Maiz Date: Thu, 1 Jun 2023 17:07:39 +0800 Subject: [PATCH 13/13] chore: v3.15.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0389237b..fdbbe052 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vconsole", - "version": "3.16.0-alpha", + "version": "3.15.1", "description": "A lightweight, extendable front-end developer tool for mobile web page.", "homepage": "https://github.com/Tencent/vConsole", "files": [