@@ -278,4 +278,65 @@ M.plotLive = function (host, opts) {
} ;
} ;
/* ============================ КОМПОНЕНТ: ПОШАГОВЫЙ ПЛЕЕР (DOM, не canvas) ============================ */
M . stepPlayer = function ( host , opts ) {
opts = opts || { } ; var steps = opts . steps || [ ] ; if ( ! steps . length ) return { stop : function ( ) { } } ;
var i = 0 , auto = null ;
host . innerHTML = '' ;
var wrap = D . createElement ( 'div' ) ;
wrap . innerHTML =
'<div class="m6-step-view" style="min-height:58px;padding:14px 16px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.02rem;line-height:1.65"></div>'
+ '<div style="display:flex;gap:8px;align-items:center;justify-content:center;margin-top:10px;flex-wrap:wrap">'
+ '<button class="btn" data-act="prev" type="button">Назад</button>'
+ '<span class="m6-step-dots" style="display:inline-flex;gap:5px"></span>'
+ '<button class="btn primary" data-act="next" type="button">Дальше</button>'
+ '<button class="btn" data-act="auto" type="button">Авто</button></div>' ;
host . appendChild ( wrap ) ;
var view = wrap . querySelector ( '.m6-step-view' ) , dots = wrap . querySelector ( '.m6-step-dots' ) ;
var prevB = wrap . querySelector ( '[data-act="prev"]' ) , nextB = wrap . querySelector ( '[data-act="next"]' ) , autoB = wrap . querySelector ( '[data-act="auto"]' ) ;
for ( var k = 0 ; k < steps . length ; k ++ ) { var dt = D . createElement ( 'span' ) ; dt . style . cssText = 'width:9px;height:9px;border-radius:50%;background:var(--border,#cbd5e1);transition:background .2s' ; dots . appendChild ( dt ) ; }
function render ( ) {
view . innerHTML = steps [ i ] || '' ;
if ( W . renderMathInElement ) try { W . renderMathInElement ( view , { delimiters : [ { left : '$$' , right : '$$' , display : true } , { left : '$' , right : '$' , display : false } , { left : '\\[' , right : '\\]' , display : true } , { left : '\\(' , right : '\\)' , display : false } ] , throwOnError : false } ) ; } catch ( e ) { }
var ds = dots . children ; for ( var k2 = 0 ; k2 < ds . length ; k2 ++ ) ds [ k2 ] . style . background = ( k2 === i ? 'var(--pri,#4f46e5)' : ( k2 < i ? 'var(--ok,#10b981)' : 'var(--border,#cbd5e1)' ) ) ;
prevB . disabled = i <= 0 ; nextB . disabled = i >= steps . length - 1 ;
prevB . style . opacity = prevB . disabled ? 0.5 : 1 ; nextB . style . opacity = nextB . disabled ? 0.5 : 1 ;
}
function go ( d ) { i = Math . max ( 0 , Math . min ( steps . length - 1 , i + d ) ) ; render ( ) ; }
function stopAuto ( ) { if ( auto ) { try { clearInterval ( auto ) ; } catch ( e ) { } auto = null ; autoB . textContent = 'Авто' ; } }
prevB . addEventListener ( 'click' , function ( ) { stopAuto ( ) ; go ( - 1 ) ; } ) ;
nextB . addEventListener ( 'click' , function ( ) { stopAuto ( ) ; go ( 1 ) ; } ) ;
autoB . addEventListener ( 'click' , function ( ) {
if ( auto ) { stopAuto ( ) ; return ; }
if ( i >= steps . length - 1 ) { i = 0 ; render ( ) ; }
autoB . textContent = 'Пауза' ;
auto = setInterval ( function ( ) { if ( i >= steps . length - 1 ) { stopAuto ( ) ; return ; } go ( 1 ) ; } , 1500 ) ;
} ) ;
render ( ) ;
return { stop : stopAuto } ;
} ;
/* Превратить карточки «Разбор по шагам» (.card с <ol> в теле) в интерактивный stepPlayer. */
M . stepifyExamples = function ( root ) {
if ( ! root ) return ;
var cards = root . querySelectorAll ( '.card' ) ;
for ( var ci = 0 ; ci < cards . length ; ci ++ ) {
var card = cards [ ci ] ;
var titleEl = card . querySelector ( '.card-title' ) ; if ( ! titleEl ) continue ;
if ( ! /шаг/i . test ( titleEl . textContent || '' ) ) continue ;
var body = card . querySelector ( '.card-body' ) ; if ( ! body || body . _ _stepified ) continue ;
var ol = body . querySelector ( 'ol' ) ; if ( ! ol ) continue ;
var lis = ol . querySelectorAll ( 'li' ) ; if ( lis . length < 2 ) continue ;
var steps = [ ] , intro = '' , outro = '' , node = body . firstChild ;
while ( node && node !== ol ) { intro += ( node . nodeType === 1 ? node . outerHTML : ( node . nodeType === 3 ? node . textContent : '' ) ) ; node = node . nextSibling ; }
node = ol . nextSibling ; while ( node ) { outro += ( node . nodeType === 1 ? node . outerHTML : ( node . nodeType === 3 ? node . textContent : '' ) ) ; node = node . nextSibling ; }
if ( intro . replace ( /<[^>]*>/g , '' ) . trim ( ) ) steps . push ( '<div style="font-weight:600">' + intro + '</div>' ) ;
for ( var li = 0 ; li < lis . length ; li ++ ) steps . push ( '<div><b style="color:var(--pri,#4f46e5)">Шаг ' + ( li + 1 ) + '.</b> ' + lis [ li ] . innerHTML + '</div>' ) ;
if ( outro . replace ( /<[^>]*>/g , '' ) . trim ( ) ) steps . push ( outro ) ;
body . _ _stepified = true ; body . innerHTML = '' ;
var hostEl = D . createElement ( 'div' ) ; body . appendChild ( hostEl ) ;
M . stepPlayer ( hostEl , { steps : steps } ) ;
}
} ;
} ) ( window ) ;