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