mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-13 19:47:57 +08:00
🔥 Sync 2026-09-28 00:13:15
This commit is contained in:
1 parent
c540ea3fd1
commit
1854a1c960
151 files changed
+25199
-9649
No files matched your search
@@ -11,5 +11,5 @@
|
||||
* GENERATED — do not edit. Edit fwlive.css and run: node scripts/embed-fwlive-css.js
|
||||
*/
|
||||
return baseclass.extend({
|
||||
styleText: "\n/* SPDX-License-Identifier: Apache-2.0 */\n.fwlive-map {\n\tmax-width: none;\n\twidth: 100%;\n\t--fwlive-pass-color: var(--success-color-high, var(--success-color, #46a546));\n\t--fwlive-deny-color: var(--error-color-high, var(--error-color, #ca3c3c));\n\t--fwlive-bg-medium: var(--background-color-medium, var(--white-color-low, #f9f9f9));\n\t--fwlive-paused-color: #b45309;\n}\n/* Wide page in Detail only — Simple keeps LuCI’s 940px column. */\n#maincontent.container:has(.fwlive-map[data-view=\"detailed\"]) {\n\tmax-width: none;\n\tpadding-left: 16px;\n\tpadding-right: 16px;\n}\n.fwlive-map[data-row-tint=\"accessible\"] {\n\t--fwlive-pass-color: #0d9488;\n\t--fwlive-deny-color: #c2410c;\n}\n.fwlive-map.fwlive-watch-paused .fwlive-title-row,\n.fwlive-map.fwlive-watch-paused .fwlive-watch-strip {\n\tbackground: rgba(180, 83, 9, 0.08);\n\tbackground: color-mix(in srgb, var(--fwlive-paused-color) 8%, transparent);\n}\n.fwlive-map.fwlive-watch-paused .fwlive-title-row {\n\tmargin: 0 -8px;\n\tpadding: 6px 8px 0;\n\tborder-radius: 3px 3px 0 0;\n}\n.fwlive-map.fwlive-watch-paused .fwlive-watch-strip {\n\tmargin: 0 -8px 10px;\n\tpadding: 8px;\n\tborder-radius: 0 0 3px 3px;\n\tborder-bottom-color: transparent;\n}\n.fwlive-title-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tjustify-content: space-between;\n\tgap: 8px 16px;\n\tmargin: 0 0 4px;\n}\n.fwlive-title-row h2 {\n\tmargin: 0;\n\tflex: 0 1 auto;\n}\n.fwlive-title-status {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n\tmargin-left: auto;\n}\n.fwlive-watch-strip {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: stretch;\n\tjustify-content: flex-start;\n\tgap: 0;\n\tmin-height: 40px;\n\tpadding: 8px 0 10px;\n\tborder-bottom: 1px solid var(--border-color-medium);\n\tmargin-bottom: 10px;\n}\n.fwlive-watch-group {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tmin-height: 28px;\n\tpadding: 0 10px;\n\tborder-left: 1px solid var(--border-color-medium);\n\tflex-wrap: wrap;\n}\n.fwlive-watch-group:last-child {\n\tpadding-right: 0;\n}\n.fwlive-watch-group-label {\n\tmargin-right: 2px;\n\tcolor: var(--text-color-medium);\n\tfont-size: 0.72em;\n\tfont-weight: 700;\n\tletter-spacing: 0.08em;\n\ttext-transform: uppercase;\n\twhite-space: nowrap;\n}\n.fwlive-watch-seg {\n\tdisplay: inline-flex;\n\talign-items: stretch;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\toverflow: hidden;\n}\n.fwlive-watch-seg .fwlive-seg-btn {\n\tmargin: 0;\n\tborder: 0;\n\tborder-radius: 0;\n\tborder-right: 1px solid var(--border-color-medium);\n\tbackground: transparent;\n\tpadding: 4px 10px;\n\tfont-size: 0.88em;\n\tline-height: 1.25;\n\tmin-height: 28px;\n}\n.fwlive-watch-seg .fwlive-seg-btn:last-child {\n\tborder-right: 0;\n}\n.fwlive-watch-seg .fwlive-seg-btn[aria-pressed=\"true\"] {\n\tbackground: rgba(26, 111, 156, 0.12);\n\tbackground: color-mix(in srgb, var(--primary-color-high) 12%, transparent);\n\tcolor: var(--primary-color-high);\n\tfont-weight: 600;\n}\n.fwlive-watch-label { font-weight: 600; }\n.fwlive-watch-paused .fwlive-watch-label { color: var(--fwlive-paused-color); }\n.fwlive-map.fwlive-watch-paused .fwlive-title-status .fwlive-watch-label { color: var(--fwlive-paused-color); }\n.fwlive-dot {\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 50%;\n\tbackground: var(--text-color-low, var(--border-color-high));\n\tdisplay: inline-block;\n\tflex-shrink: 0;\n}\n.fwlive-dot.fwlive-dot-on {\n\tbackground: var(--fwlive-pass-color);\n\tbox-shadow: 0 0 0 3px color-mix(in srgb, var(--fwlive-pass-color) 22%, transparent);\n}\n.fwlive-btn-ghost {\n\tbackground: transparent;\n\tborder-color: var(--border-color-medium);\n}\n.fwlive-btn-quiet {\n\tbackground: transparent;\n\tborder-color: var(--border-color-medium);\n\tcolor: var(--text-color-medium);\n\tfont-weight: 500;\n}\n.fwlive-log-merged {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 10px;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\tbackground: var(--background-color-medium, var(--white-color-low, var(--background-color-high)));\n\tcolor: var(--text-color-high);\n\tfont-weight: 500;\n\tfont-size: 0.88em;\n\tline-height: 1.25;\n\tmin-height: 28px;\n\tcursor: pointer;\n}\n.fwlive-log-merged:hover {\n\tbackground: var(--background-color-low, var(--background-color-medium));\n}\n.fwlive-log-merged:disabled {\n\topacity: 0.65;\n\tcursor: default;\n}\n.fwlive-log-on-dot {\n\twidth: 6px;\n\theight: 6px;\n\tborder-radius: 50%;\n\tbackground: var(--fwlive-pass-color);\n\tflex-shrink: 0;\n}\n.fwlive-log-rate {\n\tcolor: var(--text-color-medium);\n\tfont-weight: 400;\n}\n.fwlive-display-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px 14px;\n\tmargin: 0 0 12px;\n\tpadding: 8px 12px;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\tbackground: var(--background-color-high);\n}\n.fwlive-dLine truncated
|
||||
styleText: "\n/* SPDX-License-Identifier: Apache-2.0 */\n.fwlive-map {\n\tmax-width: none;\n\twidth: 100%;\n\t--fwlive-pass-color: var(--success-color-high, var(--success-color, #46a546));\n\t--fwlive-deny-color: var(--error-color-high, var(--error-color, #ca3c3c));\n\t--fwlive-bg-medium: var(--background-color-medium, var(--white-color-low, #f9f9f9));\n\t--fwlive-paused-color: #b45309;\n}\n/* Wide page in Detail only — Simple keeps LuCI’s 940px column. */\n#maincontent.container:has(.fwlive-map[data-view=\"detailed\"]) {\n\tmax-width: none;\n\tpadding-left: 16px;\n\tpadding-right: 16px;\n}\n.fwlive-map[data-row-tint=\"accessible\"] {\n\t--fwlive-pass-color: #0d9488;\n\t--fwlive-deny-color: #c2410c;\n}\n.fwlive-map.fwlive-watch-paused .fwlive-title-row,\n.fwlive-map.fwlive-watch-paused .fwlive-watch-strip {\n\tbackground: rgba(180, 83, 9, 0.08);\n\tbackground: color-mix(in srgb, var(--fwlive-paused-color) 8%, transparent);\n}\n.fwlive-map.fwlive-watch-paused .fwlive-title-row {\n\tmargin: 0 -8px;\n\tpadding: 6px 8px 0;\n\tborder-radius: 3px 3px 0 0;\n}\n.fwlive-map.fwlive-watch-paused .fwlive-watch-strip {\n\tmargin: 0 -8px 10px;\n\tpadding: 8px;\n\tborder-radius: 0 0 3px 3px;\n\tborder-bottom-color: transparent;\n}\n.fwlive-title-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tjustify-content: space-between;\n\tgap: 8px 16px;\n\tmargin: 0 0 4px;\n}\n.fwlive-title-row h2 {\n\tmargin: 0;\n\tflex: 0 1 auto;\n}\n.fwlive-title-status {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n\tmargin-left: auto;\n}\n.fwlive-watch-strip {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: stretch;\n\tjustify-content: flex-start;\n\tgap: 0;\n\tmin-height: 40px;\n\tpadding: 8px 0 10px;\n\tborder-bottom: 1px solid var(--border-color-medium);\n\tmargin-bottom: 10px;\n}\n.fwlive-watch-group {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tmin-height: 28px;\n\tpadding: 0 10px;\n\tborder-left: 1px solid var(--border-color-medium);\n\tflex-wrap: wrap;\n}\n.fwlive-watch-group:last-child {\n\tpadding-right: 0;\n}\n.fwlive-watch-group-label {\n\tmargin-right: 2px;\n\tcolor: var(--text-color-medium);\n\tfont-size: 0.72em;\n\tfont-weight: 700;\n\tletter-spacing: 0.08em;\n\ttext-transform: uppercase;\n\twhite-space: nowrap;\n}\n.fwlive-watch-seg {\n\tdisplay: inline-flex;\n\talign-items: stretch;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\toverflow: hidden;\n}\n.fwlive-watch-seg .fwlive-seg-btn {\n\tmargin: 0;\n\tborder: 0;\n\tborder-radius: 0;\n\tborder-right: 1px solid var(--border-color-medium);\n\tbackground: transparent;\n\tpadding: 4px 10px;\n\tfont-size: 0.88em;\n\tline-height: 1.25;\n\tmin-height: 28px;\n}\n.fwlive-watch-seg .fwlive-seg-btn:last-child {\n\tborder-right: 0;\n}\n.fwlive-watch-seg .fwlive-seg-btn[aria-pressed=\"true\"] {\n\tbackground: rgba(26, 111, 156, 0.12);\n\tbackground: color-mix(in srgb, var(--primary-color-high) 12%, transparent);\n\tcolor: var(--primary-color-high);\n\tfont-weight: 600;\n}\n.fwlive-watch-label { font-weight: 600; }\n.fwlive-watch-paused .fwlive-watch-label { color: var(--fwlive-paused-color); }\n.fwlive-map.fwlive-watch-paused .fwlive-title-status .fwlive-watch-label { color: var(--fwlive-paused-color); }\n.fwlive-dot {\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 50%;\n\tbackground: var(--text-color-low, var(--border-color-high));\n\tdisplay: inline-block;\n\tflex-shrink: 0;\n}\n.fwlive-dot.fwlive-dot-on {\n\tbackground: var(--fwlive-pass-color);\n\tbox-shadow: 0 0 0 3px color-mix(in srgb, var(--fwlive-pass-color) 22%, transparent);\n}\n.fwlive-btn-ghost {\n\tbackground: transparent;\n\tborder-color: var(--border-color-medium);\n}\n.fwlive-btn-quiet {\n\tbackground: transparent;\n\tborder-color: var(--border-color-medium);\n\tcolor: var(--text-color-medium);\n\tfont-weight: 500;\n}\n.fwlive-log-merged {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 10px;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\tbackground: var(--background-color-medium, var(--white-color-low, var(--background-color-high)));\n\tcolor: var(--text-color-high);\n\tfont-weight: 500;\n\tfont-size: 0.88em;\n\tline-height: 1.25;\n\tmin-height: 28px;\n\tcursor: pointer;\n}\n.fwlive-log-merged:hover {\n\tbackground: var(--background-color-low, var(--background-color-medium));\n}\n.fwlive-log-merged:disabled {\n\topacity: 0.65;\n\tcursor: default;\n}\n.fwlive-log-on-dot {\n\twidth: 6px;\n\theight: 6px;\n\tborder-radius: 50%;\n\tbackground: var(--fwlive-pass-color);\n\tflex-shrink: 0;\n}\n.fwlive-log-rate {\n\tcolor: var(--text-color-medium);\n\tfont-weight: 400;\n}\n.fwlive-display-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px 14px;\n\tmargin: 0 0 12px;\n\tpadding: 8px 12px;\n\tborder: 1px solid var(--border-color-medium);\n\tborder-radius: 3px;\n\tbackground: var(--background-color-high);\n}\n.fwlive-dLine truncated
|
||||
});
|
||||
@@ -533,6 +533,9 @@
|
||||
.fwlive-logging-notice {
|
||||
color: var(--fwlive-pass-color);
|
||||
}
|
||||
.fwlive-logging-notice-fail {
|
||||
color: var(--fwlive-deny-color);
|
||||
}
|
||||
.fwlive-filter-link {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* renderToolbar(host, state, callbacks) → void
|
||||
* host - #fwlive-logging-bar strip slot (cleared and rebuilt; element kept)
|
||||
* state - { loggingStatus, loggingBusy, loggingNotice }
|
||||
* state - { loggingStatus, loggingBusy, loggingNotice, loggingNoticeFail }
|
||||
* callbacks - { onEnable(), onDisable() }
|
||||
*
|
||||
* G Hybrid chrome: when WAN logging is on, one merged control carries status +
|
||||
@@ -88,9 +88,15 @@ function labelWithZoneCandidates(label, st) {
|
||||
return children;
|
||||
}
|
||||
|
||||
function loggingNoticeClass(state) {
|
||||
return state.loggingNoticeFail
|
||||
? 'fwlive-logging-notice fwlive-logging-notice-fail'
|
||||
: 'fwlive-logging-notice';
|
||||
}
|
||||
|
||||
function appendLoggingNotice(host, state) {
|
||||
if (!state.loggingNotice) return;
|
||||
host.appendChild(E('span', { 'class': 'fwlive-logging-notice' }, [state.loggingNotice]));
|
||||
host.appendChild(E('span', { 'class': loggingNoticeClass(state) }, [state.loggingNotice]));
|
||||
}
|
||||
|
||||
function appendBlockerStatus(host, blocker, st) {
|
||||
@@ -254,7 +260,7 @@ function buildEmptyStateNodes(state, callbacks) {
|
||||
|
||||
if (state.loggingNotice) {
|
||||
nodes.push(
|
||||
E('p', { 'class': 'fwlive-logging-notice' }, [
|
||||
E('p', { 'class': loggingNoticeClass(state) }, [
|
||||
state.loggingNotice,
|
||||
' ',
|
||||
links.firewallZonesLink()
|
||||
@@ -287,14 +293,12 @@ function buildEmptyStateNodes(state, callbacks) {
|
||||
nodes.push(
|
||||
E('p', {}, [
|
||||
_(
|
||||
'Kernel netfilter log modules are missing. Install kmod-nf-log-ipv4 and kmod-nf-log-ipv6 (or kmod-nf-log / kmod-nf-log6), then reload the firewall.'
|
||||
'Kernel netfilter log modules are missing. Install kmod-nf-log and kmod-nf-log6, then reload the firewall.'
|
||||
)
|
||||
])
|
||||
);
|
||||
nodes.push(
|
||||
E('p', {}, [
|
||||
E('code', {}, ['opkg update && opkg install kmod-nf-log-ipv4 kmod-nf-log-ipv6'])
|
||||
])
|
||||
E('p', {}, [E('code', {}, ['opkg update && opkg install kmod-nf-log kmod-nf-log6'])])
|
||||
);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@@ -177,6 +177,7 @@ return view.extend({
|
||||
loggingStatusReadGeneration: 0,
|
||||
loggingBusy: false,
|
||||
loggingNotice: '',
|
||||
loggingNoticeFail: false,
|
||||
_loggingNoticeFromToggle: false,
|
||||
/* Session-only dismiss of first-run consent (Not now without checkbox). */
|
||||
consentDismissedSession: false,
|
||||
@@ -704,10 +705,13 @@ return view.extend({
|
||||
/* Bounds / mktemp failures are reply.error — same idea as poll. */
|
||||
this.lastRulesError = (res && res.error) || null;
|
||||
if (this.lastRulesError) console.warn('fwlive rules map error:', this.lastRulesError);
|
||||
this.refreshBufferedRuleLabels();
|
||||
} catch (_e) {
|
||||
if (!this.isCurrentPollEpoch(epoch)) return;
|
||||
this.rulesMap = {};
|
||||
this.firewallBackend = 'nft';
|
||||
if (!(this.rulesMap && Object.keys(this.rulesMap).length)) {
|
||||
this.rulesMap = {};
|
||||
this.firewallBackend = 'nft';
|
||||
}
|
||||
this.lastRulesError = 'rules_unavailable';
|
||||
}
|
||||
this.updateBackendUi();
|
||||
@@ -762,7 +766,10 @@ return view.extend({
|
||||
)
|
||||
return;
|
||||
this.loggingStatus = status;
|
||||
if (!this._loggingNoticeFromToggle) this.loggingNotice = '';
|
||||
if (!this._loggingNoticeFromToggle) {
|
||||
this.loggingNotice = '';
|
||||
this.loggingNoticeFail = false;
|
||||
}
|
||||
this.weakDevice = !!(this.loggingStatus && this.loggingStatus.weak_device === true);
|
||||
} catch (_e) {
|
||||
if (
|
||||
@@ -771,10 +778,12 @@ return view.extend({
|
||||
)
|
||||
return;
|
||||
/* Keep last-known toolbar; unknown until the first successful fetch. */
|
||||
if (!this.loggingNotice)
|
||||
if (!this.loggingNotice) {
|
||||
this.loggingNotice = this.loggingStatus
|
||||
? _('Could not refresh logging status; showing the last known state.')
|
||||
: _('Could not load logging status.');
|
||||
this.loggingNoticeFail = true;
|
||||
}
|
||||
}
|
||||
this.updateBackendUi();
|
||||
this.updateLoggingToolbarUi();
|
||||
@@ -791,6 +800,7 @@ return view.extend({
|
||||
this.loggingStatusReadGeneration++;
|
||||
this.loggingBusy = true;
|
||||
this.loggingNotice = '';
|
||||
this.loggingNoticeFail = false;
|
||||
this._loggingNoticeFromToggle = false;
|
||||
opts.initialUi();
|
||||
|
||||
@@ -798,12 +808,14 @@ return view.extend({
|
||||
const res = await opts.call();
|
||||
if (!res || !res.ok) {
|
||||
this.loggingNotice = opts.failureNotice(res);
|
||||
this.loggingNoticeFail = true;
|
||||
this._loggingNoticeFromToggle = true;
|
||||
await this.loadLoggingStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
this.loggingNotice = opts.successNotice(res);
|
||||
this.loggingNoticeFail = false;
|
||||
this._loggingNoticeFromToggle = !!this.loggingNotice;
|
||||
if (opts.onSuccess) opts.onSuccess(res);
|
||||
if (this.loggingStatus && typeof opts.wanLog === 'boolean')
|
||||
@@ -813,6 +825,7 @@ return view.extend({
|
||||
await this.loadLoggingStatus();
|
||||
} catch (_e) {
|
||||
this.loggingNotice = opts.catchNotice();
|
||||
this.loggingNoticeFail = true;
|
||||
this._loggingNoticeFromToggle = true;
|
||||
await this.loadLoggingStatus();
|
||||
} finally {
|
||||
@@ -847,6 +860,16 @@ return view.extend({
|
||||
return _('Could not snapshot the current logging state.');
|
||||
if (res && res.error === 'firewall_reload_failed')
|
||||
return _('The firewall did not reload; saved and live logging may differ.');
|
||||
if (res && res.error === 'uci_set_failed')
|
||||
return _('Could not write the WAN zone log option.');
|
||||
if (res && res.error === 'uci_delete_failed')
|
||||
return _('Could not clear the WAN zone log option.');
|
||||
if (res && res.error === 'uci_commit_failed')
|
||||
return _('Could not save the firewall configuration.');
|
||||
if (res && res.error === 'firewall_commit_raced')
|
||||
return _(
|
||||
'Another change overwrote WAN logging after it was saved; check the current state.'
|
||||
);
|
||||
return _('Could not enable logging.');
|
||||
},
|
||||
successNotice: (res) =>
|
||||
@@ -876,6 +899,16 @@ return view.extend({
|
||||
return _('Could not acquire the logging lock.');
|
||||
if (res && res.error === 'firewall_reload_failed')
|
||||
return _('The firewall did not reload; saved and live logging may differ.');
|
||||
if (res && res.error === 'uci_set_failed')
|
||||
return _('Could not write the WAN zone log option.');
|
||||
if (res && res.error === 'uci_delete_failed')
|
||||
return _('Could not clear the WAN zone log option.');
|
||||
if (res && res.error === 'uci_commit_failed')
|
||||
return _('Could not save the firewall configuration.');
|
||||
if (res && res.error === 'firewall_commit_raced')
|
||||
return _(
|
||||
'Another change overwrote WAN logging after it was saved; check the current state.'
|
||||
);
|
||||
return _('Could not disable logging.');
|
||||
},
|
||||
successNotice: (res) => (res.changed ? _('WAN drop/reject logging is off.') : ''),
|
||||
@@ -905,6 +938,7 @@ return view.extend({
|
||||
loggingStatus: this.loggingStatus,
|
||||
loggingBusy: this.loggingBusy,
|
||||
loggingNotice: this.loggingNotice,
|
||||
loggingNoticeFail: !!this.loggingNoticeFail,
|
||||
showConsent: this.shouldShowLoggingConsent()
|
||||
};
|
||||
},
|
||||
@@ -924,6 +958,7 @@ return view.extend({
|
||||
candidates,
|
||||
this.loggingBusy ? '1' : '0',
|
||||
this.loggingNotice || '',
|
||||
this.loggingNoticeFail ? 'f1' : 'f0',
|
||||
this.shouldShowLoggingConsent() ? 'c1' : 'c0'
|
||||
].join('|');
|
||||
},
|
||||
@@ -1145,6 +1180,9 @@ return view.extend({
|
||||
/* Recovery RPCs can outlive the poll epoch; don't repaint stale views. */
|
||||
if (epoch !== this.currentPollEpoch() || this.viewDisposed) return;
|
||||
this.refreshBufferedRuleLabels();
|
||||
} else if (this.lastRulesError === 'rules_unavailable') {
|
||||
await this.loadRulesMap(epoch);
|
||||
if (epoch !== this.currentPollEpoch() || this.viewDisposed) return;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1505,12 +1543,11 @@ return view.extend({
|
||||
},
|
||||
|
||||
scheduleResolvePaint() {
|
||||
this.resolvePaintPending = true;
|
||||
if (this.tablePaused) {
|
||||
this.resolvePaintPending = true;
|
||||
this.updateStatus();
|
||||
return;
|
||||
}
|
||||
this.resolvePaintPending = false;
|
||||
this.scheduleRenderRows(true);
|
||||
},
|
||||
|
||||
|
||||
Reference in new issue
Block a user