@ezuikit/player-theme 3.1.8-beta.1 → 3.1.8-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constant.js +2 -2
- package/dist/index.cjs +159 -53
- package/dist/index.esm.js +159 -53
- package/dist/index.umd.js +227 -121
- package/dist/style.css +1 -1
- package/dist/style.js +2 -2
- package/dist/types/index.d.ts +31 -2
- package/package.json +2 -2
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* @ezuikit/player-theme v3.1.8-beta.
|
|
3
|
-
* Copyright (c) 2026-
|
|
2
|
+
* @ezuikit/player-theme v3.1.8-beta.3
|
|
3
|
+
* Copyright (c) 2026-10-10 18:47:13 Ezviz-OpenBiz
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
import EventEmitter from 'eventemitter3';
|
|
@@ -443,20 +443,22 @@ function _set_prototype_of$z(o, p) {
|
|
|
443
443
|
/**
|
|
444
444
|
* 销毁控件
|
|
445
445
|
*/ _proto.destroy = function destroy() {
|
|
446
|
-
var _this___options, _this_$container_remove, _this_$
|
|
446
|
+
var _this___options, _this_$container, _this_$container_remove, _this_$container1;
|
|
447
447
|
if (this._camelCaseName) {
|
|
448
448
|
this.emit("Control." + this._camelCaseName + "Destroy");
|
|
449
449
|
}
|
|
450
|
-
|
|
450
|
+
// 用可选链与下面的 click 解绑保持一致:destroy() 之后 $container 会被置空,
|
|
451
|
+
// 重复 destroy(例如主题卸载控件后调用方又手动销毁一次)不应抛错
|
|
452
|
+
if (((_this___options = this.__options) == null ? void 0 : _this___options.controlType) !== 'block') (_this_$container = this.$container) == null ? void 0 : _this_$container.removeEventListener('dblclick', this._onDBlClick);
|
|
451
453
|
// 移除 click 监听
|
|
452
454
|
if (this._onClickHandler) {
|
|
453
|
-
var _this_$
|
|
454
|
-
(_this_$
|
|
455
|
+
var _this_$container2;
|
|
456
|
+
(_this_$container2 = this.$container) == null ? void 0 : _this_$container2.removeEventListener('click', this._onClickHandler);
|
|
455
457
|
this._onClickHandler = null;
|
|
456
458
|
}
|
|
457
459
|
this._active = false;
|
|
458
460
|
this.removeAllListeners();
|
|
459
|
-
(_this_$
|
|
461
|
+
(_this_$container1 = this.$container) == null ? void 0 : (_this_$container_remove = _this_$container1.remove) == null ? void 0 : _this_$container_remove.call(_this_$container1);
|
|
460
462
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
461
463
|
this.$container = null;
|
|
462
464
|
};
|
|
@@ -566,6 +568,45 @@ function _set_prototype_of$z(o, p) {
|
|
|
566
568
|
* ```
|
|
567
569
|
*/ Control.supportedPlayTypes = [].concat(PLAY_TYPES);
|
|
568
570
|
|
|
571
|
+
/**
|
|
572
|
+
* HTML 转义
|
|
573
|
+
*
|
|
574
|
+
* 控件大量使用「模板字符串拼 HTML + innerHTML」的写法,只要拼进去的值来自
|
|
575
|
+
* 播放地址、接口返回或多语言配置,就存在注入风险。能改用 `textContent` /
|
|
576
|
+
* `createElement` 的地方应优先改用 DOM API;确实需要拼字符串时,所有外部
|
|
577
|
+
* 数据都必须先过这个函数。
|
|
578
|
+
*
|
|
579
|
+
* 同时覆盖两种语境:
|
|
580
|
+
* - 文本内容:`<span>${escapeHtml(v)}</span>`
|
|
581
|
+
* - 属性值:`<span title="${escapeHtml(v)}">`
|
|
582
|
+
*
|
|
583
|
+
* @remarks 用一次 `replace` 扫描完成,不存在「先转 `&` 再转其他」导致的二次转义。
|
|
584
|
+
*/ /** 需要转义的字符与对应实体 */ var HTML_ESCAPE_MAP = {
|
|
585
|
+
'&': '&',
|
|
586
|
+
'<': '<',
|
|
587
|
+
'>': '>',
|
|
588
|
+
'"': '"',
|
|
589
|
+
"'": '''
|
|
590
|
+
};
|
|
591
|
+
/**
|
|
592
|
+
* 转义 HTML 中有特殊含义的字符
|
|
593
|
+
*
|
|
594
|
+
* @param value - 任意值,`null` / `undefined` 归一成空字符串
|
|
595
|
+
* @returns 可安全拼进 HTML 文本或双引号属性值的字符串
|
|
596
|
+
* @since 3.1.8
|
|
597
|
+
* @example
|
|
598
|
+
* ```ts
|
|
599
|
+
* escapeHtml('x" onerror="alert(1)'); // 'x" onerror="alert(1)'
|
|
600
|
+
* escapeHtml('<img src=x>'); // '<img src=x>'
|
|
601
|
+
* escapeHtml(undefined); // ''
|
|
602
|
+
* ```
|
|
603
|
+
*/ function escapeHtml(value) {
|
|
604
|
+
if (value === null || value === undefined) return '';
|
|
605
|
+
return String(value).replace(/[&<>"']/g, function(char) {
|
|
606
|
+
return HTML_ESCAPE_MAP[char];
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
569
610
|
function _extends$y() {
|
|
570
611
|
_extends$y = Object.assign || function assign(target) {
|
|
571
612
|
for(var i = 1; i < arguments.length; i++){
|
|
@@ -618,14 +659,17 @@ var LOADING_DEFAULT_OPTIONS = {};
|
|
|
618
659
|
var _proto = Loading.prototype;
|
|
619
660
|
_proto._html = function _html() {
|
|
620
661
|
if (typeof this._options.render === 'function') {
|
|
662
|
+
// 自定义节点安全由开发者自己保障
|
|
621
663
|
this.$container.innerHTML = this._options.render();
|
|
622
664
|
} else {
|
|
623
665
|
var _this_locale;
|
|
624
|
-
this.$container.innerHTML = '\n <span class="' + PREFIX_CLASS + "-loading-dot " + PREFIX_CLASS + '-loading-dot-load">\n <i class="' + PREFIX_CLASS + '-loading-dot-item"></i>\n <i class="' + PREFIX_CLASS + '-loading-dot-item"></i>\n <i class="' + PREFIX_CLASS + '-loading-dot-item"></i>\n <i class="' + PREFIX_CLASS + '-loading-dot-item"></i>\n </span>\n <div class="' + PREFIX_CLASS + '-loading-text">' + (((_this_locale = this.locale) == null ? void 0 : _this_locale.LOADING) || 'loading...') + "</div>\n ";
|
|
666
|
+
this.$container.innerHTML = '\n <span class="' + PREFIX_CLASS + "-loading-dot " + PREFIX_CLASS + '-loading-dot-load">\n <i class="' + PREFIX_CLASS + '-loading-dot-item"></i>\n <i class="' + PREFIX_CLASS + '-loading-dot-item"></i>\n <i class="' + PREFIX_CLASS + '-loading-dot-item"></i>\n <i class="' + PREFIX_CLASS + '-loading-dot-item"></i>\n </span>\n <div class="' + PREFIX_CLASS + '-loading-text">' + escapeHtml(((_this_locale = this.locale) == null ? void 0 : _this_locale.LOADING) || 'loading...') + "</div>\n ";
|
|
625
667
|
}
|
|
626
668
|
};
|
|
627
669
|
/**
|
|
628
670
|
* 动画展示
|
|
671
|
+
*
|
|
672
|
+
* @remarks `html` 会原样写入 `innerHTML`,**不做转义**,仅接受可信内容。
|
|
629
673
|
* @param html 自定义动画内容, 如果不存在则使用默认动画
|
|
630
674
|
*/ _proto.show = function show(html) {
|
|
631
675
|
if (html) this.$container.innerHTML = html;
|
|
@@ -714,16 +758,21 @@ var POSTER_OPTIONS = {
|
|
|
714
758
|
* 设置封面 这里不对 poster 进行缓存,如果有值优先使用,如果没有值优先使用 初始化传入的值
|
|
715
759
|
* @param {string} poster 封面地址或 base64 数据
|
|
716
760
|
*/ _proto.setPoster = function setPoster(poster) {
|
|
717
|
-
var // eslint-disable-next-line @typescript-eslint/unbound-method
|
|
718
|
-
// prettier-ignore
|
|
719
|
-
_this_$container_querySelector;
|
|
720
761
|
poster = poster != null ? poster : this._options.poster;
|
|
721
|
-
|
|
722
|
-
|
|
762
|
+
// 空值一律清空。原先只判 `=== ''`,poster 为 undefined 时会渲染出
|
|
763
|
+
// `<img src="undefined">`,浏览器会去请求 ./undefined 再触发 error 回调
|
|
764
|
+
if (!poster) {
|
|
765
|
+
this.$container.replaceChildren();
|
|
723
766
|
return;
|
|
724
767
|
}
|
|
725
|
-
|
|
726
|
-
|
|
768
|
+
// 用 DOM API 而不是拼 innerHTML:封面地址可能来自远程模板接口或业务动态传入,
|
|
769
|
+
// 拼进 src="${poster}" 时 `x" onerror="...` 能闭合属性挂上事件处理器
|
|
770
|
+
var $img = document.createElement('img');
|
|
771
|
+
$img.className = "" + PREFIX_CLASS + "-poster-img";
|
|
772
|
+
$img.src = poster;
|
|
773
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
774
|
+
$img.addEventListener('error', this._imgLoadErrorEvent);
|
|
775
|
+
this.$container.replaceChildren($img);
|
|
727
776
|
};
|
|
728
777
|
/**
|
|
729
778
|
* 展示封面 这里不对 poster 进行缓存, 如果有值优先使用, 如果没有值优先使用 初始化传入的值
|
|
@@ -817,7 +866,9 @@ var Icons = {
|
|
|
817
866
|
var attrStr = '';
|
|
818
867
|
if (attr) {
|
|
819
868
|
Object.keys(attr).forEach(function(key) {
|
|
820
|
-
|
|
869
|
+
// 属性值必须转义:所有控件的 title 都来自 options.locales,
|
|
870
|
+
// 不转义时 `x" onmouseover="alert(1)` 这样的文案可以闭合属性并挂上事件
|
|
871
|
+
if (!(attr[key] === undefined || attr[key] === null)) attrStr += key + '="' + escapeHtml(attr[key]) + '"';
|
|
821
872
|
});
|
|
822
873
|
}
|
|
823
874
|
return '<span class="' + PREFIX_CLASS + "-icon " + PREFIX_CLASS + "-icon-" + type + '" ' + attrStr + ">" + svg + "</span>";
|
|
@@ -1059,7 +1110,7 @@ var MESSAGE_DEFAULT_OPTIONS = {};
|
|
|
1059
1110
|
* @param {number=} duration 认自动关闭延时,单位秒, 默认 0 不关闭, 需手动 调用 hide()
|
|
1060
1111
|
*/ _proto.error = function error(msg, duration) {
|
|
1061
1112
|
if (duration === void 0) duration = 0;
|
|
1062
|
-
this._show(this._getIcon('error') + '<div class="' + PREFIX_CLASS + '-message-msg">' + (msg || '') + "</div>", duration, 'error');
|
|
1113
|
+
this._show(this._getIcon('error') + '<div class="' + PREFIX_CLASS + '-message-msg">' + (escapeHtml(msg) || '') + "</div>", duration, 'error');
|
|
1063
1114
|
};
|
|
1064
1115
|
_proto._toast = function _toast(msg, type, duration) {
|
|
1065
1116
|
var _this = this;
|
|
@@ -1072,7 +1123,8 @@ var MESSAGE_DEFAULT_OPTIONS = {};
|
|
|
1072
1123
|
this._$toast = document.createElement('div');
|
|
1073
1124
|
this._$toast.classList.add("" + PREFIX_CLASS + "-toast");
|
|
1074
1125
|
}
|
|
1075
|
-
|
|
1126
|
+
// msg 是 EVENTS.message 的载荷,内核与接口的错误信息都走这个通道,必须转义
|
|
1127
|
+
this._$toast.innerHTML = '<div class="' + PREFIX_CLASS + '-toast-content">' + this._getIcon(type) + '<span class="' + PREFIX_CLASS + "-toast-msg " + PREFIX_CLASS + "-toast-" + type + '">' + escapeHtml(msg) + "</span></div>";
|
|
1076
1128
|
this.options.rootContainer.appendChild(this._$toast);
|
|
1077
1129
|
if (duration > 0) {
|
|
1078
1130
|
this._toastTimer = setTimeout(function() {
|
|
@@ -1104,7 +1156,7 @@ var MESSAGE_DEFAULT_OPTIONS = {};
|
|
|
1104
1156
|
//
|
|
1105
1157
|
this.$container.innerHTML = this.options.render(msg, duration, type);
|
|
1106
1158
|
} else {
|
|
1107
|
-
this.$container.innerHTML = '<div class="' + PREFIX_CLASS + "-message-content " + PREFIX_CLASS + "-message-" + type + '">' +
|
|
1159
|
+
this.$container.innerHTML = '<div class="' + PREFIX_CLASS + "-message-content " + PREFIX_CLASS + "-message-" + type + '">' + msg + "</div>";
|
|
1108
1160
|
}
|
|
1109
1161
|
//
|
|
1110
1162
|
this.$container.style.display = 'flex';
|
|
@@ -2011,9 +2063,9 @@ var VOLUME_DEFAULT_OPTIONS = {
|
|
|
2011
2063
|
// 这里不要用 click 事件,因为拖动音量大小时鼠标移动到图标上会触发 click
|
|
2012
2064
|
// prettier-ignore
|
|
2013
2065
|
delegate(this.$container, "." + PREFIX_CLASS + "-control-volume", "mousedown", function() {
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2066
|
+
// 禁用判断交给 _toggleMute 里的 this.disabled(状态是权威来源,
|
|
2067
|
+
// class 只是它的呈现),避免两处各判一遍
|
|
2068
|
+
_this._toggleMute();
|
|
2017
2069
|
});
|
|
2018
2070
|
};
|
|
2019
2071
|
_create_class$6(Volume, [
|
|
@@ -5385,11 +5437,14 @@ function _ts_generator$6(thisArg, body) {
|
|
|
5385
5437
|
*/ function getThemeDataByTemplate(theme, id) {
|
|
5386
5438
|
return _async_to_generator$6(function() {
|
|
5387
5439
|
var _theme_options_token_httpToken, _theme_options_token, // 中止上一个在途请求,并为本次请求创建可中止的信号(destroy 时会 abort)
|
|
5388
|
-
_theme__templateAbortController, url, controller;
|
|
5440
|
+
_theme__templateAbortController, accessToken, url, controller;
|
|
5389
5441
|
return _ts_generator$6(this, function(_state) {
|
|
5390
5442
|
switch(_state.label){
|
|
5391
5443
|
case 0:
|
|
5392
|
-
|
|
5444
|
+
accessToken = theme.options.accessToken || ((_theme_options_token = theme.options.token) == null ? void 0 : (_theme_options_token_httpToken = _theme_options_token.httpToken) == null ? void 0 : _theme_options_token_httpToken.url);
|
|
5445
|
+
// 查询参数逐个 encodeURIComponent,防止 `&` `#` `=` 等字符注入额外参数或截断 URL(SECURITY_AUDIT M1)
|
|
5446
|
+
// 不用 `new URL()`:env.domain 允许为空(同源相对路径)或带路径前缀,URL 构造会抛错或丢掉前缀
|
|
5447
|
+
url = theme.options.env.domain + "/api/service/media/template/getDetail?accessToken=" + encodeURIComponent(String(accessToken)) + "&id=" + encodeURIComponent(String(id));
|
|
5393
5448
|
(_theme__templateAbortController = theme._templateAbortController) == null ? void 0 : _theme__templateAbortController.abort();
|
|
5394
5449
|
controller = new AbortController();
|
|
5395
5450
|
theme._templateAbortController = controller;
|
|
@@ -5717,7 +5772,9 @@ function _filterLeftRightControls(btnList) {
|
|
|
5717
5772
|
];
|
|
5718
5773
|
// 渲染主题模板
|
|
5719
5774
|
themeData = TEMPLATES[data];
|
|
5720
|
-
|
|
5775
|
+
// 修复:此前判的是 `!data`,而这个分支里 data 必然是非空字符串,告警永远不会发出,
|
|
5776
|
+
// 传了不存在的模板名只会静默返回 undefined。应当判查表结果。
|
|
5777
|
+
if (!themeData) {
|
|
5721
5778
|
(_theme_logger = theme.logger) == null ? void 0 : _theme_logger.warn("Theme template " + data + " is not exist!");
|
|
5722
5779
|
themeData = null;
|
|
5723
5780
|
}
|
|
@@ -6408,7 +6465,9 @@ function _set_prototype_of$k(o, p) {
|
|
|
6408
6465
|
this._ptzControl.updateOptions(options);
|
|
6409
6466
|
}
|
|
6410
6467
|
if (this._ptzControl1) {
|
|
6411
|
-
this._ptzControl
|
|
6468
|
+
// 修复:此前误写成 this._ptzControl,移动端扩展区域的云台拿不到新凭据,
|
|
6469
|
+
// 换 accessToken 或切设备后移动端云台会继续用旧值请求
|
|
6470
|
+
this._ptzControl1.updateOptions(options);
|
|
6412
6471
|
}
|
|
6413
6472
|
};
|
|
6414
6473
|
_proto._onSpeedChange = function _onSpeedChange(speed) {
|
|
@@ -7630,7 +7689,13 @@ function _set_prototype_of$e(o, p) {
|
|
|
7630
7689
|
controlType: 'button',
|
|
7631
7690
|
classNameSuffix: 'rec-dropdown'
|
|
7632
7691
|
})) || this;
|
|
7633
|
-
_this._options =
|
|
7692
|
+
_this._options = Object.assign({
|
|
7693
|
+
list: [
|
|
7694
|
+
'rec',
|
|
7695
|
+
'cloudRec',
|
|
7696
|
+
'cloudRecord'
|
|
7697
|
+
]
|
|
7698
|
+
}, options || {});
|
|
7634
7699
|
// H5 端不展示直播/回放切换按钮
|
|
7635
7700
|
if (Utils.isMobile) {
|
|
7636
7701
|
_this.$container.style.display = 'none';
|
|
@@ -7663,7 +7728,8 @@ function _set_prototype_of$e(o, p) {
|
|
|
7663
7728
|
}
|
|
7664
7729
|
};
|
|
7665
7730
|
_proto._render = function _render() {
|
|
7666
|
-
var _this_locale;
|
|
7731
|
+
var _this__options_list, _this_locale;
|
|
7732
|
+
if (((_this__options_list = this._options.list) == null ? void 0 : _this__options_list.length) === 0) ;
|
|
7667
7733
|
this.$container.innerHTML = IconComponents.recDropdown({
|
|
7668
7734
|
title: ((_this_locale = this.locale) == null ? void 0 : _this_locale.BTN_REC_DROPDOWN) || '回放'
|
|
7669
7735
|
});
|
|
@@ -7686,8 +7752,8 @@ function _set_prototype_of$e(o, p) {
|
|
|
7686
7752
|
// 打开时按控件在视口中的位置决定对齐方式。
|
|
7687
7753
|
// 此时 picker 已把 $wrapperContent 设为 inline-flex(可测量宽度),
|
|
7688
7754
|
// 而它内部的定位计算还在 requestAnimationFrame 里,改 placement 来得及生效。
|
|
7689
|
-
//
|
|
7690
|
-
if (open
|
|
7755
|
+
// 移动端不适用的判断放在 _adjustPlacement 内部,避免两处各管一半
|
|
7756
|
+
if (open) _this._adjustPlacement();
|
|
7691
7757
|
}
|
|
7692
7758
|
});
|
|
7693
7759
|
this._picker.innerHTML(this._getPanelHTML());
|
|
@@ -7733,7 +7799,7 @@ function _set_prototype_of$e(o, p) {
|
|
|
7733
7799
|
var cloudRecLabel = ((_this_locale = this.locale) == null ? void 0 : _this_locale.REC_DROPDOWN_CLOUD_REC) || '云存储';
|
|
7734
7800
|
var cloudRecordLabel = ((_this_locale1 = this.locale) == null ? void 0 : _this_locale1.REC_DROPDOWN_CLOUD_RECORD) || '云录制';
|
|
7735
7801
|
var localRecLabel = ((_this_locale2 = this.locale) == null ? void 0 : _this_locale2.REC_DROPDOWN_LOCAL_REC) || '本地回放';
|
|
7736
|
-
return '<div class="' + PREFIX_CLASS + '-rec-dropdown-panel">\n <ul class="' + PREFIX_CLASS + '-rec-dropdown-list">\n <li class="' + PREFIX_CLASS + '-rec-dropdown-item" data-type="cloudRec">\n <span>' + cloudRecLabel +
|
|
7802
|
+
return '<div class="' + PREFIX_CLASS + '-rec-dropdown-panel">\n <ul class="' + PREFIX_CLASS + '-rec-dropdown-list">\n ' + (this._options.list.includes('cloudRec') ? '<li class="' + PREFIX_CLASS + '-rec-dropdown-item" data-type="cloudRec">\n <span>' + cloudRecLabel + "</span>\n </li>" : '') + "\n " + (this._options.list.includes('cloudRecord') ? '<li class="' + PREFIX_CLASS + '-rec-dropdown-item" data-type="cloudRecord">\n <span>' + cloudRecordLabel + "</span>\n </li>" : '') + "\n " + (this._options.list.includes('rec') ? ' <li class="' + PREFIX_CLASS + '-rec-dropdown-item" data-type="rec">\n <span>' + localRecLabel + "</span>\n </li>" : '') + "\n </ul>\n </div>";
|
|
7737
7803
|
};
|
|
7738
7804
|
_proto._bindPanelEvents = function _bindPanelEvents() {
|
|
7739
7805
|
var _this = this;
|
|
@@ -7754,6 +7820,9 @@ function _set_prototype_of$e(o, p) {
|
|
|
7754
7820
|
};
|
|
7755
7821
|
_proto._activeOption = function _activeOption(type) {
|
|
7756
7822
|
var _this__picker;
|
|
7823
|
+
if (!this._options.list.includes(type)) {
|
|
7824
|
+
return;
|
|
7825
|
+
}
|
|
7757
7826
|
if ((_this__picker = this._picker) == null ? void 0 : _this__picker.$body) {
|
|
7758
7827
|
var items = this._picker.$body.querySelectorAll("." + PREFIX_CLASS + "-rec-dropdown-item");
|
|
7759
7828
|
items.forEach(function(item) {
|
|
@@ -8078,8 +8147,9 @@ var SELECT_DEFAULT_OPTIONS = {
|
|
|
8078
8147
|
label: 'label',
|
|
8079
8148
|
value: 'value'
|
|
8080
8149
|
},
|
|
8150
|
+
// label 可能来自内核下发的列表,内置实现必须转义
|
|
8081
8151
|
renderLabel: function renderLabel(label) {
|
|
8082
|
-
return "<span>" + (label
|
|
8152
|
+
return "<span>" + escapeHtml(label) + "</span>";
|
|
8083
8153
|
},
|
|
8084
8154
|
onChange: function onChange() {},
|
|
8085
8155
|
onOpenChange: function onOpenChange() {}
|
|
@@ -8194,9 +8264,11 @@ var SELECT_DEFAULT_OPTIONS = {
|
|
|
8194
8264
|
var _this__options_fieldNames, _this__options_fieldNames1, _this_locale, _this__picker;
|
|
8195
8265
|
var labelKey = (_ref = (_this__options_fieldNames = this._options.fieldNames) == null ? void 0 : _this__options_fieldNames.label) != null ? _ref : 'label';
|
|
8196
8266
|
var valueKey = (_ref1 = (_this__options_fieldNames1 = this._options.fieldNames) == null ? void 0 : _this__options_fieldNames1.value) != null ? _ref1 : 'value';
|
|
8197
|
-
(_this__picker = this._picker) == null ? void 0 : _this__picker.innerHTML('<div class="' + PREFIX_CLASS + '-select-panel">\n <ul class="' + PREFIX_CLASS + '-select-list">\n ' + list.map(
|
|
8198
|
-
|
|
8199
|
-
|
|
8267
|
+
(_this__picker = this._picker) == null ? void 0 : _this__picker.innerHTML('<div class="' + PREFIX_CLASS + '-select-panel">\n <ul class="' + PREFIX_CLASS + '-select-list">\n ' + list.map(// 列表可能来自内核下发(如 setVideoLevelList 的清晰度列表),
|
|
8268
|
+
// data-value 与标签文本都要转义
|
|
8269
|
+
function(item) {
|
|
8270
|
+
return '\n <li class="' + PREFIX_CLASS + "-select-option " + (+item[valueKey] === _this.value ? "" + PREFIX_CLASS + "-active" : '') + '" data-value="' + escapeHtml(item[valueKey]) + '">\n <span>' + escapeHtml(item[labelKey]) + "</span>\n </li>\n ";
|
|
8271
|
+
}).join('') + "\n </ul>\n " + (Utils.isMobile ? '<div class="' + PREFIX_CLASS + '-select-cancel">\n <span>' + escapeHtml(((_this_locale = this.locale) == null ? void 0 : _this_locale.cancel) || '取消') + "</span>\n </div>" : '') + "\n " + (Utils.isMobile ? '<span class="' + PREFIX_CLASS + '-select-close">' + IconComponents.close() + "</span>" : '') + "\n <div>");
|
|
8200
8272
|
this.list = list;
|
|
8201
8273
|
this._activeOption();
|
|
8202
8274
|
} else if ((list == null ? void 0 : list.length) === 0) {
|
|
@@ -8428,15 +8500,16 @@ function __filter(list, locale) {
|
|
|
8428
8500
|
classNameSuffix: 'definition',
|
|
8429
8501
|
renderLabel: function renderLabel(label, item, list) {
|
|
8430
8502
|
var _list_;
|
|
8503
|
+
// 文案来自 options.locales,name / label 来自内核下发的清晰度列表,都要转义
|
|
8431
8504
|
if ((item == null ? void 0 : item.level) === 'auto') {
|
|
8432
8505
|
var _options_locales_options_language;
|
|
8433
8506
|
var realItem = list.find(function(it) {
|
|
8434
8507
|
return it.level === _assert_this_initialized$1(_this)._level;
|
|
8435
8508
|
});
|
|
8436
|
-
return "<span>" + (options == null ? void 0 : (_options_locales_options_language = options.locales[options.language]) == null ? void 0 : _options_locales_options_language.VIDEO_LEVEL_AUTO) + "(" + ((realItem == null ? void 0 : realItem.name) || '') + ")</span>";
|
|
8509
|
+
return "<span>" + escapeHtml(options == null ? void 0 : (_options_locales_options_language = options.locales[options.language]) == null ? void 0 : _options_locales_options_language.VIDEO_LEVEL_AUTO) + "(" + escapeHtml((realItem == null ? void 0 : realItem.name) || '') + ")</span>";
|
|
8437
8510
|
}
|
|
8438
8511
|
// 如果 label 不存在,则不显示label,直接显示list的第一个label, 一般自定义清晰度列表可能会出现
|
|
8439
|
-
return "<span>" + (label || ((_list_ = list[0]) == null ? void 0 : _list_.name) || '') + "</span>";
|
|
8512
|
+
return "<span>" + escapeHtml(label || ((_list_ = list[0]) == null ? void 0 : _list_.name) || '') + "</span>";
|
|
8440
8513
|
},
|
|
8441
8514
|
onChange: function onChange(value, item) {
|
|
8442
8515
|
var _options_onChange;
|
|
@@ -8466,7 +8539,8 @@ function __filter(list, locale) {
|
|
|
8466
8539
|
var realItem = _this.list.find(function(it) {
|
|
8467
8540
|
return it.level === _this._level;
|
|
8468
8541
|
});
|
|
8469
|
-
|
|
8542
|
+
// 文案来自 options.locales,realItem.name 来自内核下发的清晰度列表,两者都要转义
|
|
8543
|
+
_this.$container.querySelector("." + PREFIX_CLASS + "-select-btn").innerHTML = "\n <span>" + escapeHtml(options == null ? void 0 : (_options_locales_options_language = options.locales[options.language]) == null ? void 0 : _options_locales_options_language.VIDEO_LEVEL_AUTO) + "(" + escapeHtml((realItem == null ? void 0 : realItem.name) || '') + ")</span>\n ";
|
|
8470
8544
|
} else {
|
|
8471
8545
|
if (_this.value !== _this._level + '') _this.value = _this._level + '';
|
|
8472
8546
|
}
|
|
@@ -8695,7 +8769,8 @@ function _set_prototype_of$8(o, p) {
|
|
|
8695
8769
|
var isMobile1 = isMobile();
|
|
8696
8770
|
if (isMobile1) {
|
|
8697
8771
|
var _this_locale;
|
|
8698
|
-
|
|
8772
|
+
// title 来自 options.locales,必须转义后再拼进属性
|
|
8773
|
+
this.$container.innerHTML = '\n <span class="' + PREFIX_CLASS + '-mobile-date-filter" title="' + escapeHtml(((_this_locale = this.locale) == null ? void 0 : _this_locale.BTN_CALENDAR) || '') + '">\n <span class="' + PREFIX_CLASS + '-mobile-date-filter-value">' + escapeHtml(this._getDateStr()) + "</span>\n " + IconComponents.filter() + "\n <span>";
|
|
8699
8774
|
} else {
|
|
8700
8775
|
var _this_locale1;
|
|
8701
8776
|
this.$container.innerHTML = IconComponents.date({
|
|
@@ -8729,7 +8804,8 @@ function _set_prototype_of$8(o, p) {
|
|
|
8729
8804
|
_this.options.onOk == null ? void 0 : _this.options.onOk.call(_this.options, date);
|
|
8730
8805
|
_this.emit(EVENTS.control.dateChange, date);
|
|
8731
8806
|
if (date && _this.$container.querySelector("." + PREFIX_CLASS + "-mobile-date-filter-value")) {
|
|
8732
|
-
|
|
8807
|
+
// 纯文本,用 textContent 避免把日期字符串交给 HTML 解析器
|
|
8808
|
+
_this.$container.querySelector("." + PREFIX_CLASS + "-mobile-date-filter-value").textContent = _this._getDateStr();
|
|
8733
8809
|
}
|
|
8734
8810
|
}
|
|
8735
8811
|
},
|
|
@@ -8776,7 +8852,7 @@ function _set_prototype_of$8(o, p) {
|
|
|
8776
8852
|
if (date && !change && this._value !== DateTime.format(date, 'YYYY-MM-DD')) {
|
|
8777
8853
|
this._value = DateTime.format(date, 'YYYY-MM-DD');
|
|
8778
8854
|
if (date && this.$container.querySelector("." + PREFIX_CLASS + "-mobile-date-filter-value")) {
|
|
8779
|
-
this.$container.querySelector("." + PREFIX_CLASS + "-mobile-date-filter-value").
|
|
8855
|
+
this.$container.querySelector("." + PREFIX_CLASS + "-mobile-date-filter-value").textContent = this._getDateStr();
|
|
8780
8856
|
}
|
|
8781
8857
|
}
|
|
8782
8858
|
};
|
|
@@ -8947,7 +9023,8 @@ function _set_prototype_of$7(o, p) {
|
|
|
8947
9023
|
this._value = time;
|
|
8948
9024
|
var valueEl = this.$container.querySelector("." + PREFIX_CLASS + "-mobile-date-filter-value");
|
|
8949
9025
|
if (valueEl) {
|
|
8950
|
-
|
|
9026
|
+
// time 由调用方传入(setTime 是公开方法),只需纯文本,走 textContent
|
|
9027
|
+
valueEl.textContent = this._getTimeStr();
|
|
8951
9028
|
}
|
|
8952
9029
|
}
|
|
8953
9030
|
};
|
|
@@ -9378,8 +9455,12 @@ function _set_prototype_of$5(o, p) {
|
|
|
9378
9455
|
}
|
|
9379
9456
|
this._progress.setCurrent(currentMs);
|
|
9380
9457
|
};
|
|
9381
|
-
/**
|
|
9382
|
-
|
|
9458
|
+
/**
|
|
9459
|
+
* 没有可用片段信息时退化为整个区间,避免进度条空转
|
|
9460
|
+
*
|
|
9461
|
+
* 两个调用方(`_syncCurrent` 开头、`_updateVisible` 的 `visible` 分支)都已经
|
|
9462
|
+
* 判过 `_hasRange()`,这里不再重复判断。
|
|
9463
|
+
*/ _proto._fallbackToRange = function _fallbackToRange() {
|
|
9383
9464
|
this._progress.setSegment(this._rangeBeginMs, this._rangeEndMs);
|
|
9384
9465
|
};
|
|
9385
9466
|
_proto._hasRange = function _hasRange() {
|
|
@@ -9453,7 +9534,12 @@ function _set_prototype_of$4(o, p) {
|
|
|
9453
9534
|
var _proto = Device.prototype;
|
|
9454
9535
|
_proto._render = function _render() {
|
|
9455
9536
|
var _this___options_props_urlInfo, _this___options_props;
|
|
9456
|
-
|
|
9537
|
+
// deviceSerial 由播放地址解析而来(parseEzopenUrl 对它不做字符校验),
|
|
9538
|
+
// 这里只需要纯文本,用 textContent 从根上避免注入
|
|
9539
|
+
var $span = document.createElement('span');
|
|
9540
|
+
$span.className = PREFIX_CLASS + "-text " + PREFIX_CLASS + "-text-device";
|
|
9541
|
+
$span.textContent = this._splicingString(this.__options.deviceName, (_this___options_props = this.__options.props) == null ? void 0 : (_this___options_props_urlInfo = _this___options_props.urlInfo) == null ? void 0 : _this___options_props_urlInfo.deviceSerial);
|
|
9542
|
+
this.$container.replaceChildren($span);
|
|
9457
9543
|
};
|
|
9458
9544
|
/**
|
|
9459
9545
|
* 更新设备序列号
|
|
@@ -9464,7 +9550,8 @@ function _set_prototype_of$4(o, p) {
|
|
|
9464
9550
|
var $span = this.$container.querySelector("." + PREFIX_CLASS + "-text-device");
|
|
9465
9551
|
var text = this._splicingString(deviceName, deviceSerial);
|
|
9466
9552
|
$span == null ? void 0 : $span.setAttribute('title', text);
|
|
9467
|
-
|
|
9553
|
+
// 设备信息来自 getDeviceInfo 事件(接口/内核数据),同样走 textContent
|
|
9554
|
+
$span.textContent = text;
|
|
9468
9555
|
}
|
|
9469
9556
|
};
|
|
9470
9557
|
_proto._splicingString = function _splicingString(deviceName, deviceSerial) {
|
|
@@ -9860,7 +9947,11 @@ var _unmountedControls = function _unmountedControls(theme) {
|
|
|
9860
9947
|
theme._footer.destroy();
|
|
9861
9948
|
theme._footer = null;
|
|
9862
9949
|
}
|
|
9950
|
+
// 移除 header / footer 动画暂停监听(挂在 theme 上,需显式解绑)
|
|
9951
|
+
// 修复:此前只置空引用没有解绑,changeTheme 每调用一次就漏一个监听器,
|
|
9952
|
+
// 且引用被清掉后 _renderTheme 里的兜底解绑也永远不会执行
|
|
9863
9953
|
if (theme._onPauseTimingFunc) {
|
|
9954
|
+
theme.removeListener(CLEAR_TIMER_HEADER_FOOTER_ANIMATION, theme._onPauseTimingFunc);
|
|
9864
9955
|
theme._onPauseTimingFunc = null;
|
|
9865
9956
|
}
|
|
9866
9957
|
// 移除首帧同步监听(挂在 theme 上,需显式解绑,避免 changeTheme 累积)
|
|
@@ -10274,10 +10365,8 @@ function _renderTheme(theme, data) {
|
|
|
10274
10365
|
});
|
|
10275
10366
|
// 当移动端 picker 控件打开时需要关闭动画(定时器)
|
|
10276
10367
|
// 暂停 header footer 的动画(定时器)
|
|
10277
|
-
|
|
10278
|
-
|
|
10279
|
-
theme._onPauseTimingFunc = null;
|
|
10280
|
-
}
|
|
10368
|
+
// 旧监听的解绑统一在 _unmountedControls 里做(本函数开头已无条件调用过),
|
|
10369
|
+
// 这里不再重复判断
|
|
10281
10370
|
theme._onPauseTimingFunc = function(open) {
|
|
10282
10371
|
if (open) {
|
|
10283
10372
|
var _theme__interactiveResult_clearTimeout, _theme__interactiveResult;
|
|
@@ -10671,6 +10760,17 @@ function _inherits(subClass, superClass) {
|
|
|
10671
10760
|
});
|
|
10672
10761
|
if (superClass) _set_prototype_of(subClass, superClass);
|
|
10673
10762
|
}
|
|
10763
|
+
function _object_without_properties_loose(source, excluded) {
|
|
10764
|
+
if (source == null) return {};
|
|
10765
|
+
var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i;
|
|
10766
|
+
for(i = 0; i < sourceKeys.length; i++){
|
|
10767
|
+
key = sourceKeys[i];
|
|
10768
|
+
if (excluded.indexOf(key) >= 0) continue;
|
|
10769
|
+
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
|
|
10770
|
+
target[key] = source[key];
|
|
10771
|
+
}
|
|
10772
|
+
return target;
|
|
10773
|
+
}
|
|
10674
10774
|
function _set_prototype_of(o, p) {
|
|
10675
10775
|
_set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
|
|
10676
10776
|
o.__proto__ = p;
|
|
@@ -11265,10 +11365,16 @@ var THEME_DEFAULT_OPTIONS = {
|
|
|
11265
11365
|
// JSON 不能序列化dom节点, 不要使用 this.options.container, 请使用 this.container
|
|
11266
11366
|
delete this.options.container;
|
|
11267
11367
|
}
|
|
11368
|
+
// 凭据不进日志:这条 log 在生产产物里依然存在(strip 插件只剥离 console.*,
|
|
11369
|
+
// 不处理 logger 实例方法),直接打印 options 等于把 accessToken 暴露在控制台
|
|
11370
|
+
var _this_options = this.options; _this_options.accessToken; _this_options.token; var loggableOptions = _object_without_properties_loose(_this_options, [
|
|
11371
|
+
"accessToken",
|
|
11372
|
+
"token"
|
|
11373
|
+
]);
|
|
11268
11374
|
try {
|
|
11269
|
-
this.logger.log('[options] \n', JSON.stringify(
|
|
11375
|
+
this.logger.log('[options] \n', JSON.stringify(loggableOptions));
|
|
11270
11376
|
} catch (error) {
|
|
11271
|
-
this.logger.log('[options] \n',
|
|
11377
|
+
this.logger.log('[options] \n', loggableOptions);
|
|
11272
11378
|
}
|
|
11273
11379
|
var language = this.options.language || 'zh';
|
|
11274
11380
|
// 深拷贝内置语言包,避免与模块级 zh/en 常量共享引用(I18n 若对其做合并/修改会污染全局)
|
|
@@ -12341,6 +12447,6 @@ var THEME_DEFAULT_OPTIONS = {
|
|
|
12341
12447
|
zh: zh,
|
|
12342
12448
|
en: en
|
|
12343
12449
|
};
|
|
12344
|
-
/** 版本号 @since 0.0.1 */ Theme.THEME_VERSION = '3.1.8-beta.
|
|
12450
|
+
/** 版本号 @since 0.0.1 */ Theme.THEME_VERSION = '3.1.8-beta.3';
|
|
12345
12451
|
|
|
12346
12452
|
export { CONTROL_INIT_EVENTS, Control, EVENTS, Fullscreen, Loading, Message, Play, Poster, Rec, Theme, Utils, Volume };
|