motimeline 2.9.0 → 2.11.0
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/README.md +89 -0
- package/dist/moTimeline.cjs +3 -3
- package/dist/moTimeline.css +2 -2
- package/dist/moTimeline.js +142 -97
- package/dist/moTimeline.umd.js +3 -3
- package/package.json +1 -1
- package/src/moTimeline.css +10 -1
- package/src/moTimeline.js +114 -35
package/README.md
CHANGED
|
@@ -92,6 +92,41 @@ import 'motimeline/dist/moTimeline.css';
|
|
|
92
92
|
</li>
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
+
### Rendered DOM (after init)
|
|
96
|
+
|
|
97
|
+
The library injects classes and elements into your markup. Here is what a fully rendered item looks like:
|
|
98
|
+
|
|
99
|
+
```html
|
|
100
|
+
<!-- Container gets mo-timeline, mo-theme, mo-twocol added -->
|
|
101
|
+
<ul class="mo-timeline mo-theme mo-twocol">
|
|
102
|
+
|
|
103
|
+
<!-- Left-column item: mo-item + js-mo-item added to every <li> -->
|
|
104
|
+
<li class="mo-item js-mo-item">
|
|
105
|
+
<span class="mo-arrow js-mo-arrow"></span> <!-- injected when showArrow: true -->
|
|
106
|
+
<span class="mo-badge js-mo-badge">1</span> <!-- injected when showBadge: true -->
|
|
107
|
+
<div class="mo-card">
|
|
108
|
+
<div class="mo-card-image">
|
|
109
|
+
<img class="mo-banner" src="banner.jpg" alt="">
|
|
110
|
+
<img class="mo-avatar" src="avatar.jpg" alt="">
|
|
111
|
+
</div>
|
|
112
|
+
<div class="mo-card-body">
|
|
113
|
+
<h3>Title</h3>
|
|
114
|
+
<p class="mo-meta">Date</p>
|
|
115
|
+
<p>Text…</p>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
</li>
|
|
119
|
+
|
|
120
|
+
<!-- Right-column item: also gets mo-inverted + js-mo-inverted -->
|
|
121
|
+
<li class="mo-item js-mo-item mo-inverted js-mo-inverted">
|
|
122
|
+
...
|
|
123
|
+
</li>
|
|
124
|
+
|
|
125
|
+
</ul>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
> `js-mo-*` classes are JS-only selector mirrors of their `mo-*` counterparts — use them in your own scripts to avoid coupling to styling class names.
|
|
129
|
+
|
|
95
130
|
---
|
|
96
131
|
|
|
97
132
|
## Options
|
|
@@ -110,6 +145,8 @@ import 'motimeline/dist/moTimeline.css';
|
|
|
110
145
|
| `cardMarginFullWidth` | string | `'0.5rem'` | Margin of full-width themed cards. Sets `--mo-card-margin-fullwidth` on the container. |
|
|
111
146
|
| `randomFullWidth` | number \| boolean | `0` | `0`/`false` = off. A number `0–1` sets the probability that each item is randomly promoted to full-width during init. `true` = 33% chance. Items can also be set manually by adding the `mo-fullwidth` class to the `<li>`. |
|
|
112
147
|
| `animate` | string \| boolean | `false` | Animate items as they scroll into view using `IntersectionObserver`. `'fade'` — items fade in. `'slide'` — left-column items slide in from the left, right-column items from the right. `true` = `'fade'`. Disable for individual items by adding `mo-visible` manually. Control speed via `--mo-animate-duration`. |
|
|
148
|
+
| `renderCard` | function \| null | `null` | `(item, cardEl) => void`. When set, called for every item instead of the built-in HTML renderer. `cardEl` is the `.mo-card` div already placed inside the `<li>`. Populate it via `innerHTML` or DOM methods. The library still owns the `<li>`, column placement, spine, badge, arrow, `addItems()`, and scroll pagination. |
|
|
149
|
+
| `adSlots` | object \| null | `null` | Inject ad slot placeholders into the timeline and observe them. See **Ad slots** below. |
|
|
113
150
|
|
|
114
151
|
---
|
|
115
152
|
|
|
@@ -290,6 +327,52 @@ export default function App() {
|
|
|
290
327
|
|
|
291
328
|
---
|
|
292
329
|
|
|
330
|
+
## Ad slots
|
|
331
|
+
|
|
332
|
+
Inject ad placeholder `<li>` elements at configurable positions, observe them with `IntersectionObserver`, and fire a callback exactly once when each slot reaches 50% visibility. The library owns the slot element — you own what goes inside it.
|
|
333
|
+
|
|
334
|
+
```js
|
|
335
|
+
const tl = new MoTimeline('#my-timeline', {
|
|
336
|
+
adSlots: {
|
|
337
|
+
mode: 'every_n', // 'every_n' | 'random'
|
|
338
|
+
interval: 10, // every_n: inject after every N real items
|
|
339
|
+
// random: inject once at a random position per N-item page
|
|
340
|
+
style: 'card', // 'card' | 'fullwidth'
|
|
341
|
+
onEnterViewport: (slotEl, position) => {
|
|
342
|
+
// slotEl = the <li class="mo-ad-slot"> element
|
|
343
|
+
// position = its 0-based index in the container at injection time
|
|
344
|
+
const ins = document.createElement('ins');
|
|
345
|
+
ins.className = 'adsbygoogle';
|
|
346
|
+
ins.style.display = 'block';
|
|
347
|
+
ins.dataset.adClient = 'ca-pub-XXXXXXXXXXXXXXXX';
|
|
348
|
+
ins.dataset.adSlot = '1234567890';
|
|
349
|
+
ins.dataset.adFormat = 'auto';
|
|
350
|
+
slotEl.appendChild(ins);
|
|
351
|
+
(window.adsbygoogle = window.adsbygoogle || []).push({});
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### `adSlots` option shape
|
|
358
|
+
|
|
359
|
+
| Property | Type | Description |
|
|
360
|
+
|---|---|---|
|
|
361
|
+
| `mode` | `'every_n' \| 'random'` | `'every_n'` — inject after every `interval` real items. `'random'` — inject one slot at a random position within each `interval`-item page. |
|
|
362
|
+
| `interval` | number | Cadence for slot injection (see `mode`). |
|
|
363
|
+
| `style` | `'card' \| 'fullwidth'` | `'card'` — slot sits in the normal left/right column flow. `'fullwidth'` — slot spans both columns (adds `mo-fullwidth`). |
|
|
364
|
+
| `onEnterViewport` | `(slotEl: HTMLElement, position: number) => void` | Called once per slot when ≥ 50% of it enters the viewport. `position` is the 0-based child index of the slot in the container at injection time. |
|
|
365
|
+
|
|
366
|
+
**What the library provides:**
|
|
367
|
+
- A `<li class="mo-ad-slot">` element with `min-height: 100px` (so the observer can detect it before content loads)
|
|
368
|
+
- `fullwidth` layout via the existing `mo-fullwidth` mechanism when `style: 'fullwidth'`
|
|
369
|
+
- Exactly-once `IntersectionObserver` (threshold 0.5) per slot
|
|
370
|
+
- Automatic slot cleanup on `tl.destroy()`
|
|
371
|
+
|
|
372
|
+
**What you provide:** everything inside the slot — the ad creative, network scripts, markup.
|
|
373
|
+
|
|
374
|
+
Slots are injected after each `addItems()` call, so they work seamlessly with infinite scroll.
|
|
375
|
+
|
|
293
376
|
## Infinite scroll recipe
|
|
294
377
|
|
|
295
378
|
moTimeline handles the layout — you own the data fetching. Wire an `IntersectionObserver` to a sentinel element below the list and call `addItems()` when it comes into view.
|
|
@@ -382,6 +465,12 @@ No framework option needed. Wrap the `<ul>` inside a Bootstrap `.container`:
|
|
|
382
465
|
|
|
383
466
|
## Changelog
|
|
384
467
|
|
|
468
|
+
### v2.11.0
|
|
469
|
+
- New option `adSlots` — inject ad slot `<li>` placeholders at configurable positions (`every_n` or `random` mode) and receive an `onEnterViewport(slotEl, position)` callback exactly once per slot when ≥ 50% of it is visible. Works with `addItems()` and infinite scroll. Slots are removed on `tl.destroy()`. See **Ad slots** section.
|
|
470
|
+
|
|
471
|
+
### v2.10.0
|
|
472
|
+
- New option `renderCard(item, cardEl)` — custom card renderer. When provided, the library skips its built-in card HTML and calls this function instead, passing the item data object and the `.mo-card` div already inserted into the DOM. The library continues to own column placement, spine, badge, arrow, `addItems()`, and scroll pagination. Enables full React component injection via `createRoot(cardEl).render(...)`.
|
|
473
|
+
|
|
385
474
|
### v2.9.0
|
|
386
475
|
- New option `animate` — scroll-triggered animations via `IntersectionObserver`. `'fade'` fades items in as they enter the viewport; `'slide'` slides left-column items from the left and right-column items from the right. `true` defaults to `'fade'`. Speed controlled via `--mo-animate-duration` (default `0.5s`). Works for initial load, `addItems()`, and `insertItem()`.
|
|
387
476
|
|
package/dist/moTimeline.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
* moTimeline v2.
|
|
1
|
+
"use strict";var C=Object.defineProperty;var S=(l,e,t)=>e in l?C(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var _=(l,e,t)=>S(l,typeof e!="symbol"?e+"":e,t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});/*!
|
|
2
|
+
* moTimeline v2.11.0
|
|
3
3
|
* Responsive two-column timeline layout library
|
|
4
4
|
* https://github.com/MattOpen/moTimeline
|
|
5
5
|
* MIT License
|
|
6
|
-
*/const
|
|
6
|
+
*/const h=new WeakMap,b={columnCount:{xs:1,sm:2,md:2,lg:2},showBadge:!1,showArrow:!1,theme:!1,showCounterStyle:"counter",cardBorderRadius:"8px",avatarSize:"50px",cardMargin:"0.5rem 1.25rem 0.5rem 0.5rem",cardMarginInverted:"0.5rem 0.5rem 0.5rem 1.25rem",cardMarginFullWidth:"0.5rem",randomFullWidth:0,animate:!1,renderCard:null,adSlots:null},A="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";function w(){const l=window.innerWidth;return l<600?"xs":l<992?"sm":l<1200?"md":"lg"}function I(l,e=100){let t;return(...s)=>{clearTimeout(t),t=setTimeout(()=>l(...s),e)}}function p(l){return l?{o:l.offsetTop,h:l.offsetHeight,gppu:l.offsetTop+l.offsetHeight}:{o:0,h:0,gppu:0}}function y(l,e){const t=[];let s=l.previousElementSibling;for(;s;)(!e||s.matches(e))&&t.push(s),s=s.previousElementSibling;return t}const f=class f{constructor(e,t={}){if(typeof e=="string"&&(e=document.querySelector(e)),!e)throw new Error("moTimeline: element not found");this.element=e,this.settings=Object.assign({},b,t),this.settings.columnCount=Object.assign({},b.columnCount,t.columnCount),this._resizeHandler=I(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(h.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});if(h.set(e,t),f.instances.add(this),e.classList.add("mo-timeline"),t.theme&&e.classList.add("mo-theme"),e.style.setProperty("--mo-card-border-radius",t.cardBorderRadius),e.style.setProperty("--mo-avatar-size",t.avatarSize),e.style.setProperty("--mo-card-margin",t.cardMargin),e.style.setProperty("--mo-card-margin-inverted",t.cardMarginInverted),e.style.setProperty("--mo-card-margin-fullwidth",t.cardMarginFullWidth),t.animate){const s=t.animate===!0?"fade":t.animate;e.classList.add("mo-animate",`mo-animate-${s}`),this._observer=new IntersectionObserver(o=>{o.forEach(r=>{r.isIntersecting&&(r.target.classList.add("mo-visible"),this._observer.unobserve(r.target))})},{threshold:.1})}t.adSlots&&(t._adRealCount=0,typeof t.adSlots.onEnterViewport=="function"&&(this._adObserver=new IntersectionObserver(s=>{s.forEach(o=>{o.isIntersecting&&(this._adObserver.unobserve(o.target),t.adSlots.onEnterViewport(o.target,Number(o.target.dataset.moAdPosition)))})},{threshold:.5}))),this._initialized=!0,window.addEventListener("resize",this._resizeHandler),Array.from(e.children).length>0&&this._initItems()}refresh(){f.instances.forEach(e=>{const t=e.element,s=h.get(t);s&&(s.col=s.columnCount[w()],e._setDivider(),Array.from(t.children).forEach(o=>{e._setPostPosition(o)}))})}initNewItems(){this._initItems()}addItems(e){typeof e=="string"&&(e=JSON.parse(e)),e.forEach(t=>this.element.appendChild(this._createItemElement(t))),this._initItems()}insertItem(e,t){const s=this.element,o=this._getData();if(!o)return;const r=this._createItemElement(e),i=Array.from(s.children).filter(n=>n.classList.contains("js-mo-item")),a=t==null?Math.floor(Math.random()*(i.length+1)):Math.max(0,Math.min(t,i.length));if(a>=i.length?s.appendChild(r):s.insertBefore(r,i[a]),r.id||(r.id="moT"+crypto.randomUUID()+"_"+a),r.classList.add("mo-item","js-mo-item"),e.fullWidth)r.classList.add("mo-fullwidth","js-mo-fullwidth");else if(o.randomFullWidth){const n=o.randomFullWidth===!0?.33:o.randomFullWidth;Math.random()<n&&r.classList.add("mo-fullwidth","js-mo-fullwidth")}return o.showBadge&&this._createBadge(r,a+1),o.showArrow&&this._createArrow(r),o.showBadge&&o.showCounterStyle==="counter"&&Array.from(s.querySelectorAll(".js-mo-item")).forEach((n,c)=>{const d=n.querySelector(".js-mo-badge");d&&(d.textContent=c+1)}),o.lastItemIdx=Array.from(s.children).length,h.set(s,o),this.refresh(),this._observeItems([r]),r.querySelectorAll("img").forEach(n=>{n.complete||n.addEventListener("load",this._resizeHandler,{once:!0})}),r}destroy(){window.removeEventListener("resize",this._resizeHandler),this._observer&&(this._observer.disconnect(),this._observer=null),this._adObserver&&(this._adObserver.disconnect(),this._adObserver=null),Array.from(this.element.querySelectorAll(".mo-ad-slot")).forEach(e=>e.remove()),h.delete(this.element),f.instances.delete(this),this.element.style.removeProperty("--mo-card-border-radius"),this.element.style.removeProperty("--mo-avatar-size"),this.element.style.removeProperty("--mo-card-margin"),this.element.style.removeProperty("--mo-card-margin-inverted"),this.element.style.removeProperty("--mo-card-margin-fullwidth"),this.element.classList.remove("mo-timeline","mo-theme","mo-twocol","mo-animate","mo-animate-fade","mo-animate-slide"),Array.from(this.element.children).forEach(e=>{e.classList.remove("mo-item","js-mo-item","mo-inverted","js-mo-inverted","mo-offset","mo-fullwidth","js-mo-fullwidth","mo-visible"),e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach(t=>t.remove())})}_getData(){return h.get(this.element)}_setDivider(){const e=this._getData();e&&(e.col=e.columnCount[w()],this.element.classList.toggle("mo-twocol",e.col>1))}_initItems(){const e=this.element,t=this._getData();if(!t)return;const s=t.lastItemIdx,o=Array.from(e.children),r=o.slice(s);if(r.length!==0){if(r.forEach((i,a)=>{i.id||(i.id="moT"+crypto.randomUUID()+"_"+(a+s)),i.classList.add("mo-item","js-mo-item")}),this._setDivider(),t.randomFullWidth){const i=t.randomFullWidth===!0?.33:t.randomFullWidth;r.forEach(a=>{!a.classList.contains("mo-fullwidth")&&Math.random()<i&&a.classList.add("mo-fullwidth","js-mo-fullwidth")})}r.forEach((i,a)=>{t.showBadge&&this._createBadge(i,a+s+1),t.showArrow&&this._createArrow(i)}),t.lastItemIdx=o.length,h.set(e,t),this.refresh(),this._observeItems(r),this._injectAdSlots(r),r.forEach(i=>{i.querySelectorAll("img").forEach(a=>{a.complete||a.addEventListener("load",this._resizeHandler,{once:!0})})})}}_setPostPosition(e){if(e.classList.contains("mo-fullwidth")){e.classList.remove("mo-inverted","js-mo-inverted","mo-offset");return}const t=this._getLeftOrRight(e);t&&(e.classList.toggle("mo-inverted",t.lr>0),e.classList.toggle("js-mo-inverted",t.lr>0),e.classList.toggle("mo-offset",t.badge_offset>0))}_getLeftOrRight(e){if(!e)return null;const t=this._getData();if(!t)return null;const s=t.col,o=y(e,".js-mo-inverted")[0]||null,r=y(e,".js-mo-item:not(.js-mo-inverted)")[0]||null,i=p(r),a=p(o),n=p(e);let c=0,d=0;if(s>1){i.gppu>n.o+1&&(c=1),a.gppu>i.gppu&&(c=0);const m=e.previousElementSibling;m&&Math.abs(n.o-p(m).o)<40&&(d=1)}return{lr:c,badge_offset:d}}_createBadge(e,t){const s=this._getData(),o=document.createElement("span");if(o.className="mo-badge js-mo-badge",s.showCounterStyle==="none")o.style.opacity="0";else if(s.showCounterStyle==="image"){const r=document.createElement("img");r.className="mo-badge-icon",r.alt="",r.src=e.dataset.moIcon||A,o.appendChild(r)}else o.textContent=t;e.prepend(o)}_createItemElement(e){const t=document.createElement("li");e.icon&&(t.dataset.moIcon=e.icon);const s=document.createElement("div");s.className="mo-card";const o=this._getData();if(o&&typeof o.renderCard=="function")o.renderCard(e,s);else{if(e.banner){const i=document.createElement("div");i.className="mo-card-image";const a=document.createElement("img");if(a.className="mo-banner",a.src=e.banner,a.alt="",i.appendChild(a),e.avatar){const n=document.createElement("img");n.className="mo-avatar",n.src=e.avatar,n.alt="",i.appendChild(n)}s.appendChild(i)}const r=document.createElement("div");if(r.className="mo-card-body",e.title){const i=document.createElement("h3");i.textContent=e.title,r.appendChild(i)}if(e.meta){const i=document.createElement("p");i.className="mo-meta",i.textContent=e.meta,r.appendChild(i)}if(e.text){const i=document.createElement("p");i.textContent=e.text,r.appendChild(i)}s.appendChild(r)}return t.appendChild(s),t}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}_injectAdSlots(e){const t=this._getData();if(!t||!t.adSlots||!e.length)return;const{mode:s,interval:o,style:r}=t.adSlots,i=r==="fullwidth",a=this.element;let n=!1;if(s==="every_n")e.forEach((c,d)=>{if((t._adRealCount+d+1)%o===0){const m=this._createAdSlot(i);c.after(m),m.dataset.moAdPosition=String(Array.from(a.children).indexOf(m)),this._adObserver&&this._adObserver.observe(m),i&&(n=!0)}});else if(s==="random"){let c=t._adRealCount%o,d=0;for(;d<e.length;){const m=o-c,u=e.slice(d,d+m);if(u.length===m){const E=u[Math.floor(Math.random()*u.length)],g=this._createAdSlot(i);E.after(g),g.dataset.moAdPosition=String(Array.from(a.children).indexOf(g)),this._adObserver&&this._adObserver.observe(g),i&&(n=!0),c=0}else c+=u.length;d+=m}}t._adRealCount+=e.length,n&&this.refresh()}_createAdSlot(e){const t=document.createElement("li");return t.className="mo-ad-slot",e&&t.classList.add("mo-fullwidth"),t}_observeItems(e){this._observer&&e.forEach(t=>{t.classList.contains("mo-visible")||this._observer.observe(t)})}};_(f,"instances",new Set);let v=f;exports.MoTimeline=v;exports.default=v;
|
package/dist/moTimeline.css
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* moTimeline v2.
|
|
3
|
-
*/:root{--mo-line-color: #dde1e7;--mo-badge-bg: #4f46e5;--mo-badge-color: #fff;--mo-badge-size: 26px;--mo-badge-font-size: 12px;--mo-arrow-color: #dde1e7}.mo-timeline{display:block;list-style:none;margin:0;padding:0;position:relative;width:100%}.mo-timeline:after{content:"";display:table;clear:both}.mo-timeline.mo-twocol:before{background-color:var(--mo-line-color);bottom:0;content:"";left:50%;margin-left:-1.5px;position:absolute;top:0;width:3px;z-index:0}.mo-timeline>.mo-item{box-sizing:border-box;display:block;float:left;position:relative;width:50%}.mo-timeline:not(.mo-twocol)>.mo-item{float:none;width:100%}.mo-timeline>.mo-item.mo-inverted{float:right}.mo-timeline.mo-twocol>.mo-item.mo-fullwidth{clear:both;float:none;width:100%}.mo-theme>.mo-item.mo-fullwidth .mo-card{margin:var(--mo-card-margin-fullwidth, .5rem)}.mo-timeline.mo-twocol>.mo-item.mo-fullwidth .mo-badge,.mo-timeline.mo-twocol>.mo-item.mo-fullwidth .mo-arrow{display:none}.mo-badge{align-items:center;background:var(--mo-badge-bg);border-radius:50%;color:var(--mo-badge-color);display:flex;font-size:var(--mo-badge-font-size);font-weight:700;height:var(--mo-badge-size);justify-content:center;min-width:var(--mo-badge-size);overflow:hidden;position:absolute;top:18px;z-index:2}.mo-badge .mo-badge-icon{border-radius:50%;height:100%;object-fit:cover;width:100%}.mo-timeline.mo-twocol>.mo-item:not(.mo-inverted) .mo-badge{left:auto;right:calc(var(--mo-badge-size) / -2)}.mo-timeline.mo-twocol>.mo-item.mo-inverted .mo-badge{left:calc(var(--mo-badge-size) / -2);right:auto}.mo-timeline.mo-twocol>.mo-item.mo-offset .mo-badge{top:calc(18px + var(--mo-badge-size) + 10px)}.mo-timeline.mo-twocol>.mo-item.mo-offset .mo-arrow{top:calc(26px + var(--mo-badge-size) + 10px)}.mo-timeline:not(.mo-twocol)>.mo-item .mo-badge{display:none}.mo-arrow{border:8px solid transparent;display:block;height:0;position:absolute;top:26px;width:0;z-index:1}.mo-timeline.mo-twocol>.mo-item:not(.mo-inverted) .mo-arrow{border-left:8px solid var(--mo-arrow-color);border-right:none;left:auto;right:0}.mo-timeline.mo-twocol>.mo-item.mo-inverted .mo-arrow{border-right:8px solid var(--mo-arrow-color);border-left:none;left:0;right:auto}.mo-timeline:not(.mo-twocol)>.mo-item .mo-arrow{display:none}.mo-theme{--mo-arrow-color: #fff}.mo-theme>.mo-item .mo-card{background:#fff;border-radius:var(--mo-card-border-radius, 8px);box-shadow:0 2px 14px #0000001a;margin:var(--mo-card-margin, .5rem 1.25rem .5rem .5rem);position:relative}.mo-theme>.mo-item.mo-inverted .mo-card{margin:var(--mo-card-margin-inverted, .5rem .5rem .5rem 1.25rem)}.mo-theme>.mo-item .mo-banner{border-radius:var(--mo-card-border-radius, 8px) var(--mo-card-border-radius, 8px) 0 0;display:block;max-height:240px;object-fit:cover;width:100%}.mo-theme>.mo-item .mo-card-image{overflow:visible;position:relative}.mo-theme>.mo-item .mo-avatar{border:3px solid #fff;border-radius:50%;bottom:calc(var(--mo-avatar-size, 50px) * -.44);box-shadow:0 2px 8px #0000002e;height:var(--mo-avatar-size, 50px);object-fit:cover;position:absolute;right:14px;width:var(--mo-avatar-size, 50px);z-index:1}.mo-theme>.mo-item .mo-card-body{padding:1.75rem 1rem 1rem}.mo-theme>.mo-item .mo-card-body h3{font-size:1rem;font-weight:700;margin:0 0 .3rem}.mo-theme>.mo-item .mo-card-body .mo-meta{color:#9ca3af;font-size:.75rem;margin-bottom:.5rem}.mo-theme>.mo-item .mo-card-body p{color:#6b7280;font-size:.875rem;line-height:1.55;margin:0}.mo-theme.mo-twocol>.mo-item:not(.mo-inverted) .mo-arrow{border-left-color:var(--mo-arrow-color);right:12px}.mo-theme.mo-twocol>.mo-item.mo-inverted .mo-arrow{border-right-color:var(--mo-arrow-color);left:12px}.mo-theme .mo-badge{background:#fff;border:2px solid var(--mo-line-color);box-shadow:0 2px 6px #0000001a;color:#374151}.mo-timeline.mo-animate>.mo-item{transition:opacity var(--mo-animate-duration, .5s) ease,transform var(--mo-animate-duration, .5s) ease}.mo-timeline.mo-animate-fade>.mo-item{opacity:0}.mo-timeline.mo-animate-slide>.mo-item:not(.mo-inverted){opacity:0;transform:translate(-40px)}.mo-timeline.mo-animate-slide>.mo-item.mo-inverted{opacity:0;transform:translate(40px)}.mo-timeline:not(.mo-twocol).mo-animate-slide>.mo-item{transform:translate(-40px)}.mo-timeline.mo-animate>.mo-item.mo-visible{opacity:1;transform:translate(0)}
|
|
2
|
+
* moTimeline v2.11.0 — CSS
|
|
3
|
+
*/:root{--mo-line-color: #dde1e7;--mo-badge-bg: #4f46e5;--mo-badge-color: #fff;--mo-badge-size: 26px;--mo-badge-font-size: 12px;--mo-arrow-color: #dde1e7}.mo-timeline{display:block;list-style:none;margin:0;padding:0;position:relative;width:100%}.mo-timeline:after{content:"";display:table;clear:both}.mo-timeline.mo-twocol:before{background-color:var(--mo-line-color);bottom:0;content:"";left:50%;margin-left:-1.5px;position:absolute;top:0;width:3px;z-index:0}.mo-timeline>.mo-item{box-sizing:border-box;display:block;float:left;position:relative;width:50%}.mo-timeline:not(.mo-twocol)>.mo-item{float:none;width:100%}.mo-timeline>.mo-item.mo-inverted{float:right}.mo-timeline.mo-twocol>.mo-item.mo-fullwidth{clear:both;float:none;width:100%}.mo-theme>.mo-item.mo-fullwidth .mo-card{margin:var(--mo-card-margin-fullwidth, .5rem)}.mo-timeline.mo-twocol>.mo-item.mo-fullwidth .mo-badge,.mo-timeline.mo-twocol>.mo-item.mo-fullwidth .mo-arrow{display:none}.mo-badge{align-items:center;background:var(--mo-badge-bg);border-radius:50%;color:var(--mo-badge-color);display:flex;font-size:var(--mo-badge-font-size);font-weight:700;height:var(--mo-badge-size);justify-content:center;min-width:var(--mo-badge-size);overflow:hidden;position:absolute;top:18px;z-index:2}.mo-badge .mo-badge-icon{border-radius:50%;height:100%;object-fit:cover;width:100%}.mo-timeline.mo-twocol>.mo-item:not(.mo-inverted) .mo-badge{left:auto;right:calc(var(--mo-badge-size) / -2)}.mo-timeline.mo-twocol>.mo-item.mo-inverted .mo-badge{left:calc(var(--mo-badge-size) / -2);right:auto}.mo-timeline.mo-twocol>.mo-item.mo-offset .mo-badge{top:calc(18px + var(--mo-badge-size) + 10px)}.mo-timeline.mo-twocol>.mo-item.mo-offset .mo-arrow{top:calc(26px + var(--mo-badge-size) + 10px)}.mo-timeline:not(.mo-twocol)>.mo-item .mo-badge{display:none}.mo-arrow{border:8px solid transparent;display:block;height:0;position:absolute;top:26px;width:0;z-index:1}.mo-timeline.mo-twocol>.mo-item:not(.mo-inverted) .mo-arrow{border-left:8px solid var(--mo-arrow-color);border-right:none;left:auto;right:0}.mo-timeline.mo-twocol>.mo-item.mo-inverted .mo-arrow{border-right:8px solid var(--mo-arrow-color);border-left:none;left:0;right:auto}.mo-timeline:not(.mo-twocol)>.mo-item .mo-arrow{display:none}.mo-theme{--mo-arrow-color: #fff}.mo-theme>.mo-item .mo-card{background:#fff;border-radius:var(--mo-card-border-radius, 8px);box-shadow:0 2px 14px #0000001a;margin:var(--mo-card-margin, .5rem 1.25rem .5rem .5rem);position:relative}.mo-theme>.mo-item.mo-inverted .mo-card{margin:var(--mo-card-margin-inverted, .5rem .5rem .5rem 1.25rem)}.mo-theme>.mo-item .mo-banner{border-radius:var(--mo-card-border-radius, 8px) var(--mo-card-border-radius, 8px) 0 0;display:block;max-height:240px;object-fit:cover;width:100%}.mo-theme>.mo-item .mo-card-image{overflow:visible;position:relative}.mo-theme>.mo-item .mo-avatar{border:3px solid #fff;border-radius:50%;bottom:calc(var(--mo-avatar-size, 50px) * -.44);box-shadow:0 2px 8px #0000002e;height:var(--mo-avatar-size, 50px);object-fit:cover;position:absolute;right:14px;width:var(--mo-avatar-size, 50px);z-index:1}.mo-theme>.mo-item .mo-card-body{padding:1.75rem 1rem 1rem}.mo-theme>.mo-item .mo-card-body h3{font-size:1rem;font-weight:700;margin:0 0 .3rem}.mo-theme>.mo-item .mo-card-body .mo-meta{color:#9ca3af;font-size:.75rem;margin-bottom:.5rem}.mo-theme>.mo-item .mo-card-body p{color:#6b7280;font-size:.875rem;line-height:1.55;margin:0}.mo-theme.mo-twocol>.mo-item:not(.mo-inverted) .mo-arrow{border-left-color:var(--mo-arrow-color);right:12px}.mo-theme.mo-twocol>.mo-item.mo-inverted .mo-arrow{border-right-color:var(--mo-arrow-color);left:12px}.mo-theme .mo-badge{background:#fff;border:2px solid var(--mo-line-color);box-shadow:0 2px 6px #0000001a;color:#374151}.mo-timeline.mo-animate>.mo-item{transition:opacity var(--mo-animate-duration, .5s) ease,transform var(--mo-animate-duration, .5s) ease}.mo-timeline.mo-animate-fade>.mo-item{opacity:0}.mo-timeline.mo-animate-slide>.mo-item:not(.mo-inverted){opacity:0;transform:translate(-40px)}.mo-timeline.mo-animate-slide>.mo-item.mo-inverted{opacity:0;transform:translate(40px)}.mo-timeline:not(.mo-twocol).mo-animate-slide>.mo-item{transform:translate(-40px)}.mo-timeline.mo-animate>.mo-item.mo-visible{opacity:1;transform:translate(0)}.mo-timeline>.mo-item.mo-ad-slot{min-height:100px}
|
package/dist/moTimeline.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
1
|
+
var C = Object.defineProperty;
|
|
2
|
+
var A = (l, e, t) => e in l ? C(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
|
|
3
|
+
var v = (l, e, t) => A(l, typeof e != "symbol" ? e + "" : e, t);
|
|
4
4
|
/*!
|
|
5
|
-
* moTimeline v2.
|
|
5
|
+
* moTimeline v2.11.0
|
|
6
6
|
* Responsive two-column timeline layout library
|
|
7
7
|
* https://github.com/MattOpen/moTimeline
|
|
8
8
|
* MIT License
|
|
9
9
|
*/
|
|
10
|
-
const
|
|
10
|
+
const h = /* @__PURE__ */ new WeakMap(), _ = {
|
|
11
11
|
columnCount: { xs: 1, sm: 2, md: 2, lg: 2 },
|
|
12
12
|
showBadge: !1,
|
|
13
13
|
showArrow: !1,
|
|
@@ -21,59 +21,67 @@ const m = /* @__PURE__ */ new WeakMap(), p = {
|
|
|
21
21
|
cardMarginFullWidth: "0.5rem",
|
|
22
22
|
randomFullWidth: 0,
|
|
23
23
|
// 0 = off; 0–1 = probability per item; true = 0.33
|
|
24
|
-
animate: !1
|
|
24
|
+
animate: !1,
|
|
25
25
|
// false | 'fade' | 'slide'
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
renderCard: null,
|
|
27
|
+
// (item, cardEl) => void — custom card renderer; skips built-in HTML
|
|
28
|
+
adSlots: null
|
|
29
|
+
// { mode, interval, style, onEnterViewport } — see docs
|
|
30
|
+
}, I = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";
|
|
31
|
+
function w() {
|
|
32
|
+
const l = window.innerWidth;
|
|
33
|
+
return l < 600 ? "xs" : l < 992 ? "sm" : l < 1200 ? "md" : "lg";
|
|
30
34
|
}
|
|
31
|
-
function
|
|
35
|
+
function S(l, e = 100) {
|
|
32
36
|
let t;
|
|
33
|
-
return (...
|
|
34
|
-
clearTimeout(t), t = setTimeout(() =>
|
|
37
|
+
return (...s) => {
|
|
38
|
+
clearTimeout(t), t = setTimeout(() => l(...s), e);
|
|
35
39
|
};
|
|
36
40
|
}
|
|
37
|
-
function
|
|
38
|
-
return
|
|
39
|
-
o:
|
|
40
|
-
h:
|
|
41
|
-
gppu:
|
|
41
|
+
function p(l) {
|
|
42
|
+
return l ? {
|
|
43
|
+
o: l.offsetTop,
|
|
44
|
+
h: l.offsetHeight,
|
|
45
|
+
gppu: l.offsetTop + l.offsetHeight
|
|
42
46
|
} : { o: 0, h: 0, gppu: 0 };
|
|
43
47
|
}
|
|
44
|
-
function
|
|
48
|
+
function b(l, e) {
|
|
45
49
|
const t = [];
|
|
46
|
-
let
|
|
47
|
-
for (;
|
|
48
|
-
(!e ||
|
|
50
|
+
let s = l.previousElementSibling;
|
|
51
|
+
for (; s; )
|
|
52
|
+
(!e || s.matches(e)) && t.push(s), s = s.previousElementSibling;
|
|
49
53
|
return t;
|
|
50
54
|
}
|
|
51
|
-
const
|
|
55
|
+
const f = class f {
|
|
52
56
|
constructor(e, t = {}) {
|
|
53
57
|
if (typeof e == "string" && (e = document.querySelector(e)), !e) throw new Error("moTimeline: element not found");
|
|
54
|
-
this.element = e, this.settings = Object.assign({},
|
|
58
|
+
this.element = e, this.settings = Object.assign({}, _, t), this.settings.columnCount = Object.assign({}, _.columnCount, t.columnCount), this._resizeHandler = S(() => this.refresh(), 100), this._initialized = !1, this.init();
|
|
55
59
|
}
|
|
56
60
|
init() {
|
|
57
61
|
const e = this.element;
|
|
58
|
-
if (
|
|
62
|
+
if (h.has(e)) {
|
|
59
63
|
this.refresh();
|
|
60
64
|
return;
|
|
61
65
|
}
|
|
62
66
|
const t = Object.assign({}, this.settings, { lastItemIdx: 0 });
|
|
63
|
-
if (
|
|
64
|
-
const
|
|
65
|
-
e.classList.add("mo-animate", `mo-animate-${
|
|
66
|
-
o.forEach((
|
|
67
|
-
|
|
67
|
+
if (h.set(e, t), f.instances.add(this), e.classList.add("mo-timeline"), t.theme && e.classList.add("mo-theme"), e.style.setProperty("--mo-card-border-radius", t.cardBorderRadius), e.style.setProperty("--mo-avatar-size", t.avatarSize), e.style.setProperty("--mo-card-margin", t.cardMargin), e.style.setProperty("--mo-card-margin-inverted", t.cardMarginInverted), e.style.setProperty("--mo-card-margin-fullwidth", t.cardMarginFullWidth), t.animate) {
|
|
68
|
+
const s = t.animate === !0 ? "fade" : t.animate;
|
|
69
|
+
e.classList.add("mo-animate", `mo-animate-${s}`), this._observer = new IntersectionObserver((o) => {
|
|
70
|
+
o.forEach((r) => {
|
|
71
|
+
r.isIntersecting && (r.target.classList.add("mo-visible"), this._observer.unobserve(r.target));
|
|
68
72
|
});
|
|
69
73
|
}, { threshold: 0.1 });
|
|
70
74
|
}
|
|
71
|
-
|
|
75
|
+
t.adSlots && (t._adRealCount = 0, typeof t.adSlots.onEnterViewport == "function" && (this._adObserver = new IntersectionObserver((s) => {
|
|
76
|
+
s.forEach((o) => {
|
|
77
|
+
o.isIntersecting && (this._adObserver.unobserve(o.target), t.adSlots.onEnterViewport(o.target, Number(o.target.dataset.moAdPosition)));
|
|
78
|
+
});
|
|
79
|
+
}, { threshold: 0.5 }))), this._initialized = !0, window.addEventListener("resize", this._resizeHandler), Array.from(e.children).length > 0 && this._initItems();
|
|
72
80
|
}
|
|
73
81
|
refresh() {
|
|
74
|
-
|
|
75
|
-
const t = e.element,
|
|
76
|
-
|
|
82
|
+
f.instances.forEach((e) => {
|
|
83
|
+
const t = e.element, s = h.get(t);
|
|
84
|
+
s && (s.col = s.columnCount[w()], e._setDivider(), Array.from(t.children).forEach((o) => {
|
|
77
85
|
e._setPostPosition(o);
|
|
78
86
|
}));
|
|
79
87
|
});
|
|
@@ -101,53 +109,53 @@ const c = class c {
|
|
|
101
109
|
* @returns {HTMLElement} the inserted <li> element
|
|
102
110
|
*/
|
|
103
111
|
insertItem(e, t) {
|
|
104
|
-
const
|
|
112
|
+
const s = this.element, o = this._getData();
|
|
105
113
|
if (!o) return;
|
|
106
|
-
const
|
|
107
|
-
if (
|
|
108
|
-
|
|
114
|
+
const r = this._createItemElement(e), i = Array.from(s.children).filter((n) => n.classList.contains("js-mo-item")), a = t == null ? Math.floor(Math.random() * (i.length + 1)) : Math.max(0, Math.min(t, i.length));
|
|
115
|
+
if (a >= i.length ? s.appendChild(r) : s.insertBefore(r, i[a]), r.id || (r.id = "moT" + crypto.randomUUID() + "_" + a), r.classList.add("mo-item", "js-mo-item"), e.fullWidth)
|
|
116
|
+
r.classList.add("mo-fullwidth", "js-mo-fullwidth");
|
|
109
117
|
else if (o.randomFullWidth) {
|
|
110
|
-
const
|
|
111
|
-
Math.random() <
|
|
118
|
+
const n = o.randomFullWidth === !0 ? 0.33 : o.randomFullWidth;
|
|
119
|
+
Math.random() < n && r.classList.add("mo-fullwidth", "js-mo-fullwidth");
|
|
112
120
|
}
|
|
113
|
-
return o.showBadge && this._createBadge(
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
}), o.lastItemIdx = Array.from(
|
|
117
|
-
|
|
118
|
-
}),
|
|
121
|
+
return o.showBadge && this._createBadge(r, a + 1), o.showArrow && this._createArrow(r), o.showBadge && o.showCounterStyle === "counter" && Array.from(s.querySelectorAll(".js-mo-item")).forEach((n, c) => {
|
|
122
|
+
const d = n.querySelector(".js-mo-badge");
|
|
123
|
+
d && (d.textContent = c + 1);
|
|
124
|
+
}), o.lastItemIdx = Array.from(s.children).length, h.set(s, o), this.refresh(), this._observeItems([r]), r.querySelectorAll("img").forEach((n) => {
|
|
125
|
+
n.complete || n.addEventListener("load", this._resizeHandler, { once: !0 });
|
|
126
|
+
}), r;
|
|
119
127
|
}
|
|
120
128
|
destroy() {
|
|
121
|
-
window.removeEventListener("resize", this._resizeHandler), this._observer && (this._observer.disconnect(), this._observer = null),
|
|
129
|
+
window.removeEventListener("resize", this._resizeHandler), this._observer && (this._observer.disconnect(), this._observer = null), this._adObserver && (this._adObserver.disconnect(), this._adObserver = null), Array.from(this.element.querySelectorAll(".mo-ad-slot")).forEach((e) => e.remove()), h.delete(this.element), f.instances.delete(this), this.element.style.removeProperty("--mo-card-border-radius"), this.element.style.removeProperty("--mo-avatar-size"), this.element.style.removeProperty("--mo-card-margin"), this.element.style.removeProperty("--mo-card-margin-inverted"), this.element.style.removeProperty("--mo-card-margin-fullwidth"), this.element.classList.remove("mo-timeline", "mo-theme", "mo-twocol", "mo-animate", "mo-animate-fade", "mo-animate-slide"), Array.from(this.element.children).forEach((e) => {
|
|
122
130
|
e.classList.remove("mo-item", "js-mo-item", "mo-inverted", "js-mo-inverted", "mo-offset", "mo-fullwidth", "js-mo-fullwidth", "mo-visible"), e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach((t) => t.remove());
|
|
123
131
|
});
|
|
124
132
|
}
|
|
125
133
|
// ─── Private ────────────────────────────────────────────────────────────────
|
|
126
134
|
_getData() {
|
|
127
|
-
return
|
|
135
|
+
return h.get(this.element);
|
|
128
136
|
}
|
|
129
137
|
_setDivider() {
|
|
130
138
|
const e = this._getData();
|
|
131
|
-
e && (e.col = e.columnCount[
|
|
139
|
+
e && (e.col = e.columnCount[w()], this.element.classList.toggle("mo-twocol", e.col > 1));
|
|
132
140
|
}
|
|
133
141
|
_initItems() {
|
|
134
142
|
const e = this.element, t = this._getData();
|
|
135
143
|
if (!t) return;
|
|
136
|
-
const
|
|
137
|
-
if (
|
|
138
|
-
if (
|
|
139
|
-
i.id || (i.id = "moT" + crypto.randomUUID() + "_" + (
|
|
144
|
+
const s = t.lastItemIdx, o = Array.from(e.children), r = o.slice(s);
|
|
145
|
+
if (r.length !== 0) {
|
|
146
|
+
if (r.forEach((i, a) => {
|
|
147
|
+
i.id || (i.id = "moT" + crypto.randomUUID() + "_" + (a + s)), i.classList.add("mo-item", "js-mo-item");
|
|
140
148
|
}), this._setDivider(), t.randomFullWidth) {
|
|
141
149
|
const i = t.randomFullWidth === !0 ? 0.33 : t.randomFullWidth;
|
|
142
|
-
|
|
143
|
-
!
|
|
150
|
+
r.forEach((a) => {
|
|
151
|
+
!a.classList.contains("mo-fullwidth") && Math.random() < i && a.classList.add("mo-fullwidth", "js-mo-fullwidth");
|
|
144
152
|
});
|
|
145
153
|
}
|
|
146
|
-
|
|
147
|
-
t.showBadge && this._createBadge(i,
|
|
148
|
-
}), t.lastItemIdx = o.length,
|
|
149
|
-
i.querySelectorAll("img").forEach((
|
|
150
|
-
|
|
154
|
+
r.forEach((i, a) => {
|
|
155
|
+
t.showBadge && this._createBadge(i, a + s + 1), t.showArrow && this._createArrow(i);
|
|
156
|
+
}), t.lastItemIdx = o.length, h.set(e, t), this.refresh(), this._observeItems(r), this._injectAdSlots(r), r.forEach((i) => {
|
|
157
|
+
i.querySelectorAll("img").forEach((a) => {
|
|
158
|
+
a.complete || a.addEventListener("load", this._resizeHandler, { once: !0 });
|
|
151
159
|
});
|
|
152
160
|
});
|
|
153
161
|
}
|
|
@@ -164,22 +172,22 @@ const c = class c {
|
|
|
164
172
|
if (!e) return null;
|
|
165
173
|
const t = this._getData();
|
|
166
174
|
if (!t) return null;
|
|
167
|
-
const
|
|
168
|
-
let
|
|
169
|
-
if (
|
|
170
|
-
i.gppu >
|
|
171
|
-
const
|
|
172
|
-
|
|
175
|
+
const s = t.col, o = b(e, ".js-mo-inverted")[0] || null, r = b(e, ".js-mo-item:not(.js-mo-inverted)")[0] || null, i = p(r), a = p(o), n = p(e);
|
|
176
|
+
let c = 0, d = 0;
|
|
177
|
+
if (s > 1) {
|
|
178
|
+
i.gppu > n.o + 1 && (c = 1), a.gppu > i.gppu && (c = 0);
|
|
179
|
+
const m = e.previousElementSibling;
|
|
180
|
+
m && Math.abs(n.o - p(m).o) < 40 && (d = 1);
|
|
173
181
|
}
|
|
174
|
-
return { lr:
|
|
182
|
+
return { lr: c, badge_offset: d };
|
|
175
183
|
}
|
|
176
184
|
_createBadge(e, t) {
|
|
177
|
-
const
|
|
178
|
-
if (o.className = "mo-badge js-mo-badge",
|
|
185
|
+
const s = this._getData(), o = document.createElement("span");
|
|
186
|
+
if (o.className = "mo-badge js-mo-badge", s.showCounterStyle === "none")
|
|
179
187
|
o.style.opacity = "0";
|
|
180
|
-
else if (
|
|
181
|
-
const
|
|
182
|
-
|
|
188
|
+
else if (s.showCounterStyle === "image") {
|
|
189
|
+
const r = document.createElement("img");
|
|
190
|
+
r.className = "mo-badge-icon", r.alt = "", r.src = e.dataset.moIcon || I, o.appendChild(r);
|
|
183
191
|
} else
|
|
184
192
|
o.textContent = t;
|
|
185
193
|
e.prepend(o);
|
|
@@ -187,44 +195,81 @@ const c = class c {
|
|
|
187
195
|
_createItemElement(e) {
|
|
188
196
|
const t = document.createElement("li");
|
|
189
197
|
e.icon && (t.dataset.moIcon = e.icon);
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
+
const s = document.createElement("div");
|
|
199
|
+
s.className = "mo-card";
|
|
200
|
+
const o = this._getData();
|
|
201
|
+
if (o && typeof o.renderCard == "function")
|
|
202
|
+
o.renderCard(e, s);
|
|
203
|
+
else {
|
|
204
|
+
if (e.banner) {
|
|
205
|
+
const i = document.createElement("div");
|
|
206
|
+
i.className = "mo-card-image";
|
|
207
|
+
const a = document.createElement("img");
|
|
208
|
+
if (a.className = "mo-banner", a.src = e.banner, a.alt = "", i.appendChild(a), e.avatar) {
|
|
209
|
+
const n = document.createElement("img");
|
|
210
|
+
n.className = "mo-avatar", n.src = e.avatar, n.alt = "", i.appendChild(n);
|
|
211
|
+
}
|
|
212
|
+
s.appendChild(i);
|
|
198
213
|
}
|
|
199
|
-
r.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
s.
|
|
214
|
+
const r = document.createElement("div");
|
|
215
|
+
if (r.className = "mo-card-body", e.title) {
|
|
216
|
+
const i = document.createElement("h3");
|
|
217
|
+
i.textContent = e.title, r.appendChild(i);
|
|
218
|
+
}
|
|
219
|
+
if (e.meta) {
|
|
220
|
+
const i = document.createElement("p");
|
|
221
|
+
i.className = "mo-meta", i.textContent = e.meta, r.appendChild(i);
|
|
222
|
+
}
|
|
223
|
+
if (e.text) {
|
|
224
|
+
const i = document.createElement("p");
|
|
225
|
+
i.textContent = e.text, r.appendChild(i);
|
|
226
|
+
}
|
|
227
|
+
s.appendChild(r);
|
|
213
228
|
}
|
|
214
|
-
return
|
|
229
|
+
return t.appendChild(s), t;
|
|
215
230
|
}
|
|
216
231
|
_createArrow(e) {
|
|
217
232
|
const t = document.createElement("span");
|
|
218
233
|
t.className = "mo-arrow js-mo-arrow", e.prepend(t);
|
|
219
234
|
}
|
|
235
|
+
_injectAdSlots(e) {
|
|
236
|
+
const t = this._getData();
|
|
237
|
+
if (!t || !t.adSlots || !e.length) return;
|
|
238
|
+
const { mode: s, interval: o, style: r } = t.adSlots, i = r === "fullwidth", a = this.element;
|
|
239
|
+
let n = !1;
|
|
240
|
+
if (s === "every_n")
|
|
241
|
+
e.forEach((c, d) => {
|
|
242
|
+
if ((t._adRealCount + d + 1) % o === 0) {
|
|
243
|
+
const m = this._createAdSlot(i);
|
|
244
|
+
c.after(m), m.dataset.moAdPosition = String(Array.from(a.children).indexOf(m)), this._adObserver && this._adObserver.observe(m), i && (n = !0);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
else if (s === "random") {
|
|
248
|
+
let c = t._adRealCount % o, d = 0;
|
|
249
|
+
for (; d < e.length; ) {
|
|
250
|
+
const m = o - c, u = e.slice(d, d + m);
|
|
251
|
+
if (u.length === m) {
|
|
252
|
+
const E = u[Math.floor(Math.random() * u.length)], g = this._createAdSlot(i);
|
|
253
|
+
E.after(g), g.dataset.moAdPosition = String(Array.from(a.children).indexOf(g)), this._adObserver && this._adObserver.observe(g), i && (n = !0), c = 0;
|
|
254
|
+
} else
|
|
255
|
+
c += u.length;
|
|
256
|
+
d += m;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
t._adRealCount += e.length, n && this.refresh();
|
|
260
|
+
}
|
|
261
|
+
_createAdSlot(e) {
|
|
262
|
+
const t = document.createElement("li");
|
|
263
|
+
return t.className = "mo-ad-slot", e && t.classList.add("mo-fullwidth"), t;
|
|
264
|
+
}
|
|
220
265
|
_observeItems(e) {
|
|
221
266
|
this._observer && e.forEach((t) => {
|
|
222
267
|
t.classList.contains("mo-visible") || this._observer.observe(t);
|
|
223
268
|
});
|
|
224
269
|
}
|
|
225
270
|
};
|
|
226
|
-
|
|
227
|
-
let y =
|
|
271
|
+
v(f, "instances", /* @__PURE__ */ new Set());
|
|
272
|
+
let y = f;
|
|
228
273
|
export {
|
|
229
274
|
y as MoTimeline,
|
|
230
275
|
y as default
|
package/dist/moTimeline.umd.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(function(l
|
|
2
|
-
* moTimeline v2.
|
|
1
|
+
(function(d,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(d=typeof globalThis<"u"?globalThis:d||self,l(d.MoTimeline={}))})(this,function(d){"use strict";var I=Object.defineProperty;var L=(d,l,u)=>l in d?I(d,l,{enumerable:!0,configurable:!0,writable:!0,value:u}):d[l]=u;var E=(d,l,u)=>L(d,typeof l!="symbol"?l+"":l,u);/*!
|
|
2
|
+
* moTimeline v2.11.0
|
|
3
3
|
* Responsive two-column timeline layout library
|
|
4
4
|
* https://github.com/MattOpen/moTimeline
|
|
5
5
|
* MIT License
|
|
6
|
-
*/const
|
|
6
|
+
*/const l=new WeakMap,u={columnCount:{xs:1,sm:2,md:2,lg:2},showBadge:!1,showArrow:!1,theme:!1,showCounterStyle:"counter",cardBorderRadius:"8px",avatarSize:"50px",cardMargin:"0.5rem 1.25rem 0.5rem 0.5rem",cardMarginInverted:"0.5rem 0.5rem 0.5rem 1.25rem",cardMarginFullWidth:"0.5rem",randomFullWidth:0,animate:!1,renderCard:null,adSlots:null},C="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";function w(){const c=window.innerWidth;return c<600?"xs":c<992?"sm":c<1200?"md":"lg"}function S(c,e=100){let t;return(...s)=>{clearTimeout(t),t=setTimeout(()=>c(...s),e)}}function p(c){return c?{o:c.offsetTop,h:c.offsetHeight,gppu:c.offsetTop+c.offsetHeight}:{o:0,h:0,gppu:0}}function y(c,e){const t=[];let s=c.previousElementSibling;for(;s;)(!e||s.matches(e))&&t.push(s),s=s.previousElementSibling;return t}const g=class g{constructor(e,t={}){if(typeof e=="string"&&(e=document.querySelector(e)),!e)throw new Error("moTimeline: element not found");this.element=e,this.settings=Object.assign({},u,t),this.settings.columnCount=Object.assign({},u.columnCount,t.columnCount),this._resizeHandler=S(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(l.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});if(l.set(e,t),g.instances.add(this),e.classList.add("mo-timeline"),t.theme&&e.classList.add("mo-theme"),e.style.setProperty("--mo-card-border-radius",t.cardBorderRadius),e.style.setProperty("--mo-avatar-size",t.avatarSize),e.style.setProperty("--mo-card-margin",t.cardMargin),e.style.setProperty("--mo-card-margin-inverted",t.cardMarginInverted),e.style.setProperty("--mo-card-margin-fullwidth",t.cardMarginFullWidth),t.animate){const s=t.animate===!0?"fade":t.animate;e.classList.add("mo-animate",`mo-animate-${s}`),this._observer=new IntersectionObserver(o=>{o.forEach(r=>{r.isIntersecting&&(r.target.classList.add("mo-visible"),this._observer.unobserve(r.target))})},{threshold:.1})}t.adSlots&&(t._adRealCount=0,typeof t.adSlots.onEnterViewport=="function"&&(this._adObserver=new IntersectionObserver(s=>{s.forEach(o=>{o.isIntersecting&&(this._adObserver.unobserve(o.target),t.adSlots.onEnterViewport(o.target,Number(o.target.dataset.moAdPosition)))})},{threshold:.5}))),this._initialized=!0,window.addEventListener("resize",this._resizeHandler),Array.from(e.children).length>0&&this._initItems()}refresh(){g.instances.forEach(e=>{const t=e.element,s=l.get(t);s&&(s.col=s.columnCount[w()],e._setDivider(),Array.from(t.children).forEach(o=>{e._setPostPosition(o)}))})}initNewItems(){this._initItems()}addItems(e){typeof e=="string"&&(e=JSON.parse(e)),e.forEach(t=>this.element.appendChild(this._createItemElement(t))),this._initItems()}insertItem(e,t){const s=this.element,o=this._getData();if(!o)return;const r=this._createItemElement(e),i=Array.from(s.children).filter(a=>a.classList.contains("js-mo-item")),n=t==null?Math.floor(Math.random()*(i.length+1)):Math.max(0,Math.min(t,i.length));if(n>=i.length?s.appendChild(r):s.insertBefore(r,i[n]),r.id||(r.id="moT"+crypto.randomUUID()+"_"+n),r.classList.add("mo-item","js-mo-item"),e.fullWidth)r.classList.add("mo-fullwidth","js-mo-fullwidth");else if(o.randomFullWidth){const a=o.randomFullWidth===!0?.33:o.randomFullWidth;Math.random()<a&&r.classList.add("mo-fullwidth","js-mo-fullwidth")}return o.showBadge&&this._createBadge(r,n+1),o.showArrow&&this._createArrow(r),o.showBadge&&o.showCounterStyle==="counter"&&Array.from(s.querySelectorAll(".js-mo-item")).forEach((a,h)=>{const m=a.querySelector(".js-mo-badge");m&&(m.textContent=h+1)}),o.lastItemIdx=Array.from(s.children).length,l.set(s,o),this.refresh(),this._observeItems([r]),r.querySelectorAll("img").forEach(a=>{a.complete||a.addEventListener("load",this._resizeHandler,{once:!0})}),r}destroy(){window.removeEventListener("resize",this._resizeHandler),this._observer&&(this._observer.disconnect(),this._observer=null),this._adObserver&&(this._adObserver.disconnect(),this._adObserver=null),Array.from(this.element.querySelectorAll(".mo-ad-slot")).forEach(e=>e.remove()),l.delete(this.element),g.instances.delete(this),this.element.style.removeProperty("--mo-card-border-radius"),this.element.style.removeProperty("--mo-avatar-size"),this.element.style.removeProperty("--mo-card-margin"),this.element.style.removeProperty("--mo-card-margin-inverted"),this.element.style.removeProperty("--mo-card-margin-fullwidth"),this.element.classList.remove("mo-timeline","mo-theme","mo-twocol","mo-animate","mo-animate-fade","mo-animate-slide"),Array.from(this.element.children).forEach(e=>{e.classList.remove("mo-item","js-mo-item","mo-inverted","js-mo-inverted","mo-offset","mo-fullwidth","js-mo-fullwidth","mo-visible"),e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach(t=>t.remove())})}_getData(){return l.get(this.element)}_setDivider(){const e=this._getData();e&&(e.col=e.columnCount[w()],this.element.classList.toggle("mo-twocol",e.col>1))}_initItems(){const e=this.element,t=this._getData();if(!t)return;const s=t.lastItemIdx,o=Array.from(e.children),r=o.slice(s);if(r.length!==0){if(r.forEach((i,n)=>{i.id||(i.id="moT"+crypto.randomUUID()+"_"+(n+s)),i.classList.add("mo-item","js-mo-item")}),this._setDivider(),t.randomFullWidth){const i=t.randomFullWidth===!0?.33:t.randomFullWidth;r.forEach(n=>{!n.classList.contains("mo-fullwidth")&&Math.random()<i&&n.classList.add("mo-fullwidth","js-mo-fullwidth")})}r.forEach((i,n)=>{t.showBadge&&this._createBadge(i,n+s+1),t.showArrow&&this._createArrow(i)}),t.lastItemIdx=o.length,l.set(e,t),this.refresh(),this._observeItems(r),this._injectAdSlots(r),r.forEach(i=>{i.querySelectorAll("img").forEach(n=>{n.complete||n.addEventListener("load",this._resizeHandler,{once:!0})})})}}_setPostPosition(e){if(e.classList.contains("mo-fullwidth")){e.classList.remove("mo-inverted","js-mo-inverted","mo-offset");return}const t=this._getLeftOrRight(e);t&&(e.classList.toggle("mo-inverted",t.lr>0),e.classList.toggle("js-mo-inverted",t.lr>0),e.classList.toggle("mo-offset",t.badge_offset>0))}_getLeftOrRight(e){if(!e)return null;const t=this._getData();if(!t)return null;const s=t.col,o=y(e,".js-mo-inverted")[0]||null,r=y(e,".js-mo-item:not(.js-mo-inverted)")[0]||null,i=p(r),n=p(o),a=p(e);let h=0,m=0;if(s>1){i.gppu>a.o+1&&(h=1),n.gppu>i.gppu&&(h=0);const f=e.previousElementSibling;f&&Math.abs(a.o-p(f).o)<40&&(m=1)}return{lr:h,badge_offset:m}}_createBadge(e,t){const s=this._getData(),o=document.createElement("span");if(o.className="mo-badge js-mo-badge",s.showCounterStyle==="none")o.style.opacity="0";else if(s.showCounterStyle==="image"){const r=document.createElement("img");r.className="mo-badge-icon",r.alt="",r.src=e.dataset.moIcon||C,o.appendChild(r)}else o.textContent=t;e.prepend(o)}_createItemElement(e){const t=document.createElement("li");e.icon&&(t.dataset.moIcon=e.icon);const s=document.createElement("div");s.className="mo-card";const o=this._getData();if(o&&typeof o.renderCard=="function")o.renderCard(e,s);else{if(e.banner){const i=document.createElement("div");i.className="mo-card-image";const n=document.createElement("img");if(n.className="mo-banner",n.src=e.banner,n.alt="",i.appendChild(n),e.avatar){const a=document.createElement("img");a.className="mo-avatar",a.src=e.avatar,a.alt="",i.appendChild(a)}s.appendChild(i)}const r=document.createElement("div");if(r.className="mo-card-body",e.title){const i=document.createElement("h3");i.textContent=e.title,r.appendChild(i)}if(e.meta){const i=document.createElement("p");i.className="mo-meta",i.textContent=e.meta,r.appendChild(i)}if(e.text){const i=document.createElement("p");i.textContent=e.text,r.appendChild(i)}s.appendChild(r)}return t.appendChild(s),t}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}_injectAdSlots(e){const t=this._getData();if(!t||!t.adSlots||!e.length)return;const{mode:s,interval:o,style:r}=t.adSlots,i=r==="fullwidth",n=this.element;let a=!1;if(s==="every_n")e.forEach((h,m)=>{if((t._adRealCount+m+1)%o===0){const f=this._createAdSlot(i);h.after(f),f.dataset.moAdPosition=String(Array.from(n.children).indexOf(f)),this._adObserver&&this._adObserver.observe(f),i&&(a=!0)}});else if(s==="random"){let h=t._adRealCount%o,m=0;for(;m<e.length;){const f=o-h,_=e.slice(m,m+f);if(_.length===f){const A=_[Math.floor(Math.random()*_.length)],b=this._createAdSlot(i);A.after(b),b.dataset.moAdPosition=String(Array.from(n.children).indexOf(b)),this._adObserver&&this._adObserver.observe(b),i&&(a=!0),h=0}else h+=_.length;m+=f}}t._adRealCount+=e.length,a&&this.refresh()}_createAdSlot(e){const t=document.createElement("li");return t.className="mo-ad-slot",e&&t.classList.add("mo-fullwidth"),t}_observeItems(e){this._observer&&e.forEach(t=>{t.classList.contains("mo-visible")||this._observer.observe(t)})}};E(g,"instances",new Set);let v=g;d.MoTimeline=v,d.default=v,Object.defineProperties(d,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
package/package.json
CHANGED
package/src/moTimeline.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* moTimeline v2.
|
|
2
|
+
* moTimeline v2.11.0 — CSS
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/* ── CSS custom properties (easy override) ─────────────────── */
|
|
@@ -299,3 +299,12 @@
|
|
|
299
299
|
opacity: 1;
|
|
300
300
|
transform: translateX(0);
|
|
301
301
|
}
|
|
302
|
+
|
|
303
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
304
|
+
AD SLOTS — injected by adSlots option
|
|
305
|
+
═══════════════════════════════════════════════════════════════ */
|
|
306
|
+
|
|
307
|
+
/* Minimum height so IntersectionObserver can fire before content loads */
|
|
308
|
+
.mo-timeline > .mo-item.mo-ad-slot {
|
|
309
|
+
min-height: 100px;
|
|
310
|
+
}
|
package/src/moTimeline.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* moTimeline v2.
|
|
2
|
+
* moTimeline v2.11.0
|
|
3
3
|
* Responsive two-column timeline layout library
|
|
4
4
|
* https://github.com/MattOpen/moTimeline
|
|
5
5
|
* MIT License
|
|
@@ -23,6 +23,8 @@ const DEFAULTS = {
|
|
|
23
23
|
cardMarginFullWidth: '0.5rem',
|
|
24
24
|
randomFullWidth: 0, // 0 = off; 0–1 = probability per item; true = 0.33
|
|
25
25
|
animate: false, // false | 'fade' | 'slide'
|
|
26
|
+
renderCard: null, // (item, cardEl) => void — custom card renderer; skips built-in HTML
|
|
27
|
+
adSlots: null, // { mode, interval, style, onEnterViewport } — see docs
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
const DEFAULT_BADGE_ICON = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";
|
|
@@ -114,6 +116,20 @@ export class MoTimeline {
|
|
|
114
116
|
}, { threshold: 0.1 });
|
|
115
117
|
}
|
|
116
118
|
|
|
119
|
+
if (data.adSlots) {
|
|
120
|
+
data._adRealCount = 0;
|
|
121
|
+
if (typeof data.adSlots.onEnterViewport === 'function') {
|
|
122
|
+
this._adObserver = new IntersectionObserver((entries) => {
|
|
123
|
+
entries.forEach((entry) => {
|
|
124
|
+
if (entry.isIntersecting) {
|
|
125
|
+
this._adObserver.unobserve(entry.target);
|
|
126
|
+
data.adSlots.onEnterViewport(entry.target, Number(entry.target.dataset.moAdPosition));
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}, { threshold: 0.5 });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
117
133
|
this._initialized = true;
|
|
118
134
|
window.addEventListener('resize', this._resizeHandler);
|
|
119
135
|
|
|
@@ -225,6 +241,11 @@ export class MoTimeline {
|
|
|
225
241
|
this._observer.disconnect();
|
|
226
242
|
this._observer = null;
|
|
227
243
|
}
|
|
244
|
+
if (this._adObserver) {
|
|
245
|
+
this._adObserver.disconnect();
|
|
246
|
+
this._adObserver = null;
|
|
247
|
+
}
|
|
248
|
+
Array.from(this.element.querySelectorAll('.mo-ad-slot')).forEach((s) => s.remove());
|
|
228
249
|
instanceData.delete(this.element);
|
|
229
250
|
MoTimeline.instances.delete(this);
|
|
230
251
|
this.element.style.removeProperty('--mo-card-border-radius');
|
|
@@ -299,6 +320,7 @@ export class MoTimeline {
|
|
|
299
320
|
this.refresh();
|
|
300
321
|
|
|
301
322
|
this._observeItems(newItems);
|
|
323
|
+
this._injectAdSlots(newItems);
|
|
302
324
|
|
|
303
325
|
// Re-layout after any unloaded images finish, because offsetHeight is
|
|
304
326
|
// based on text-only height until images are ready.
|
|
@@ -382,43 +404,49 @@ export class MoTimeline {
|
|
|
382
404
|
const card = document.createElement('div');
|
|
383
405
|
card.className = 'mo-card';
|
|
384
406
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
banner
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
avatar
|
|
398
|
-
|
|
407
|
+
const data = this._getData();
|
|
408
|
+
if (data && typeof data.renderCard === 'function') {
|
|
409
|
+
data.renderCard(item, card);
|
|
410
|
+
} else {
|
|
411
|
+
if (item.banner) {
|
|
412
|
+
const wrap = document.createElement('div');
|
|
413
|
+
wrap.className = 'mo-card-image';
|
|
414
|
+
const banner = document.createElement('img');
|
|
415
|
+
banner.className = 'mo-banner';
|
|
416
|
+
banner.src = item.banner;
|
|
417
|
+
banner.alt = '';
|
|
418
|
+
wrap.appendChild(banner);
|
|
419
|
+
if (item.avatar) {
|
|
420
|
+
const avatar = document.createElement('img');
|
|
421
|
+
avatar.className = 'mo-avatar';
|
|
422
|
+
avatar.src = item.avatar;
|
|
423
|
+
avatar.alt = '';
|
|
424
|
+
wrap.appendChild(avatar);
|
|
425
|
+
}
|
|
426
|
+
card.appendChild(wrap);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const body = document.createElement('div');
|
|
430
|
+
body.className = 'mo-card-body';
|
|
431
|
+
if (item.title) {
|
|
432
|
+
const h = document.createElement('h3');
|
|
433
|
+
h.textContent = item.title;
|
|
434
|
+
body.appendChild(h);
|
|
435
|
+
}
|
|
436
|
+
if (item.meta) {
|
|
437
|
+
const m = document.createElement('p');
|
|
438
|
+
m.className = 'mo-meta';
|
|
439
|
+
m.textContent = item.meta;
|
|
440
|
+
body.appendChild(m);
|
|
441
|
+
}
|
|
442
|
+
if (item.text) {
|
|
443
|
+
const p = document.createElement('p');
|
|
444
|
+
p.textContent = item.text;
|
|
445
|
+
body.appendChild(p);
|
|
399
446
|
}
|
|
400
|
-
card.appendChild(
|
|
447
|
+
card.appendChild(body);
|
|
401
448
|
}
|
|
402
449
|
|
|
403
|
-
const body = document.createElement('div');
|
|
404
|
-
body.className = 'mo-card-body';
|
|
405
|
-
if (item.title) {
|
|
406
|
-
const h = document.createElement('h3');
|
|
407
|
-
h.textContent = item.title;
|
|
408
|
-
body.appendChild(h);
|
|
409
|
-
}
|
|
410
|
-
if (item.meta) {
|
|
411
|
-
const m = document.createElement('p');
|
|
412
|
-
m.className = 'mo-meta';
|
|
413
|
-
m.textContent = item.meta;
|
|
414
|
-
body.appendChild(m);
|
|
415
|
-
}
|
|
416
|
-
if (item.text) {
|
|
417
|
-
const p = document.createElement('p');
|
|
418
|
-
p.textContent = item.text;
|
|
419
|
-
body.appendChild(p);
|
|
420
|
-
}
|
|
421
|
-
card.appendChild(body);
|
|
422
450
|
li.appendChild(card);
|
|
423
451
|
return li;
|
|
424
452
|
}
|
|
@@ -429,6 +457,57 @@ export class MoTimeline {
|
|
|
429
457
|
el.prepend(span);
|
|
430
458
|
}
|
|
431
459
|
|
|
460
|
+
_injectAdSlots(newItems) {
|
|
461
|
+
const data = this._getData();
|
|
462
|
+
if (!data || !data.adSlots || !newItems.length) return;
|
|
463
|
+
|
|
464
|
+
const { mode, interval, style } = data.adSlots;
|
|
465
|
+
const fullWidth = style === 'fullwidth';
|
|
466
|
+
const el = this.element;
|
|
467
|
+
let needsRefresh = false;
|
|
468
|
+
|
|
469
|
+
if (mode === 'every_n') {
|
|
470
|
+
newItems.forEach((item, i) => {
|
|
471
|
+
if ((data._adRealCount + i + 1) % interval === 0) {
|
|
472
|
+
const slot = this._createAdSlot(fullWidth);
|
|
473
|
+
item.after(slot);
|
|
474
|
+
slot.dataset.moAdPosition = String(Array.from(el.children).indexOf(slot));
|
|
475
|
+
if (this._adObserver) this._adObserver.observe(slot);
|
|
476
|
+
if (fullWidth) needsRefresh = true;
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
} else if (mode === 'random') {
|
|
480
|
+
let pageOffset = data._adRealCount % interval;
|
|
481
|
+
let i = 0;
|
|
482
|
+
while (i < newItems.length) {
|
|
483
|
+
const remaining = interval - pageOffset;
|
|
484
|
+
const chunk = newItems.slice(i, i + remaining);
|
|
485
|
+
if (chunk.length === remaining) {
|
|
486
|
+
const anchor = chunk[Math.floor(Math.random() * chunk.length)];
|
|
487
|
+
const slot = this._createAdSlot(fullWidth);
|
|
488
|
+
anchor.after(slot);
|
|
489
|
+
slot.dataset.moAdPosition = String(Array.from(el.children).indexOf(slot));
|
|
490
|
+
if (this._adObserver) this._adObserver.observe(slot);
|
|
491
|
+
if (fullWidth) needsRefresh = true;
|
|
492
|
+
pageOffset = 0;
|
|
493
|
+
} else {
|
|
494
|
+
pageOffset += chunk.length;
|
|
495
|
+
}
|
|
496
|
+
i += remaining;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
data._adRealCount += newItems.length;
|
|
501
|
+
if (needsRefresh) this.refresh();
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
_createAdSlot(fullWidth) {
|
|
505
|
+
const slot = document.createElement('li');
|
|
506
|
+
slot.className = 'mo-ad-slot';
|
|
507
|
+
if (fullWidth) slot.classList.add('mo-fullwidth');
|
|
508
|
+
return slot;
|
|
509
|
+
}
|
|
510
|
+
|
|
432
511
|
_observeItems(items) {
|
|
433
512
|
if (!this._observer) return;
|
|
434
513
|
items.forEach((item) => {
|