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 = $('
');
$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 @@