mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-10 12:46:15 -08:00
fix(chapter): [PKG-CHAPTER-05] checkpoint composition tests and bounded title layout
This commit is contained in:
1 parent
d18c545675
commit
e0d47ea74b
16 files changed
+7942
-10
No files matched your search
@@ -4,4 +4,4 @@
|
|||||||
* (c) 2017-2026 Harvey Zhao
|
* (c) 2017-2026 Harvey Zhao
|
||||||
* Released under the MIT License.
|
* Released under the MIT License.
|
||||||
*/
|
*/
|
||||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";return function(){if("undefined"===typeof document)return;const t="artplayer-plugin-chapter",e=()=>{let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"};document.getElementById(t)||"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,{once:!0})}(),function(t={}){return e=>{const r=e.template.$player,a=e.query(".art-control-progress-inner");if(!a)throw new Error("Missing ArtPlayer progress container");const n="artplayer-plugin-chapter";let o=function(t){const e=(e,r)=>{const a=t.ownerDocument.createElement("div");return a.className=r,e.appendChild(a),a},r=e(t,"art-chapters"),a=e(t,"art-chapter-title");let n=[];function o(){a.textContent="",a.style.left="0px",a.style.visibility="hidden"}function i(){n=[],r.textContent="",o()}return o(),{clear:i,render:function(t,a){n=t.map(t=>{const n=e(r,"art-chapter"),o=e(n,"art-chapter-inner"),i=t.end-t.start;return n.dataset.start=String(t.start),n.dataset.end=String(t.end),n.dataset.duration=String(i),n.dataset.title=t.title.trim(),n.style.width=i/a*100+"%",{start:t.start,end:t.end,title:t.title.trim(),bars:{hover:e(o,"art-progress-hover"),loaded:e(o,"art-progress-loaded"),played:e(o,"art-progress-played")}}})},setBar:function(e,i,s){if("hover"!==e&&"loaded"!==e&&"played"!==e)return;if(!Number.isFinite(i))return;const l=s*i;let p;for(const t of n)t.bars[e].style.width=l<t.start?"0px":l>t.end?"100%":(l-t.start)/(t.end-t.start)*100+"%",l>=t.start&&l<=t.end&&(p=t);if("hover"!==e)return;o();const d=r.clientWidth*i;p?.title&&d>0&&(a.textContent=p.title,a.style.visibility="visible",a.style.left=`${Math.max(0,Math.min(d-a.clientWidth/2,t.clientWidth-a.clientWidth))}px`)},destroy:function(){i(),r.remove(),a.remove()}}}(a);function i(t){if(!o||e.isDestroy)return;o.clear(),r.classList.remove(n);const a=function(t=[],e){if(!Array.isArray(t)||!t.length||!Number.isFinite(e)||e<=0)return[];t.sort((t,e)=>t.start-e.start);for(const[n,o]of t.entries()){if(!o||"number"!==typeof o.start||"number"!==typeof o.end||"string"!==typeof o.title)throw new TypeError("Illegal chapter data type");o.end===1/0&&(o.end=e);const r=t[n+1];if(!Number.isFinite(o.start)||!Number.isFinite(o.end)||o.start<0||o.end>e||o.start>=o.end||r&&o.end>r.start)throw new Error("Illegal chapter time point")}const r=t[0],a=t[t.length-1];r&&r.start>0&&t.unshift({start:0,end:r.start,title:""}),a&&a.end<e&&t.push({start:a.end,end:e,title:""});for(let n=0;n<t.length-1;n++){const e=t[n],r=t[n+1];e&&r&&e.end!==r.start&&t.splice(n+1,0,{start:e.end,end:r.start,title:""})}return t}(t,e.duration);a.length&&(o.render(a,e.duration),r.classList.add(n),e.emit("setBar","loaded",e.loaded||0))}function s(t,r){e.isDestroy||o?.setBar(t,r,e.duration)}function l(){i(t.chapters)}return e.on("setBar",s),e.once("video:loadedmetadata",l),e.on("destroy",function t(){e.off("setBar",s),e.off("video:loadedmetadata",l),e.off("destroy",t),o?.destroy(),o=void 0,r.classList.remove(n)}),{name:"artplayerPluginChapter",update:({chapters:t})=>i(t)}}}});
|
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";return function(){if("undefined"===typeof document)return;const t="artplayer-plugin-chapter",e=()=>{let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;box-sizing:border-box;max-width:100%;overflow:hidden;text-overflow:ellipsis;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"};document.getElementById(t)||"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,{once:!0})}(),function(t={}){return e=>{const r=e.template.$player,a=e.query(".art-control-progress-inner");if(!a)throw new Error("Missing ArtPlayer progress container");const n="artplayer-plugin-chapter";let o=function(t){const e=(e,r)=>{const a=t.ownerDocument.createElement("div");return a.className=r,e.appendChild(a),a},r=e(t,"art-chapters"),a=e(t,"art-chapter-title");let n=[];function o(){a.textContent="",a.style.left="0px",a.style.visibility="hidden"}function i(){n=[],r.textContent="",o()}return o(),{clear:i,render:function(t,a){n=t.map(t=>{const n=e(r,"art-chapter"),o=e(n,"art-chapter-inner"),i=t.end-t.start;return n.dataset.start=String(t.start),n.dataset.end=String(t.end),n.dataset.duration=String(i),n.dataset.title=t.title.trim(),n.style.width=i/a*100+"%",{start:t.start,end:t.end,title:t.title.trim(),bars:{hover:e(o,"art-progress-hover"),loaded:e(o,"art-progress-loaded"),played:e(o,"art-progress-played")}}})},setBar:function(e,i,s){if("hover"!==e&&"loaded"!==e&&"played"!==e)return;if(!Number.isFinite(i))return;const l=s*i;let d;for(const t of n)t.bars[e].style.width=l<t.start?"0px":l>t.end?"100%":(l-t.start)/(t.end-t.start)*100+"%",l>=t.start&&l<=t.end&&(d=t);if("hover"!==e)return;o();const p=r.clientWidth*i;d?.title&&p>0&&(a.textContent=d.title,a.style.visibility="visible",a.style.left=`${Math.max(0,Math.min(p-a.clientWidth/2,t.clientWidth-a.clientWidth))}px`)},destroy:function(){i(),r.remove(),a.remove()}}}(a);function i(t){if(!o||e.isDestroy)return;o.clear(),r.classList.remove(n);const a=function(t=[],e){if(!Array.isArray(t)||!t.length||!Number.isFinite(e)||e<=0)return[];t.sort((t,e)=>t.start-e.start);for(const[n,o]of t.entries()){if(!o||"number"!==typeof o.start||"number"!==typeof o.end||"string"!==typeof o.title)throw new TypeError("Illegal chapter data type");o.end===1/0&&(o.end=e);const r=t[n+1];if(!Number.isFinite(o.start)||!Number.isFinite(o.end)||o.start<0||o.end>e||o.start>=o.end||r&&o.end>r.start)throw new Error("Illegal chapter time point")}const r=t[0],a=t[t.length-1];r&&r.start>0&&t.unshift({start:0,end:r.start,title:""}),a&&a.end<e&&t.push({start:a.end,end:e,title:""});for(let n=0;n<t.length-1;n++){const e=t[n],r=t[n+1];e&&r&&e.end!==r.start&&t.splice(n+1,0,{start:e.end,end:r.start,title:""})}return t}(t,e.duration);a.length&&(o.render(a,e.duration),r.classList.add(n),e.emit("setBar","loaded",e.loaded||0))}function s(t,r){e.isDestroy||o?.setBar(t,r,e.duration)}function l(){i(t.chapters)}return e.on("setBar",s),e.once("video:loadedmetadata",l),e.on("destroy",function t(){e.off("setBar",s),e.off("video:loadedmetadata",l),e.off("destroy",t),o?.destroy(),o=void 0,r.classList.remove(n)}),{name:"artplayerPluginChapteLine truncated
|
||||||
@@ -4,4 +4,4 @@
|
|||||||
* (c) 2017-2026 Harvey Zhao
|
* (c) 2017-2026 Harvey Zhao
|
||||||
* Released under the MIT License.
|
* Released under the MIT License.
|
||||||
*/
|
*/
|
||||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";return function(){if("undefined"===typeof document)return;const t="artplayer-plugin-chapter",e=()=>{let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"};document.getElementById(t)||"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,{once:!0})}(),function(t={}){return e=>{const r=e.template.$player,a=e.query(".art-control-progress-inner");if(!a)throw new Error("Missing ArtPlayer progress container");const n="artplayer-plugin-chapter";let o=function(t){const e=(e,r)=>{const a=t.ownerDocument.createElement("div");return a.className=r,e.appendChild(a),a},r=e(t,"art-chapters"),a=e(t,"art-chapter-title");let n=[];function o(){a.textContent="",a.style.left="0px",a.style.visibility="hidden"}function i(){n=[],r.textContent="",o()}return o(),{clear:i,render:function(t,a){n=t.map(t=>{const n=e(r,"art-chapter"),o=e(n,"art-chapter-inner"),i=t.end-t.start;return n.dataset.start=String(t.start),n.dataset.end=String(t.end),n.dataset.duration=String(i),n.dataset.title=t.title.trim(),n.style.width=i/a*100+"%",{start:t.start,end:t.end,title:t.title.trim(),bars:{hover:e(o,"art-progress-hover"),loaded:e(o,"art-progress-loaded"),played:e(o,"art-progress-played")}}})},setBar:function(e,i,s){if("hover"!==e&&"loaded"!==e&&"played"!==e)return;if(!Number.isFinite(i))return;const l=s*i;let p;for(const t of n)t.bars[e].style.width=l<t.start?"0px":l>t.end?"100%":(l-t.start)/(t.end-t.start)*100+"%",l>=t.start&&l<=t.end&&(p=t);if("hover"!==e)return;o();const d=r.clientWidth*i;(null==p?void 0:p.title)&&d>0&&(a.textContent=p.title,a.style.visibility="visible",a.style.left=`${Math.max(0,Math.min(d-a.clientWidth/2,t.clientWidth-a.clientWidth))}px`)},destroy:function(){i(),r.remove(),a.remove()}}}(a);function i(t){if(!o||e.isDestroy)return;o.clear(),r.classList.remove(n);const a=function(t=[],e){if(!Array.isArray(t)||!t.length||!Number.isFinite(e)||e<=0)return[];t.sort((t,e)=>t.start-e.start);for(const[n,o]of t.entries()){if(!o||"number"!==typeof o.start||"number"!==typeof o.end||"string"!==typeof o.title)throw new TypeError("Illegal chapter data type");o.end===1/0&&(o.end=e);const r=t[n+1];if(!Number.isFinite(o.start)||!Number.isFinite(o.end)||o.start<0||o.end>e||o.start>=o.end||r&&o.end>r.start)throw new Error("Illegal chapter time point")}const r=t[0],a=t[t.length-1];r&&r.start>0&&t.unshift({start:0,end:r.start,title:""}),a&&a.end<e&&t.push({start:a.end,end:e,title:""});for(let n=0;n<t.length-1;n++){const e=t[n],r=t[n+1];e&&r&&e.end!==r.start&&t.splice(n+1,0,{start:e.end,end:r.start,title:""})}return t}(t,e.duration);a.length&&(o.render(a,e.duration),r.classList.add(n),e.emit("setBar","loaded",e.loaded||0))}function s(t,r){e.isDestroy||null==o||o.setBar(t,r,e.duration)}function l(){i(t.chapters)}return e.on("setBar",s),e.once("video:loadedmetadata",l),e.on("destroy",function t(){e.off("setBar",s),e.off("video:loadedmetadata",l),e.off("destroy",t),null==o||o.destroy(),o=void 0,r.classList.remove(n)}),{name:"artplayerPluginChapter",update:({chapters:t})=>i(t)}}}});
|
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";return function(){if("undefined"===typeof document)return;const t="artplayer-plugin-chapter",e=()=>{let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;box-sizing:border-box;max-width:100%;overflow:hidden;text-overflow:ellipsis;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"};document.getElementById(t)||"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,{once:!0})}(),function(t={}){return e=>{const r=e.template.$player,a=e.query(".art-control-progress-inner");if(!a)throw new Error("Missing ArtPlayer progress container");const n="artplayer-plugin-chapter";let o=function(t){const e=(e,r)=>{const a=t.ownerDocument.createElement("div");return a.className=r,e.appendChild(a),a},r=e(t,"art-chapters"),a=e(t,"art-chapter-title");let n=[];function o(){a.textContent="",a.style.left="0px",a.style.visibility="hidden"}function i(){n=[],r.textContent="",o()}return o(),{clear:i,render:function(t,a){n=t.map(t=>{const n=e(r,"art-chapter"),o=e(n,"art-chapter-inner"),i=t.end-t.start;return n.dataset.start=String(t.start),n.dataset.end=String(t.end),n.dataset.duration=String(i),n.dataset.title=t.title.trim(),n.style.width=i/a*100+"%",{start:t.start,end:t.end,title:t.title.trim(),bars:{hover:e(o,"art-progress-hover"),loaded:e(o,"art-progress-loaded"),played:e(o,"art-progress-played")}}})},setBar:function(e,i,s){if("hover"!==e&&"loaded"!==e&&"played"!==e)return;if(!Number.isFinite(i))return;const l=s*i;let d;for(const t of n)t.bars[e].style.width=l<t.start?"0px":l>t.end?"100%":(l-t.start)/(t.end-t.start)*100+"%",l>=t.start&&l<=t.end&&(d=t);if("hover"!==e)return;o();const p=r.clientWidth*i;(null==d?void 0:d.title)&&p>0&&(a.textContent=d.title,a.style.visibility="visible",a.style.left=`${Math.max(0,Math.min(p-a.clientWidth/2,t.clientWidth-a.clientWidth))}px`)},destroy:function(){i(),r.remove(),a.remove()}}}(a);function i(t){if(!o||e.isDestroy)return;o.clear(),r.classList.remove(n);const a=function(t=[],e){if(!Array.isArray(t)||!t.length||!Number.isFinite(e)||e<=0)return[];t.sort((t,e)=>t.start-e.start);for(const[n,o]of t.entries()){if(!o||"number"!==typeof o.start||"number"!==typeof o.end||"string"!==typeof o.title)throw new TypeError("Illegal chapter data type");o.end===1/0&&(o.end=e);const r=t[n+1];if(!Number.isFinite(o.start)||!Number.isFinite(o.end)||o.start<0||o.end>e||o.start>=o.end||r&&o.end>r.start)throw new Error("Illegal chapter time point")}const r=t[0],a=t[t.length-1];r&&r.start>0&&t.unshift({start:0,end:r.start,title:""}),a&&a.end<e&&t.push({start:a.end,end:e,title:""});for(let n=0;n<t.length-1;n++){const e=t[n],r=t[n+1];e&&r&&e.end!==r.start&&t.splice(n+1,0,{start:e.end,end:r.start,title:""})}return t}(t,e.duration);a.length&&(o.render(a,e.duration),r.classList.add(n),e.emit("setBar","loaded",e.loaded||0))}function s(t,r){e.isDestroy||null==o||o.setBar(t,r,e.duration)}function l(){i(t.chapters)}return e.on("setBar",s),e.once("video:loadedmetadata",l),e.on("destroy",function t(){e.off("setBar",s),e.off("video:loadedmetadata",l),e.off("destroy",t),null==o||o.destroy(),o=void 0,r.classList.remove(nLine truncated
|
||||||
@@ -105,7 +105,7 @@ function createProgress(inner) {
|
|||||||
clearTitle();
|
clearTitle();
|
||||||
return { clear, render, setBar, destroy };
|
return { clear, render, setBar, destroy };
|
||||||
}
|
}
|
||||||
const style = ".artplayer-plugin-chapter .art-control-progress-inner {\n height: 100% !important;\n background-color: transparent !important;\n}\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-hover,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-loaded,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-played {\n display: none !important;\n}\n.artplayer-plugin-chapter .art-control-thumbnails {\n bottom: calc(var(--art-bottom-gap) + 64px) !important;\n}\n.artplayer-plugin-chapter .art-chapters {\n position: absolute;\n z-index: 0;\n inset: 0;\n display: flex;\n align-items: center;\n gap: 4px;\n height: 100%;\n transform: scaleY(1.25);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter {\n display: flex;\n align-items: center;\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner {\n position: relative;\n cursor: pointer;\n width: 100%;\n height: 50%;\n border-radius: 10px;\n overflow: hidden;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner {\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapter-title {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n z-index: 70;\n top: -50px;\n left: 0;\n padding: 3px 5px;\n line-height: 1;\n font-size: 14px;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n background-color: var(--art-tip-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n}\n.artplayer-plugin-chapter.art-progress-hover .art-chapter-title {\n transform: scale(1);\n opacity: 1;\n}\n";
|
const style = ".artplayer-plugin-chapter .art-control-progress-inner {\n height: 100% !important;\n background-color: transparent !important;\n}\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-hover,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-loaded,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-played {\n display: none !important;\n}\n.artplayer-plugin-chapter .art-control-thumbnails {\n bottom: calc(var(--art-bottom-gap) + 64px) !important;\n}\n.artplayer-plugin-chapter .art-chapters {\n position: absolute;\n z-index: 0;\n inset: 0;\n display: flex;\n align-items: center;\n gap: 4px;\n height: 100%;\n transform: scaleY(1.25);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter {\n display: flex;\n align-items: center;\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner {\n position: relative;\n cursor: pointer;\n width: 100%;\n height: 50%;\n border-radius: 10px;\n overflow: hidden;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner {\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapter-title {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n z-index: 70;\n top: -50px;\n left: 0;\n padding: 3px 5px;\n line-height: 1;\n font-size: 14px;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n box-sizing: border-box;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n background-color: var(--art-tip-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n}\n.artplayer-plugin-chapter.art-progress-hover .art-chapter-title {\n transform: scale(1);\n opacity: 1;\n}\n";
|
||||||
function installStyle() {
|
function installStyle() {
|
||||||
if (typeof document === "undefined")
|
if (typeof document === "undefined")
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ attributes. A successful update adds the historical player class, then emits
|
|||||||
`setBar('loaded', art.loaded || 0)` synchronously. Progress events update the three
|
`setBar('loaded', art.loaded || 0)` synchronously. Progress events update the three
|
||||||
bars; a shared boundary belongs to the later chapter for hover title selection,
|
bars; a shared boundary belongs to the later chapter for hover title selection,
|
||||||
matching the old traversal order. Titles use textContent, never caller HTML.
|
matching the old traversal order. Titles use textContent, never caller HTML.
|
||||||
|
Title boxes are limited to the progress container width, including their padding,
|
||||||
|
and display an ellipsis for long text. Full textContent and data-title remain intact.
|
||||||
|
The renderer still clamps horizontal position; CSS owns text clipping, not normalization.
|
||||||
|
|
||||||
`update({})` and non-array chapter input clear the view. Invalid types throw
|
`update({})` and non-array chapter input clear the view. Invalid types throw
|
||||||
TypeError and invalid time ranges throw Error with the existing messages. NaN and
|
TypeError and invalid time ranges throw Error with the existing messages. NaN and
|
||||||
@@ -83,6 +86,17 @@ For UI, start at progress.ts/style.less and verify real mouse interaction. For e
|
|||||||
or cleanup changes, start at index.ts and rerun early destroy/multiple-instance tests.
|
or cleanup changes, start at index.ts and rerun early destroy/multiple-instance tests.
|
||||||
Any public declaration change also needs new/old compiler and tarball consumers.
|
Any public declaration change also needs new/old compiler and tarball consumers.
|
||||||
|
|
||||||
|
`test/browser/chapter-combinations.spec.js` adds old/new core and plugin combinations
|
||||||
|
with quality selection, actual thumbnail hover, narrow titles, element fullscreen,
|
||||||
|
web fullscreen reparenting and trusted taps. Quality menus must finish opening before
|
||||||
|
selection and lose pointer/focus before progress hover. The published core hides its
|
||||||
|
menu with opacity/pointer-events; it does not use the candidate visibility rule.
|
||||||
|
The published core also has a recorded Windows WebKit quality-position reset; keep
|
||||||
|
that historical observation separate from the candidate's position-restoration assertion.
|
||||||
|
The touch cases use a 390px viewport, hasTouch and an iPhone user agent on the desktop
|
||||||
|
engines. They validate the mobile branch and trusted input, not an actual iPhone.
|
||||||
|
See refactor/changes/2026-09-12-PKG-CHAPTER-05-combinations.md for current evidence and gaps.
|
||||||
|
|
||||||
The public declaration remains available to old compilers and exports Chapters,
|
The public declaration remains available to old compilers and exports Chapters,
|
||||||
Option and Result as types. Modern import/require conditions select format-specific
|
Option and Result as types. Modern import/require conditions select format-specific
|
||||||
bridges; typesVersions provides the legacy subpath to old resolvers. All bridges
|
bridges; typesVersions provides the legacy subpath to old resolvers. All bridges
|
||||||
|
|||||||
@@ -4,4 +4,4 @@
|
|||||||
* (c) 2017-2026 Harvey Zhao
|
* (c) 2017-2026 Harvey Zhao
|
||||||
* Released under the MIT License.
|
* Released under the MIT License.
|
||||||
*/
|
*/
|
||||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";return function(){if("undefined"===typeof document)return;const t="artplayer-plugin-chapter",e=()=>{let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"};document.getElementById(t)||"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,{once:!0})}(),function(t={}){return e=>{const r=e.template.$player,a=e.query(".art-control-progress-inner");if(!a)throw new Error("Missing ArtPlayer progress container");const n="artplayer-plugin-chapter";let o=function(t){const e=(e,r)=>{const a=t.ownerDocument.createElement("div");return a.className=r,e.appendChild(a),a},r=e(t,"art-chapters"),a=e(t,"art-chapter-title");let n=[];function o(){a.textContent="",a.style.left="0px",a.style.visibility="hidden"}function i(){n=[],r.textContent="",o()}return o(),{clear:i,render:function(t,a){n=t.map(t=>{const n=e(r,"art-chapter"),o=e(n,"art-chapter-inner"),i=t.end-t.start;return n.dataset.start=String(t.start),n.dataset.end=String(t.end),n.dataset.duration=String(i),n.dataset.title=t.title.trim(),n.style.width=i/a*100+"%",{start:t.start,end:t.end,title:t.title.trim(),bars:{hover:e(o,"art-progress-hover"),loaded:e(o,"art-progress-loaded"),played:e(o,"art-progress-played")}}})},setBar:function(e,i,s){if("hover"!==e&&"loaded"!==e&&"played"!==e)return;if(!Number.isFinite(i))return;const l=s*i;let p;for(const t of n)t.bars[e].style.width=l<t.start?"0px":l>t.end?"100%":(l-t.start)/(t.end-t.start)*100+"%",l>=t.start&&l<=t.end&&(p=t);if("hover"!==e)return;o();const d=r.clientWidth*i;p?.title&&d>0&&(a.textContent=p.title,a.style.visibility="visible",a.style.left=`${Math.max(0,Math.min(d-a.clientWidth/2,t.clientWidth-a.clientWidth))}px`)},destroy:function(){i(),r.remove(),a.remove()}}}(a);function i(t){if(!o||e.isDestroy)return;o.clear(),r.classList.remove(n);const a=function(t=[],e){if(!Array.isArray(t)||!t.length||!Number.isFinite(e)||e<=0)return[];t.sort((t,e)=>t.start-e.start);for(const[n,o]of t.entries()){if(!o||"number"!==typeof o.start||"number"!==typeof o.end||"string"!==typeof o.title)throw new TypeError("Illegal chapter data type");o.end===1/0&&(o.end=e);const r=t[n+1];if(!Number.isFinite(o.start)||!Number.isFinite(o.end)||o.start<0||o.end>e||o.start>=o.end||r&&o.end>r.start)throw new Error("Illegal chapter time point")}const r=t[0],a=t[t.length-1];r&&r.start>0&&t.unshift({start:0,end:r.start,title:""}),a&&a.end<e&&t.push({start:a.end,end:e,title:""});for(let n=0;n<t.length-1;n++){const e=t[n],r=t[n+1];e&&r&&e.end!==r.start&&t.splice(n+1,0,{start:e.end,end:r.start,title:""})}return t}(t,e.duration);a.length&&(o.render(a,e.duration),r.classList.add(n),e.emit("setBar","loaded",e.loaded||0))}function s(t,r){e.isDestroy||o?.setBar(t,r,e.duration)}function l(){i(t.chapters)}return e.on("setBar",s),e.once("video:loadedmetadata",l),e.on("destroy",function t(){e.off("setBar",s),e.off("video:loadedmetadata",l),e.off("destroy",t),o?.destroy(),o=void 0,r.classList.remove(n)}),{name:"artplayerPluginChapter",update:({chapters:t})=>i(t)}}}});
|
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";return function(){if("undefined"===typeof document)return;const t="artplayer-plugin-chapter",e=()=>{let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;box-sizing:border-box;max-width:100%;overflow:hidden;text-overflow:ellipsis;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"};document.getElementById(t)||"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,{once:!0})}(),function(t={}){return e=>{const r=e.template.$player,a=e.query(".art-control-progress-inner");if(!a)throw new Error("Missing ArtPlayer progress container");const n="artplayer-plugin-chapter";let o=function(t){const e=(e,r)=>{const a=t.ownerDocument.createElement("div");return a.className=r,e.appendChild(a),a},r=e(t,"art-chapters"),a=e(t,"art-chapter-title");let n=[];function o(){a.textContent="",a.style.left="0px",a.style.visibility="hidden"}function i(){n=[],r.textContent="",o()}return o(),{clear:i,render:function(t,a){n=t.map(t=>{const n=e(r,"art-chapter"),o=e(n,"art-chapter-inner"),i=t.end-t.start;return n.dataset.start=String(t.start),n.dataset.end=String(t.end),n.dataset.duration=String(i),n.dataset.title=t.title.trim(),n.style.width=i/a*100+"%",{start:t.start,end:t.end,title:t.title.trim(),bars:{hover:e(o,"art-progress-hover"),loaded:e(o,"art-progress-loaded"),played:e(o,"art-progress-played")}}})},setBar:function(e,i,s){if("hover"!==e&&"loaded"!==e&&"played"!==e)return;if(!Number.isFinite(i))return;const l=s*i;let d;for(const t of n)t.bars[e].style.width=l<t.start?"0px":l>t.end?"100%":(l-t.start)/(t.end-t.start)*100+"%",l>=t.start&&l<=t.end&&(d=t);if("hover"!==e)return;o();const p=r.clientWidth*i;d?.title&&p>0&&(a.textContent=d.title,a.style.visibility="visible",a.style.left=`${Math.max(0,Math.min(p-a.clientWidth/2,t.clientWidth-a.clientWidth))}px`)},destroy:function(){i(),r.remove(),a.remove()}}}(a);function i(t){if(!o||e.isDestroy)return;o.clear(),r.classList.remove(n);const a=function(t=[],e){if(!Array.isArray(t)||!t.length||!Number.isFinite(e)||e<=0)return[];t.sort((t,e)=>t.start-e.start);for(const[n,o]of t.entries()){if(!o||"number"!==typeof o.start||"number"!==typeof o.end||"string"!==typeof o.title)throw new TypeError("Illegal chapter data type");o.end===1/0&&(o.end=e);const r=t[n+1];if(!Number.isFinite(o.start)||!Number.isFinite(o.end)||o.start<0||o.end>e||o.start>=o.end||r&&o.end>r.start)throw new Error("Illegal chapter time point")}const r=t[0],a=t[t.length-1];r&&r.start>0&&t.unshift({start:0,end:r.start,title:""}),a&&a.end<e&&t.push({start:a.end,end:e,title:""});for(let n=0;n<t.length-1;n++){const e=t[n],r=t[n+1];e&&r&&e.end!==r.start&&t.splice(n+1,0,{start:e.end,end:r.start,title:""})}return t}(t,e.duration);a.length&&(o.render(a,e.duration),r.classList.add(n),e.emit("setBar","loaded",e.loaded||0))}function s(t,r){e.isDestroy||o?.setBar(t,r,e.duration)}function l(){i(t.chapters)}return e.on("setBar",s),e.once("video:loadedmetadata",l),e.on("destroy",function t(){e.off("setBar",s),e.off("video:loadedmetadata",l),e.off("destroy",t),o?.destroy(),o=void 0,r.classList.remove(n)}),{name:"artplayerPluginChapteLine truncated
|
||||||
@@ -4,4 +4,4 @@
|
|||||||
* (c) 2017-2026 Harvey Zhao
|
* (c) 2017-2026 Harvey Zhao
|
||||||
* Released under the MIT License.
|
* Released under the MIT License.
|
||||||
*/
|
*/
|
||||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";return function(){if("undefined"===typeof document)return;const t="artplayer-plugin-chapter",e=()=>{let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"};document.getElementById(t)||"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,{once:!0})}(),function(t={}){return e=>{const r=e.template.$player,a=e.query(".art-control-progress-inner");if(!a)throw new Error("Missing ArtPlayer progress container");const n="artplayer-plugin-chapter";let o=function(t){const e=(e,r)=>{const a=t.ownerDocument.createElement("div");return a.className=r,e.appendChild(a),a},r=e(t,"art-chapters"),a=e(t,"art-chapter-title");let n=[];function o(){a.textContent="",a.style.left="0px",a.style.visibility="hidden"}function i(){n=[],r.textContent="",o()}return o(),{clear:i,render:function(t,a){n=t.map(t=>{const n=e(r,"art-chapter"),o=e(n,"art-chapter-inner"),i=t.end-t.start;return n.dataset.start=String(t.start),n.dataset.end=String(t.end),n.dataset.duration=String(i),n.dataset.title=t.title.trim(),n.style.width=i/a*100+"%",{start:t.start,end:t.end,title:t.title.trim(),bars:{hover:e(o,"art-progress-hover"),loaded:e(o,"art-progress-loaded"),played:e(o,"art-progress-played")}}})},setBar:function(e,i,s){if("hover"!==e&&"loaded"!==e&&"played"!==e)return;if(!Number.isFinite(i))return;const l=s*i;let p;for(const t of n)t.bars[e].style.width=l<t.start?"0px":l>t.end?"100%":(l-t.start)/(t.end-t.start)*100+"%",l>=t.start&&l<=t.end&&(p=t);if("hover"!==e)return;o();const d=r.clientWidth*i;(null==p?void 0:p.title)&&d>0&&(a.textContent=p.title,a.style.visibility="visible",a.style.left=`${Math.max(0,Math.min(d-a.clientWidth/2,t.clientWidth-a.clientWidth))}px`)},destroy:function(){i(),r.remove(),a.remove()}}}(a);function i(t){if(!o||e.isDestroy)return;o.clear(),r.classList.remove(n);const a=function(t=[],e){if(!Array.isArray(t)||!t.length||!Number.isFinite(e)||e<=0)return[];t.sort((t,e)=>t.start-e.start);for(const[n,o]of t.entries()){if(!o||"number"!==typeof o.start||"number"!==typeof o.end||"string"!==typeof o.title)throw new TypeError("Illegal chapter data type");o.end===1/0&&(o.end=e);const r=t[n+1];if(!Number.isFinite(o.start)||!Number.isFinite(o.end)||o.start<0||o.end>e||o.start>=o.end||r&&o.end>r.start)throw new Error("Illegal chapter time point")}const r=t[0],a=t[t.length-1];r&&r.start>0&&t.unshift({start:0,end:r.start,title:""}),a&&a.end<e&&t.push({start:a.end,end:e,title:""});for(let n=0;n<t.length-1;n++){const e=t[n],r=t[n+1];e&&r&&e.end!==r.start&&t.splice(n+1,0,{start:e.end,end:r.start,title:""})}return t}(t,e.duration);a.length&&(o.render(a,e.duration),r.classList.add(n),e.emit("setBar","loaded",e.loaded||0))}function s(t,r){e.isDestroy||null==o||o.setBar(t,r,e.duration)}function l(){i(t.chapters)}return e.on("setBar",s),e.once("video:loadedmetadata",l),e.on("destroy",function t(){e.off("setBar",s),e.off("video:loadedmetadata",l),e.off("destroy",t),null==o||o.destroy(),o=void 0,r.classList.remove(n)}),{name:"artplayerPluginChapter",update:({chapters:t})=>i(t)}}}});
|
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginChapter=e(),define(function(){return t.artplayerPluginChapter})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginChapter=e()}(this,function(){"use strict";return function(){if("undefined"===typeof document)return;const t="artplayer-plugin-chapter",e=()=>{let e=document.getElementById(t);e||(e=document.createElement("style"),e.id=t,(document.head||document.documentElement).appendChild(e)),e.textContent=".artplayer-plugin-chapter .art-control-progress-inner{height:100%!important;background-color:transparent!important}.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-hover,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-loaded,.artplayer-plugin-chapter .art-control-progress-inner>.art-progress-played{display:none!important}.artplayer-plugin-chapter .art-control-thumbnails{bottom:calc(var(--art-bottom-gap) + 64px)!important}.artplayer-plugin-chapter .art-chapters{position:absolute;z-index:0;inset:0;display:flex;align-items:center;gap:4px;height:100%;transform:scaleY(1.25)}.artplayer-plugin-chapter .art-chapters .art-chapter{display:flex;align-items:center;height:100%}.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner{position:relative;cursor:pointer;width:100%;height:50%;border-radius:10px;overflow:hidden;transition:height var(--art-transition-duration) ease;background-color:var(--art-progress-color)}.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner{height:100%}.artplayer-plugin-chapter .art-chapter-title{transform-origin:bottom center;transform:scale(.5);opacity:0;position:absolute;z-index:70;top:-50px;left:0;padding:3px 5px;line-height:1;font-size:14px;border-radius:var(--art-border-radius);white-space:nowrap;box-sizing:border-box;max-width:100%;overflow:hidden;text-overflow:ellipsis;background-color:var(--art-tip-background);transition:transform var(--art-transition-duration) ease,opacity var(--art-transition-duration) ease}.artplayer-plugin-chapter.art-progress-hover .art-chapter-title{transform:scale(1);opacity:1}"};document.getElementById(t)||"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,{once:!0})}(),function(t={}){return e=>{const r=e.template.$player,a=e.query(".art-control-progress-inner");if(!a)throw new Error("Missing ArtPlayer progress container");const n="artplayer-plugin-chapter";let o=function(t){const e=(e,r)=>{const a=t.ownerDocument.createElement("div");return a.className=r,e.appendChild(a),a},r=e(t,"art-chapters"),a=e(t,"art-chapter-title");let n=[];function o(){a.textContent="",a.style.left="0px",a.style.visibility="hidden"}function i(){n=[],r.textContent="",o()}return o(),{clear:i,render:function(t,a){n=t.map(t=>{const n=e(r,"art-chapter"),o=e(n,"art-chapter-inner"),i=t.end-t.start;return n.dataset.start=String(t.start),n.dataset.end=String(t.end),n.dataset.duration=String(i),n.dataset.title=t.title.trim(),n.style.width=i/a*100+"%",{start:t.start,end:t.end,title:t.title.trim(),bars:{hover:e(o,"art-progress-hover"),loaded:e(o,"art-progress-loaded"),played:e(o,"art-progress-played")}}})},setBar:function(e,i,s){if("hover"!==e&&"loaded"!==e&&"played"!==e)return;if(!Number.isFinite(i))return;const l=s*i;let d;for(const t of n)t.bars[e].style.width=l<t.start?"0px":l>t.end?"100%":(l-t.start)/(t.end-t.start)*100+"%",l>=t.start&&l<=t.end&&(d=t);if("hover"!==e)return;o();const p=r.clientWidth*i;(null==d?void 0:d.title)&&p>0&&(a.textContent=d.title,a.style.visibility="visible",a.style.left=`${Math.max(0,Math.min(p-a.clientWidth/2,t.clientWidth-a.clientWidth))}px`)},destroy:function(){i(),r.remove(),a.remove()}}}(a);function i(t){if(!o||e.isDestroy)return;o.clear(),r.classList.remove(n);const a=function(t=[],e){if(!Array.isArray(t)||!t.length||!Number.isFinite(e)||e<=0)return[];t.sort((t,e)=>t.start-e.start);for(const[n,o]of t.entries()){if(!o||"number"!==typeof o.start||"number"!==typeof o.end||"string"!==typeof o.title)throw new TypeError("Illegal chapter data type");o.end===1/0&&(o.end=e);const r=t[n+1];if(!Number.isFinite(o.start)||!Number.isFinite(o.end)||o.start<0||o.end>e||o.start>=o.end||r&&o.end>r.start)throw new Error("Illegal chapter time point")}const r=t[0],a=t[t.length-1];r&&r.start>0&&t.unshift({start:0,end:r.start,title:""}),a&&a.end<e&&t.push({start:a.end,end:e,title:""});for(let n=0;n<t.length-1;n++){const e=t[n],r=t[n+1];e&&r&&e.end!==r.start&&t.splice(n+1,0,{start:e.end,end:r.start,title:""})}return t}(t,e.duration);a.length&&(o.render(a,e.duration),r.classList.add(n),e.emit("setBar","loaded",e.loaded||0))}function s(t,r){e.isDestroy||null==o||o.setBar(t,r,e.duration)}function l(){i(t.chapters)}return e.on("setBar",s),e.once("video:loadedmetadata",l),e.on("destroy",function t(){e.off("setBar",s),e.off("video:loadedmetadata",l),e.off("destroy",t),null==o||o.destroy(),o=void 0,r.classList.remove(nLine truncated
|
||||||
@@ -105,7 +105,7 @@ function createProgress(inner) {
|
|||||||
clearTitle();
|
clearTitle();
|
||||||
return { clear, render, setBar, destroy };
|
return { clear, render, setBar, destroy };
|
||||||
}
|
}
|
||||||
const style = ".artplayer-plugin-chapter .art-control-progress-inner {\n height: 100% !important;\n background-color: transparent !important;\n}\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-hover,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-loaded,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-played {\n display: none !important;\n}\n.artplayer-plugin-chapter .art-control-thumbnails {\n bottom: calc(var(--art-bottom-gap) + 64px) !important;\n}\n.artplayer-plugin-chapter .art-chapters {\n position: absolute;\n z-index: 0;\n inset: 0;\n display: flex;\n align-items: center;\n gap: 4px;\n height: 100%;\n transform: scaleY(1.25);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter {\n display: flex;\n align-items: center;\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner {\n position: relative;\n cursor: pointer;\n width: 100%;\n height: 50%;\n border-radius: 10px;\n overflow: hidden;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner {\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapter-title {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n z-index: 70;\n top: -50px;\n left: 0;\n padding: 3px 5px;\n line-height: 1;\n font-size: 14px;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n background-color: var(--art-tip-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n}\n.artplayer-plugin-chapter.art-progress-hover .art-chapter-title {\n transform: scale(1);\n opacity: 1;\n}\n";
|
const style = ".artplayer-plugin-chapter .art-control-progress-inner {\n height: 100% !important;\n background-color: transparent !important;\n}\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-hover,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-loaded,\n.artplayer-plugin-chapter .art-control-progress-inner > .art-progress-played {\n display: none !important;\n}\n.artplayer-plugin-chapter .art-control-thumbnails {\n bottom: calc(var(--art-bottom-gap) + 64px) !important;\n}\n.artplayer-plugin-chapter .art-chapters {\n position: absolute;\n z-index: 0;\n inset: 0;\n display: flex;\n align-items: center;\n gap: 4px;\n height: 100%;\n transform: scaleY(1.25);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter {\n display: flex;\n align-items: center;\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter .art-chapter-inner {\n position: relative;\n cursor: pointer;\n width: 100%;\n height: 50%;\n border-radius: 10px;\n overflow: hidden;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n}\n.artplayer-plugin-chapter .art-chapters .art-chapter:hover .art-chapter-inner {\n height: 100%;\n}\n.artplayer-plugin-chapter .art-chapter-title {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n z-index: 70;\n top: -50px;\n left: 0;\n padding: 3px 5px;\n line-height: 1;\n font-size: 14px;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n box-sizing: border-box;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n background-color: var(--art-tip-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n}\n.artplayer-plugin-chapter.art-progress-hover .art-chapter-title {\n transform: scale(1);\n opacity: 1;\n}\n";
|
||||||
function installStyle() {
|
function installStyle() {
|
||||||
if (typeof document === "undefined")
|
if (typeof document === "undefined")
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -59,6 +59,10 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
border-radius: var(--art-border-radius);
|
border-radius: var(--art-border-radius);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
box-sizing: border-box;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
background-color: var(--art-tip-background);
|
background-color: var(--art-tip-background);
|
||||||
transition:
|
transition:
|
||||||
transform var(--art-transition-duration) ease,
|
transform var(--art-transition-duration) ease,
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,60 @@
|
|||||||
|
# PKG-CHAPTER-05:进度、清晰度、缩略图与全屏组合
|
||||||
|
|
||||||
|
状态:进行中。起点 d18c5456,工作区已核实干净;Chapter-04 和 CORE-22 前置已完成。
|
||||||
|
|
||||||
|
现有 chapter.spec.js 的全面章节用例固定旧核心。新增组合覆盖旧/新核心、旧/新 chapter,
|
||||||
|
使用本地固定 MP4 和缩略图网格验证真实 hover、seek、清晰度切换、显式章节更新、原生/
|
||||||
|
网页全屏进出与缩略图/标题位置。触摸部分在 390px、hasTouch 与 iPhone UA 模拟环境中
|
||||||
|
要求可信 touchstart,并检查进入/退出网页全屏后的章节 seek;不声称已在 iPhone 真机运行。
|
||||||
|
|
||||||
|
本阶段先保留实际测试结果;任何失败先核对原生能力、旧版行为、测试夹具与候选实现,
|
||||||
|
不改断言使候选假通过。物理设备和未覆盖场景继续作为未验收范围。
|
||||||
|
|
||||||
|
## 已确认的显示缺陷与源码修复
|
||||||
|
|
||||||
|
390px 的长标题在新旧插件都超过进度条右边界;真实页面显示文字被播放器外边缘直接裁切。
|
||||||
|
先加入候选不越界的失败断言以及旧版溢出观察,三引擎分别两种核心:6 个候选失败、
|
||||||
|
6 个历史观察通过。style.less 现使用 max-width:100%、border-box、overflow:hidden 和
|
||||||
|
text-overflow:ellipsis,把显示宽度交给样式层;progress.ts/chapters.ts、同步 update、
|
||||||
|
数组原地变更、事件以及声明不变。完整 textContent 与 data-title 仍按原样保留。
|
||||||
|
正式 main/legacy/module 与 docs/compiled 已由 yarn build artplayer-plugin-chapter 生成。
|
||||||
|
|
||||||
|
## 夹具修正与尚未关闭的时序疑点
|
||||||
|
|
||||||
|
第一轮 48 项:36 个全屏/触摸组合通过,12 个 quality 场景失败。10 个卡在 hover 结束
|
||||||
|
章节:鼠标点在展开的 quality 菜单覆盖区域,尚未进入进度条;两个旧核心 WebKit 的
|
||||||
|
位置回到 0,已有 progress-quality.spec.js 复现该历史缺陷。该旧版观察保持显式分支,
|
||||||
|
候选核心仍必须恢复切换前位置,没有用旧缺陷放宽候选断言。
|
||||||
|
|
||||||
|
第二轮先移动鼠标,仍 12 项失败:候选菜单有焦点保持;旧 core CSS 原本只有 opacity=0
|
||||||
|
和 pointer-events:none,并无 visibility:hidden,toBeHidden 不能表示它的视觉关闭。
|
||||||
|
第三轮外部 Pause 按钮点击后,候选菜单退出,旧核心的 toBeHidden 仍失败。对照实际
|
||||||
|
发布包样式后改为检查 opacity=0,选择前等待 opacity=1,随后仍要求真实标题与缩略图
|
||||||
|
可见、位置不重叠。所有首轮报告均保留;这是菜单交互前提修正,不是删除章节断言。
|
||||||
|
|
||||||
|
第三轮 24 项中长标题全部通过;另有候选核心 WebKit 的 quality restart 等待超时。
|
||||||
|
修正菜单后的一轮 12 quality 为 11 通过/1 失败,最后候选核心+候选章节仍在 7 秒
|
||||||
|
轮询内未看到 restart,而 afterEach 已记录 restart、新源、恢复位置、readyState=4,
|
||||||
|
没有媒体错误。来源可能涉及原生 seek/事件耗时,尚未证明;不据此修改核心或提高超时,
|
||||||
|
也不因后续某次通过关闭这个疑点。原始事件序列和失败 trace 继续保留。
|
||||||
|
|
||||||
|
本次未安装依赖、未更改发布版本。触摸模拟不代替物理 Safari/iOS/Android,完整分发与
|
||||||
|
8082 demo 属于 Chapter-06。任务仍 doing,源码修复与证据以独立 checkpoint 提交。
|
||||||
|
回退本检查点会移除长标题显示限制,恢复旧显示;已发布的 npm 包没有发生变化。
|
||||||
|
|
||||||
|
## 本检查点验证结果
|
||||||
|
|
||||||
|
- 正式 main 和 legacy 分别 102 项通过,无重试/跳过;使用明确产物映射,核心与章节包
|
||||||
|
的浏览器服务指纹均与实际 dist 字节一致,不是冒用源码运行结果。
|
||||||
|
- 每组包含原有 42 项章节用例与新增 60 项组合。新增部分为 12 个长标题(含 6 个历史
|
||||||
|
溢出观察)、12 个 quality/缩略图(含两项旧核心 WebKit 位置归零观察)、24 个真实元素/
|
||||||
|
网页全屏、12 个触摸模拟。不能把所有通过项都称为没有历史缺陷的候选验收。
|
||||||
|
- 完整 CI 599 项(550 单元、14 工程、35 基线)通过;严格源码/类型消费、声明一致性、
|
||||||
|
lint 通过,保留一条已知生成声明 warning。最终新增测试定向 lint 通过。
|
||||||
|
- 长标题修复后截图已实际查看:文字省略且标题框在播放器内,完整内容保持在 DOM 数据。
|
||||||
|
- 全部阶段包括 48 项首轮、12 项菜单修正失败、12 项长标题先红后绿、24 项第三轮
|
||||||
|
17 通过/7 失败及最后 quality 11/1 均保留,见 [冻结证据](../baselines/chapter-combinations-checkpoint.json)。
|
||||||
|
|
||||||
|
CHAPTER-LAYOUT-01 已按具体显示范围关闭;CHAPTER-TIMING-01 仍 open。最终产物两轮
|
||||||
|
通过不解释早期时序超时,不能以它们消除待查证据。当前 217 项,70 done、3 doing、144 todo。
|
||||||
|
下一步可推进独立包;Chapter-05 的物理设备和时序缺口继续随风险台账接续,不阻塞全局目标。
|
||||||
+3
-2
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 217 项,范围 22 个包及工作区/示例。
|
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 217 项,范围 22 个包及工作区/示例。
|
||||||
|
|
||||||
状态:todo 145 / doing 2 / blocked 0 / done 70 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
状态:todo 144 / doing 3 / blocked 0 / done 70 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||||
|
|
||||||
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@
|
|||||||
| PKG-CHAPTER-02 | artplayer-plugin-chapter<br>建立特有行为与错误测试 | PKG-CHAPTER-01, ENG-03, ENG-05 | 区间重叠/空列表/边界 seek、hover 标题和 update 用例 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言;修正 BASE-TYPE-02 的可选参数声明并补正反例 | M | done |
|
| PKG-CHAPTER-02 | artplayer-plugin-chapter<br>建立特有行为与错误测试 | PKG-CHAPTER-01, ENG-03, ENG-05 | 区间重叠/空列表/边界 seek、hover 标题和 update 用例 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言;修正 BASE-TYPE-02 的可选参数声明并补正反例 | M | done |
|
||||||
| PKG-CHAPTER-03 | artplayer-plugin-chapter<br>以 TypeScript 拆分内部职责与资源 | PKG-CHAPTER-02, ENG-07 | 以严格 TS 拆分区间计算、进度 DOM、事件生命周期与样式注入;公开声明消费在 04 闭环 | 不依赖新核心方法或大范围设置重构;旧 API/事件和资源通过,必要适配限包内 | M | done |
|
| PKG-CHAPTER-03 | artplayer-plugin-chapter<br>以 TypeScript 拆分内部职责与资源 | PKG-CHAPTER-02, ENG-07 | 以严格 TS 拆分区间计算、进度 DOM、事件生命周期与样式注入;公开声明消费在 04 闭环 | 不依赖新核心方法或大范围设置重构;旧 API/事件和资源通过,必要适配限包内 | M | done |
|
||||||
| PKG-CHAPTER-04 | artplayer-plugin-chapter<br>迁移自有源码和公开类型 | PKG-CHAPTER-03, ENG-04, ENG-06 | 承接 03 的自有源码 TS 化,完善公开 Chapters/Option/Result 与 update 推导,关闭声明模块解析和旧消费差异 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容;处理 BASE-TYPE-01/03,保持运行时和新旧 TS 模块解析消费 | M | done |
|
| PKG-CHAPTER-04 | artplayer-plugin-chapter<br>迁移自有源码和公开类型 | PKG-CHAPTER-03, ENG-04, ENG-06 | 承接 03 的自有源码 TS 化,完善公开 Chapters/Option/Result 与 update 推导,关闭声明模块解析和旧消费差异 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容;处理 BASE-TYPE-01/03,保持运行时和新旧 TS 模块解析消费 | M | done |
|
||||||
| PKG-CHAPTER-05 | artplayer-plugin-chapter<br>验证新旧核心和组合 | PKG-CHAPTER-04, CORE-22 | chapter + quality/thumbnail、移动和全屏进度场景 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | M | todo |
|
| PKG-CHAPTER-05 | artplayer-plugin-chapter<br>验证新旧核心和组合 | PKG-CHAPTER-04, CORE-22 | chapter + quality/thumbnail、移动和全屏进度场景 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | M | doing |
|
||||||
| PKG-CHAPTER-06 | artplayer-plugin-chapter<br>验证分发并同步文档 | PKG-CHAPTER-05, ENG-07 | chapter.js 示例、产物和变更记录 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | M | todo |
|
| PKG-CHAPTER-06 | artplayer-plugin-chapter<br>验证分发并同步文档 | PKG-CHAPTER-05, ENG-07 | chapter.js 示例、产物和变更记录 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | M | todo |
|
||||||
|
|
||||||
## 5 包迁移:artplayer-plugin-ambilight
|
## 5 包迁移:artplayer-plugin-ambilight
|
||||||
@@ -468,6 +468,7 @@
|
|||||||
- PKG-CHAPTER-02: [记录](changes/2026-09-10-PKG-CHAPTER-02-tests.md) [记录](baselines/chapter-validation.json)
|
- PKG-CHAPTER-02: [记录](changes/2026-09-10-PKG-CHAPTER-02-tests.md) [记录](baselines/chapter-validation.json)
|
||||||
- PKG-CHAPTER-03: [记录](changes/2026-09-10-PKG-CHAPTER-03-typescript-modules.md) [记录](baselines/chapter-migration-validation.json)
|
- PKG-CHAPTER-03: [记录](changes/2026-09-10-PKG-CHAPTER-03-typescript-modules.md) [记录](baselines/chapter-migration-validation.json)
|
||||||
- PKG-CHAPTER-04: [记录](changes/2026-09-10-PKG-CHAPTER-04-public-types.md) [记录](baselines/chapter-types-validation.json)
|
- PKG-CHAPTER-04: [记录](changes/2026-09-10-PKG-CHAPTER-04-public-types.md) [记录](baselines/chapter-types-validation.json)
|
||||||
|
- PKG-CHAPTER-05: [记录](changes/2026-09-12-PKG-CHAPTER-05-combinations.md) [记录](baselines/chapter-combinations-checkpoint.json)
|
||||||
- PKG-AUDIO-01: [记录](changes/2026-09-12-PKG-AUDIO-01-contract.md) [记录](baselines/audio-track-contract.md) [记录](baselines/audio-track-release.json)
|
- PKG-AUDIO-01: [记录](changes/2026-09-12-PKG-AUDIO-01-contract.md) [记录](baselines/audio-track-contract.md) [记录](baselines/audio-track-release.json)
|
||||||
- PKG-AUDIO-02: [记录](changes/2026-09-12-PKG-AUDIO-02-tests.md) [记录](audio-validation.md) [记录](baselines/audio-validation.json)
|
- PKG-AUDIO-02: [记录](changes/2026-09-12-PKG-AUDIO-02-tests.md) [记录](audio-validation.md) [记录](baselines/audio-validation.json)
|
||||||
- PKG-AUDIO-03: [记录](changes/2026-09-12-PKG-AUDIO-03-lifecycle.md) [记录](baselines/audio-lifecycle-validation.json)
|
- PKG-AUDIO-03: [记录](changes/2026-09-12-PKG-AUDIO-03-lifecycle.md) [记录](baselines/audio-lifecycle-validation.json)
|
||||||
|
|||||||
@@ -1,5 +1,20 @@
|
|||||||
# 进度与证据
|
# 进度与证据
|
||||||
|
|
||||||
|
## 当前实施:Chapter-05 组合验证与长标题修复检查点
|
||||||
|
|
||||||
|
正式 main/legacy 的章节基础及新旧核心/插件组合各 102 项通过,完整 CI 599 项通过。
|
||||||
|
新增覆盖清晰度/缩略图、窄屏长标题、真实元素与网页全屏,以及 390px 可信触摸模拟。
|
||||||
|
长标题超出进度条的显示缺陷已通过 CSS 修复,完整文本与公开接口不变;截图已查看。
|
||||||
|
|
||||||
|
保留菜单交互前提修正的失败记录、旧核心 WebKit 位置归零观察。一个早期 WebKit
|
||||||
|
quality restart 等待超时的确切原因尚未证明,CHAPTER-TIMING-01 保持 open;后续
|
||||||
|
两种产物通过不能关闭它。触摸模拟没有替代手机真机。Chapter-05 仍 doing,尚未执行 06。
|
||||||
|
|
||||||
|
当前 217 项:70 done、3 doing、144 todo。Audio-05、HLS-SDK-01 的风险仍保留。
|
||||||
|
本批为本地 checkpoint,未推送或发布。后续优先推进独立包的源码/契约迁移,并在有效
|
||||||
|
环境中接续开放的媒体/设备验证。详见 [本次变更](changes/2026-09-12-PKG-CHAPTER-05-combinations.md)
|
||||||
|
和 [冻结证据](baselines/chapter-combinations-checkpoint.json)。
|
||||||
|
|
||||||
## 当前实施:Audio-05 恢复修复与真实缓冲检查点
|
## 当前实施:Audio-05 恢复修复与真实缓冲检查点
|
||||||
|
|
||||||
已修复旧核心时间零 seek 后候选音频漏恢复,严格 TS 与公开接口不变;三格式 Node 97 项、
|
已修复旧核心时间零 seek 后候选音频漏恢复,严格 TS 与公开接口不变;三格式 Node 97 项、
|
||||||
|
|||||||
@@ -133,3 +133,5 @@
|
|||||||
| CORE-SOURCE-01 | resolved / 已复现 | 候选核心连续切源丢失原播放意图 | CORE-24 |
|
| CORE-SOURCE-01 | resolved / 已复现 | 候选核心连续切源丢失原播放意图 | CORE-24 |
|
||||||
| AUDIO-RESUME-01 | resolved / 已复现 | WebKit 旧核心切源后候选音频保持暂停 | PKG-AUDIO-05 |
|
| AUDIO-RESUME-01 | resolved / 已复现 | WebKit 旧核心切源后候选音频保持暂停 | PKG-AUDIO-05 |
|
||||||
| AUDIO-BUFFER-01 | open / 已复现 | Windows WebKit 原生媒体无法在受限响应下推进至真实缓冲 | PKG-AUDIO-05 |
|
| AUDIO-BUFFER-01 | open / 已复现 | Windows WebKit 原生媒体无法在受限响应下推进至真实缓冲 | PKG-AUDIO-05 |
|
||||||
|
| CHAPTER-LAYOUT-01 | resolved / 已复现 | 长章节标题超出窄播放器进度条宽度 | PKG-CHAPTER-05 |
|
||||||
|
| CHAPTER-TIMING-01 | open / 已复现 | Windows WebKit 清晰度切换曾在等待窗口内未见 restart,稍后状态恢复 | PKG-CHAPTER-05 |
|
||||||
@@ -2791,6 +2791,43 @@
|
|||||||
],
|
],
|
||||||
"compatibleResolution": "保留真实 waiting 断言;使用独立原生对照和其他实际支持环境/输入继续验证,不将没有播放推进的诊断当成缓冲通过,也不凭此改变插件 API 或否定真实 Safari 支持。",
|
"compatibleResolution": "保留真实 waiting 断言;使用独立原生对照和其他实际支持环境/输入继续验证,不将没有播放推进的诊断当成缓冲通过,也不凭此改变插件 API 或否定真实 Safari 支持。",
|
||||||
"closureCriteria": "受影响的缓冲/恢复得到真实媒体证据;与原生能力和测试夹具差异分开,发布环境的剩余范围经显式处理。"
|
"closureCriteria": "受影响的缓冲/恢复得到真实媒体证据;与原生能力和测试夹具差异分开,发布环境的剩余范围经显式处理。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "CHAPTER-LAYOUT-01",
|
||||||
|
"title": "长章节标题超出窄播放器进度条宽度",
|
||||||
|
"confirmation": "reproduced",
|
||||||
|
"status": "resolved",
|
||||||
|
"owners": [
|
||||||
|
"PKG-CHAPTER-05"
|
||||||
|
],
|
||||||
|
"evidence": [
|
||||||
|
"refactor/baselines/chapter-combinations-checkpoint.json",
|
||||||
|
"test/browser/chapter-combinations.spec.js"
|
||||||
|
],
|
||||||
|
"compatibleResolution": "样式限制最大宽度并省略溢出显示,保留完整 textContent/data-title、DOM hooks 和原有章节数据语义。",
|
||||||
|
"closureCriteria": "两种核心三引擎窄屏候选标题不越界,历史溢出观察和完整文本保留断言通过。",
|
||||||
|
"resolutionEvidence": [
|
||||||
|
"refactor/baselines/chapter-combinations-checkpoint.json",
|
||||||
|
"packages/artplayer-plugin-chapter/src/style.less",
|
||||||
|
"packages/artplayer-plugin-chapter/ARCHITECTURE.md"
|
||||||
|
],
|
||||||
|
"resolutionRationale": "先复现 6 个候选失败并保留截图,CSS 修复后正式 main/legacy 分别 12 个长标题用例通过(各含 6 历史溢出观察)。实际浏览器输入与产物指纹已冻结,API/类型未改变。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "CHAPTER-TIMING-01",
|
||||||
|
"title": "Windows WebKit 清晰度切换曾在等待窗口内未见 restart,稍后状态恢复",
|
||||||
|
"confirmation": "reproduced",
|
||||||
|
"status": "open",
|
||||||
|
"owners": [
|
||||||
|
"PKG-CHAPTER-05"
|
||||||
|
],
|
||||||
|
"evidence": [
|
||||||
|
"refactor/baselines/chapter-combinations-checkpoint.json",
|
||||||
|
"test/browser/chapter-combinations.spec.js",
|
||||||
|
"refactor/changes/2026-09-12-PKG-CHAPTER-05-combinations.md"
|
||||||
|
],
|
||||||
|
"compatibleResolution": "记录原生事件和绝对/相对时序,进一步区分媒体驱动耗时、夹具和核心源操作;未证明原因前不改核心、不扩大超时或重复到绿灯。",
|
||||||
|
"closureCriteria": "确认先前超时的来源并有对应可靠回归;后续单次通过不足以关闭。"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+5
-2
@@ -1351,11 +1351,14 @@
|
|||||||
"PKG-CHAPTER-04",
|
"PKG-CHAPTER-04",
|
||||||
"CORE-22"
|
"CORE-22"
|
||||||
],
|
],
|
||||||
"status": "todo",
|
"status": "doing",
|
||||||
"risk": "M",
|
"risk": "M",
|
||||||
"deliverable": "chapter + quality/thumbnail、移动和全屏进度场景",
|
"deliverable": "chapter + quality/thumbnail、移动和全屏进度场景",
|
||||||
"acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成",
|
"acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成",
|
||||||
"evidence": []
|
"evidence": [
|
||||||
|
"changes/2026-09-12-PKG-CHAPTER-05-combinations.md",
|
||||||
|
"baselines/chapter-combinations-checkpoint.json"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "PKG-CHAPTER-06",
|
"id": "PKG-CHAPTER-06",
|
||||||
|
|||||||
@@ -0,0 +1,194 @@
|
|||||||
|
import { devices } from '@playwright/test'
|
||||||
|
import { expect, test } from './fixtures.js'
|
||||||
|
|
||||||
|
async function openChapter(page, core, chapter) {
|
||||||
|
await page.goto(`/test/player.html?core=${core}&chapter=${chapter}`)
|
||||||
|
await page.evaluate(() => {
|
||||||
|
document.querySelector('.player').style.cssText = 'width:min(640px,100%);height:300px'
|
||||||
|
window.chapterEvents = []
|
||||||
|
window.chapterMediaEvents = []
|
||||||
|
window.art = new window.Artplayer({
|
||||||
|
container: '.player',
|
||||||
|
url: '/test/pattern.mp4?quality=B',
|
||||||
|
muted: true,
|
||||||
|
fullscreen: true,
|
||||||
|
fullscreenWeb: true,
|
||||||
|
miniProgressBar: true,
|
||||||
|
quality: [
|
||||||
|
{ html: 'Quality A', url: '/test/pattern.mp4?quality=A' },
|
||||||
|
{ html: 'Quality B', url: '/test/pattern.mp4?quality=B', default: true },
|
||||||
|
],
|
||||||
|
thumbnails: { url: '/test/thumbnail-grid.svg', number: 100, column: 10, width: 100, height: 60 },
|
||||||
|
plugins: [window.artplayerPluginChapter({ chapters: [
|
||||||
|
{ start: 0, end: 2, title: 'Opening' },
|
||||||
|
{ start: 2, end: 6, title: 'Middle' },
|
||||||
|
{ start: 6, end: 8, title: 'Ending' },
|
||||||
|
] })],
|
||||||
|
})
|
||||||
|
for (const name of ['restart', 'seek', 'fullscreen', 'fullscreenWeb'])
|
||||||
|
window.art.on(name, value => window.chapterEvents.push({ name, value }))
|
||||||
|
for (const name of ['loadedmetadata', 'loadeddata', 'canplay', 'seeking', 'seeked', 'playing', 'pause', 'error'])
|
||||||
|
window.art.video.addEventListener(name, () => window.chapterMediaEvents.push({ name, time: window.art.currentTime, source: window.art.video.currentSrc, paused: window.art.video.paused, readyState: window.art.video.readyState }))
|
||||||
|
document.querySelector('#play').onclick = () => window.art.play()
|
||||||
|
document.querySelector('#pause').onclick = () => window.art.pause()
|
||||||
|
})
|
||||||
|
await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true)
|
||||||
|
await expect(page.locator('.art-chapter')).toHaveCount(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hoverChapter(page, percentage, text) {
|
||||||
|
const inner = page.locator('.art-control-progress-inner')
|
||||||
|
const box = await inner.boundingBox()
|
||||||
|
const x = Math.round(box.x + box.width * percentage)
|
||||||
|
await page.mouse.move(x, box.y + box.height / 2)
|
||||||
|
await expect(page.locator('.art-chapter-title')).toHaveText(text)
|
||||||
|
await expect(page.locator('.art-chapter-title')).toHaveCSS('opacity', '1')
|
||||||
|
await expect(page.locator('.art-control-thumbnails')).toBeVisible()
|
||||||
|
await expect.poll(() => page.evaluate(() => window.art.controls.thumbnails.style.backgroundImage)).not.toBe('')
|
||||||
|
const layout = await page.evaluate(() => {
|
||||||
|
const rect = (element) => {
|
||||||
|
const box = element.getBoundingClientRect()
|
||||||
|
return { left: box.left, right: box.right, top: box.top, bottom: box.bottom }
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
title: rect(document.querySelector('.art-chapter-title')),
|
||||||
|
thumbnail: rect(window.art.controls.thumbnails),
|
||||||
|
progress: rect(document.querySelector('.art-control-progress-inner')),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(layout.title.left).toBeGreaterThanOrEqual(layout.progress.left - 1)
|
||||||
|
expect(layout.title.right).toBeLessThanOrEqual(layout.progress.right + 1)
|
||||||
|
expect(layout.thumbnail.bottom).toBeLessThanOrEqual(layout.title.top)
|
||||||
|
return { box, x, layout }
|
||||||
|
}
|
||||||
|
|
||||||
|
test.afterEach(async ({ page }, testInfo) => {
|
||||||
|
const state = await page.evaluate(() => ({
|
||||||
|
events: window.chapterEvents,
|
||||||
|
nativeEvents: window.chapterMediaEvents,
|
||||||
|
time: window.art?.currentTime,
|
||||||
|
paused: window.art?.video.paused,
|
||||||
|
mediaError: window.art?.video.error?.code || null,
|
||||||
|
source: window.art?.video.currentSrc,
|
||||||
|
readyState: window.art?.video.readyState,
|
||||||
|
mobileBranch: window.Artplayer?.utils.isMobile,
|
||||||
|
maxTouchPoints: navigator.maxTouchPoints,
|
||||||
|
chapters: [...document.querySelectorAll('.art-chapter')].map(node => ({ ...node.dataset })),
|
||||||
|
})).catch(error => ({ error: error.message }))
|
||||||
|
await testInfo.attach('chapter-combination-state', { contentType: 'application/json', body: JSON.stringify(state) })
|
||||||
|
if (!page.isClosed())
|
||||||
|
await page.evaluate(() => window.art?.destroy())
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const core of ['published', 'candidate']) {
|
||||||
|
for (const chapter of ['published', 'candidate']) {
|
||||||
|
test(`${core} core + ${chapter} chapter: long titles retain text within a narrow player`, async ({ page }, testInfo) => {
|
||||||
|
await page.setViewportSize({ width: 390, height: 844 })
|
||||||
|
await openChapter(page, core, chapter)
|
||||||
|
const fullTitle = 'A long chapter title with complete metadata retained for consumers. '.repeat(4)
|
||||||
|
await page.evaluate(fullTitle => window.art.plugins.artplayerPluginChapter.update({ chapters: [{ start: 0, end: Infinity, title: fullTitle }] }), fullTitle)
|
||||||
|
const box = await page.locator('.art-control-progress-inner').boundingBox()
|
||||||
|
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2)
|
||||||
|
await expect(page.locator('.art-chapter-title')).toHaveText(fullTitle.trim())
|
||||||
|
await expect(page.locator('.art-chapter-title')).toHaveCSS('opacity', '1')
|
||||||
|
const layout = await page.locator('.art-chapter-title').evaluate((element) => {
|
||||||
|
const title = element.getBoundingClientRect()
|
||||||
|
const progress = element.parentElement.getBoundingClientRect()
|
||||||
|
return { left: title.left, right: title.right, width: title.width, progressLeft: progress.left, progressRight: progress.right, text: element.textContent, dataset: element.parentElement.querySelector('.art-chapter').dataset.title }
|
||||||
|
})
|
||||||
|
await testInfo.attach('long-chapter-layout', { contentType: 'application/json', body: JSON.stringify(layout) })
|
||||||
|
await testInfo.attach('long-chapter-title', { contentType: 'image/png', body: await page.screenshot() })
|
||||||
|
expect(layout.text).toBe(fullTitle.trim())
|
||||||
|
expect(layout.dataset).toBe(fullTitle.trim())
|
||||||
|
expect(layout.left).toBeGreaterThanOrEqual(layout.progressLeft - 1)
|
||||||
|
if (chapter === 'published')
|
||||||
|
expect(layout.right).toBeGreaterThan(layout.progressRight)
|
||||||
|
else
|
||||||
|
expect(layout.right).toBeLessThanOrEqual(layout.progressRight + 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
test(`${core} core + ${chapter} chapter: quality switch preserves chapter/thumbnail interactions`, async ({ page, browserName }, testInfo) => {
|
||||||
|
await openChapter(page, core, chapter)
|
||||||
|
await page.locator('#play').click()
|
||||||
|
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.2)
|
||||||
|
await page.locator('#pause').click()
|
||||||
|
const { box, x } = await hoverChapter(page, 0.375, 'Middle')
|
||||||
|
await page.mouse.click(x, box.y + box.height / 2)
|
||||||
|
await expect.poll(() => page.evaluate(() => !window.art.video.seeking)).toBe(true)
|
||||||
|
const time = await page.evaluate(() => window.art.currentTime)
|
||||||
|
expect(time).toBeCloseTo(3, 1)
|
||||||
|
await expect.poll(() => page.locator('.art-chapter .art-progress-played').nth(1).evaluate(node => Number.parseFloat(node.style.width))).toBeCloseTo(25, 0)
|
||||||
|
expect(await page.locator('.art-chapter .art-progress-played').evaluateAll(nodes => [nodes[0].style.width, nodes[2].style.width])).toEqual(['100%', '0px'])
|
||||||
|
await page.locator('.art-control-quality').hover()
|
||||||
|
await expect(page.locator('.art-control-quality .art-selector-list')).toHaveCSS('opacity', '1')
|
||||||
|
await page.locator('.art-control-quality .art-selector-item').filter({ hasText: 'Quality A' }).click()
|
||||||
|
await expect.poll(() => page.evaluate(() => window.art.url.includes('quality=A'))).toBe(true)
|
||||||
|
await expect.poll(() => page.evaluate(() => window.chapterEvents.filter(event => event.name === 'restart').map(event => event.value))).toEqual(['/test/pattern.mp4?quality=A'])
|
||||||
|
await expect.poll(() => page.evaluate(() => !window.art.video.seeking && window.art.video.readyState >= 2)).toBe(true)
|
||||||
|
const restoredTime = await page.evaluate(() => window.art.currentTime)
|
||||||
|
const historicalReset = core === 'published' && browserName === 'webkit'
|
||||||
|
if (historicalReset)
|
||||||
|
expect(restoredTime).toBeLessThan(0.05)
|
||||||
|
else
|
||||||
|
expect(restoredTime).toBeCloseTo(time, 1)
|
||||||
|
await testInfo.attach('quality-position', { contentType: 'application/json', body: JSON.stringify({ before: time, restoredTime, historicalReset }) })
|
||||||
|
expect(await page.evaluate(() => window.art.video.paused)).toBe(true)
|
||||||
|
await expect(page.locator('.art-control-quality .art-selector-value')).toHaveText('Quality A')
|
||||||
|
await page.locator('#pause').click()
|
||||||
|
await expect(page.locator('.art-control-quality .art-selector-list')).toHaveCSS('opacity', '0')
|
||||||
|
await hoverChapter(page, 0.85, 'Ending')
|
||||||
|
await page.evaluate(() => window.art.plugins.artplayerPluginChapter.update({ chapters: [{ start: 0, end: Infinity, title: 'Updated after quality' }] }))
|
||||||
|
await hoverChapter(page, 0.5, 'Updated after quality')
|
||||||
|
await testInfo.attach('chapter-quality-thumbnail', { contentType: 'image/png', body: await page.locator('.art-video-player').screenshot() })
|
||||||
|
await page.locator('#play').click()
|
||||||
|
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(restoredTime + 0.2)
|
||||||
|
expect(await page.evaluate(() => window.art.video.error)).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const mode of ['fullscreenWeb', 'fullscreen']) {
|
||||||
|
test(`${core} core + ${chapter} chapter: ${mode} keeps hover geometry and exits cleanly`, async ({ page }, testInfo) => {
|
||||||
|
await openChapter(page, core, chapter)
|
||||||
|
if (mode === 'fullscreenWeb')
|
||||||
|
await page.evaluate(() => { window.Artplayer.FULLSCREEN_WEB_IN_BODY = true })
|
||||||
|
const control = page.locator(`.art-control-${mode}`)
|
||||||
|
const before = await page.locator('.art-control-progress-inner').boundingBox()
|
||||||
|
await control.click()
|
||||||
|
await expect.poll(() => page.evaluate(mode => window.art[mode], mode)).toBe(true)
|
||||||
|
const { box, layout } = await hoverChapter(page, 0.5, 'Middle')
|
||||||
|
expect(box.width).toBeGreaterThanOrEqual(before.width)
|
||||||
|
await testInfo.attach(`chapter-${mode}`, { contentType: 'image/png', body: await page.screenshot() })
|
||||||
|
await testInfo.attach('chapter-fullscreen-layout', { contentType: 'application/json', body: JSON.stringify(layout) })
|
||||||
|
await control.click()
|
||||||
|
await expect.poll(() => page.evaluate(mode => window.art[mode], mode)).toBe(false)
|
||||||
|
expect(await page.evaluate(() => window.art.template.$container.contains(window.art.template.$player))).toBe(true)
|
||||||
|
await hoverChapter(page, 0.99, 'Ending')
|
||||||
|
expect(await page.evaluate(mode => window.chapterEvents.filter(event => event.name === mode).map(event => event.value), mode)).toEqual([true, false])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
test.describe(`${core} core + ${chapter} chapter touch emulation`, () => {
|
||||||
|
test.use({ viewport: { width: 390, height: 844 }, hasTouch: true, userAgent: devices['iPhone 13'].userAgent })
|
||||||
|
test('trusted taps seek through chapters before and after web fullscreen', async ({ page }, testInfo) => {
|
||||||
|
await openChapter(page, core, chapter)
|
||||||
|
expect(await page.evaluate(() => window.Artplayer.utils.isMobile)).toBe(true)
|
||||||
|
await page.evaluate(() => {
|
||||||
|
window.chapterTouches = []
|
||||||
|
window.art.template.$progress.addEventListener('touchstart', event => window.chapterTouches.push({ trusted: event.isTrusted, touches: event.touches.length }))
|
||||||
|
})
|
||||||
|
for (const fullscreen of [false, true, false]) {
|
||||||
|
if (await page.evaluate(() => window.art.fullscreenWeb) !== fullscreen)
|
||||||
|
await page.locator('.art-control-fullscreenWeb').tap()
|
||||||
|
await expect.poll(() => page.evaluate(() => window.art.fullscreenWeb)).toBe(fullscreen)
|
||||||
|
const progress = await page.locator('.art-control-progress-inner').boundingBox()
|
||||||
|
await page.touchscreen.tap(progress.x + progress.width * 0.375, progress.y + progress.height / 2)
|
||||||
|
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeCloseTo(3, 1)
|
||||||
|
await expect.poll(() => page.evaluate(() => !window.art.video.seeking)).toBe(true)
|
||||||
|
await expect(page.locator('.art-chapter')).toHaveCount(3)
|
||||||
|
}
|
||||||
|
expect(await page.evaluate(() => window.chapterTouches)).toEqual(Array.from({ length: 3 }, () => ({ trusted: true, touches: 1 })))
|
||||||
|
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true)
|
||||||
|
await testInfo.attach('chapter-touch-emulation', { contentType: 'image/png', body: await page.screenshot() })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user