motimeline 2.10.0 → 2.12.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 +56 -0
- package/dist/moTimeline.cjs +3 -3
- package/dist/moTimeline.css +2 -2
- package/dist/moTimeline.js +145 -103
- package/dist/moTimeline.umd.js +3 -3
- package/package.json +1 -1
- package/src/moTimeline.css +10 -1
- package/src/moTimeline.js +93 -1
package/README.md
CHANGED
|
@@ -20,6 +20,8 @@ Responsive two-column timeline layout library — plain JavaScript, zero depende
|
|
|
20
20
|
- **Optional theme** — built-in card theme with image banners and overlapping avatars
|
|
21
21
|
- **CSS custom properties** — override colors and sizes with one line of CSS
|
|
22
22
|
- **Dynamic items** — append, insert, or inject `<li>` elements at any time via `initNewItems()`, `addItems()`, or `insertItem()`
|
|
23
|
+
- **Custom card renderer** — pass `renderCard(item, cardEl)` to inject any HTML, vanilla JS, or full React components into each card slot; the library handles everything else
|
|
24
|
+
- **Publisher-ready ad slots** — the most publisher-friendly timeline on npm: `adSlots` injects viewport-triggered `<li>` placeholders at configurable cadences (`every_n` or `random`), fires `onEnterViewport` exactly once per slot at ≥ 50% visibility, works seamlessly with infinite scroll, and cleans up on `destroy()`. Drop in AdSense, house ads, or any network with three lines of code.
|
|
23
25
|
- **Bootstrap compatible** — wrap the `<ul>` in a Bootstrap `.container`, no config needed
|
|
24
26
|
- **ESM · CJS · UMD** — works with any bundler or as a plain `<script>` tag
|
|
25
27
|
|
|
@@ -146,6 +148,7 @@ The library injects classes and elements into your markup. Here is what a fully
|
|
|
146
148
|
| `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>`. |
|
|
147
149
|
| `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
150
|
| `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. |
|
|
151
|
+
| `adSlots` | object \| null | `null` | Inject ad slot placeholders into the timeline and observe them. See **Ad slots** below. |
|
|
149
152
|
|
|
150
153
|
---
|
|
151
154
|
|
|
@@ -189,6 +192,7 @@ tl.refresh(); // re-layout all items (called automatically on resi
|
|
|
189
192
|
tl.initNewItems(); // pick up manually appended <li> elements
|
|
190
193
|
tl.addItems(items); // create and append <li> from an array of item objects (or JSON string)
|
|
191
194
|
tl.insertItem(item, index); // insert a single item at a specific index (or random if omitted)
|
|
195
|
+
tl.clear(); // remove all items and ad slots, reset counters — instance stays alive
|
|
192
196
|
tl.destroy(); // remove listeners and reset DOM classes
|
|
193
197
|
```
|
|
194
198
|
|
|
@@ -326,6 +330,52 @@ export default function App() {
|
|
|
326
330
|
|
|
327
331
|
---
|
|
328
332
|
|
|
333
|
+
## Ad slots
|
|
334
|
+
|
|
335
|
+
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.
|
|
336
|
+
|
|
337
|
+
```js
|
|
338
|
+
const tl = new MoTimeline('#my-timeline', {
|
|
339
|
+
adSlots: {
|
|
340
|
+
mode: 'every_n', // 'every_n' | 'random'
|
|
341
|
+
interval: 10, // every_n: inject after every N real items
|
|
342
|
+
// random: inject once at a random position per N-item page
|
|
343
|
+
style: 'card', // 'card' | 'fullwidth'
|
|
344
|
+
onEnterViewport: (slotEl, position) => {
|
|
345
|
+
// slotEl = the <li class="mo-ad-slot"> element
|
|
346
|
+
// position = its 0-based index in the container at injection time
|
|
347
|
+
const ins = document.createElement('ins');
|
|
348
|
+
ins.className = 'adsbygoogle';
|
|
349
|
+
ins.style.display = 'block';
|
|
350
|
+
ins.dataset.adClient = 'ca-pub-XXXXXXXXXXXXXXXX';
|
|
351
|
+
ins.dataset.adSlot = '1234567890';
|
|
352
|
+
ins.dataset.adFormat = 'auto';
|
|
353
|
+
slotEl.appendChild(ins);
|
|
354
|
+
(window.adsbygoogle = window.adsbygoogle || []).push({});
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### `adSlots` option shape
|
|
361
|
+
|
|
362
|
+
| Property | Type | Description |
|
|
363
|
+
|---|---|---|
|
|
364
|
+
| `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. |
|
|
365
|
+
| `interval` | number | Cadence for slot injection (see `mode`). |
|
|
366
|
+
| `style` | `'card' \| 'fullwidth'` | `'card'` — slot sits in the normal left/right column flow. `'fullwidth'` — slot spans both columns (adds `mo-fullwidth`). |
|
|
367
|
+
| `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. |
|
|
368
|
+
|
|
369
|
+
**What the library provides:**
|
|
370
|
+
- A `<li class="mo-ad-slot">` element with `min-height: 100px` (so the observer can detect it before content loads)
|
|
371
|
+
- `fullwidth` layout via the existing `mo-fullwidth` mechanism when `style: 'fullwidth'`
|
|
372
|
+
- Exactly-once `IntersectionObserver` (threshold 0.5) per slot
|
|
373
|
+
- Automatic slot cleanup on `tl.destroy()`
|
|
374
|
+
|
|
375
|
+
**What you provide:** everything inside the slot — the ad creative, network scripts, markup.
|
|
376
|
+
|
|
377
|
+
Slots are injected after each `addItems()` call, so they work seamlessly with infinite scroll.
|
|
378
|
+
|
|
329
379
|
## Infinite scroll recipe
|
|
330
380
|
|
|
331
381
|
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.
|
|
@@ -418,6 +468,12 @@ No framework option needed. Wrap the `<ul>` inside a Bootstrap `.container`:
|
|
|
418
468
|
|
|
419
469
|
## Changelog
|
|
420
470
|
|
|
471
|
+
### v2.12.0
|
|
472
|
+
- New method `clear()` — removes all `.mo-item` and `.mo-ad-slot` elements from the container and resets internal counters (`lastItemIdx`, `_adRealCount`) without destroying the instance. Active `IntersectionObserver`s are disconnected but kept alive so they re-observe items added by the next `addItems()` call. Use this in React wrappers to reinitialize timeline content when props change without recreating the instance.
|
|
473
|
+
|
|
474
|
+
### v2.11.0
|
|
475
|
+
- 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.
|
|
476
|
+
|
|
421
477
|
### v2.10.0
|
|
422
478
|
- 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(...)`.
|
|
423
479
|
|
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.12.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 v(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}clear(){const e=this._getData();e&&(this._observer&&this._observer.disconnect(),this._adObserver&&this._adObserver.disconnect(),Array.from(this.element.children).forEach(t=>{(t.classList.contains("js-mo-item")||t.classList.contains("mo-ad-slot"))&&t.remove()}),e.lastItemIdx=0,e.adSlots&&(e._adRealCount=0))}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=v(r),a=v(o),n=v(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-v(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 p=f;exports.MoTimeline=p;exports.default=p;
|
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.12.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 p = (l, e, t) => A(l, typeof e != "symbol" ? e + "" : e, t);
|
|
4
4
|
/*!
|
|
5
|
-
* moTimeline v2.
|
|
5
|
+
* moTimeline v2.12.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,
|
|
@@ -23,60 +23,66 @@ const m = /* @__PURE__ */ new WeakMap(), p = {
|
|
|
23
23
|
// 0 = off; 0–1 = probability per item; true = 0.33
|
|
24
24
|
animate: !1,
|
|
25
25
|
// false | 'fade' | 'slide'
|
|
26
|
-
renderCard: null
|
|
26
|
+
renderCard: null,
|
|
27
27
|
// (item, cardEl) => void — custom card renderer; skips built-in HTML
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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 b() {
|
|
32
|
+
const l = window.innerWidth;
|
|
33
|
+
return l < 600 ? "xs" : l < 992 ? "sm" : l < 1200 ? "md" : "lg";
|
|
32
34
|
}
|
|
33
|
-
function
|
|
35
|
+
function S(l, e = 100) {
|
|
34
36
|
let t;
|
|
35
|
-
return (...
|
|
36
|
-
clearTimeout(t), t = setTimeout(() =>
|
|
37
|
+
return (...s) => {
|
|
38
|
+
clearTimeout(t), t = setTimeout(() => l(...s), e);
|
|
37
39
|
};
|
|
38
40
|
}
|
|
39
|
-
function
|
|
40
|
-
return
|
|
41
|
-
o:
|
|
42
|
-
h:
|
|
43
|
-
gppu:
|
|
41
|
+
function v(l) {
|
|
42
|
+
return l ? {
|
|
43
|
+
o: l.offsetTop,
|
|
44
|
+
h: l.offsetHeight,
|
|
45
|
+
gppu: l.offsetTop + l.offsetHeight
|
|
44
46
|
} : { o: 0, h: 0, gppu: 0 };
|
|
45
47
|
}
|
|
46
|
-
function w(
|
|
48
|
+
function w(l, e) {
|
|
47
49
|
const t = [];
|
|
48
|
-
let
|
|
49
|
-
for (;
|
|
50
|
-
(!e ||
|
|
50
|
+
let s = l.previousElementSibling;
|
|
51
|
+
for (; s; )
|
|
52
|
+
(!e || s.matches(e)) && t.push(s), s = s.previousElementSibling;
|
|
51
53
|
return t;
|
|
52
54
|
}
|
|
53
|
-
const
|
|
55
|
+
const f = class f {
|
|
54
56
|
constructor(e, t = {}) {
|
|
55
57
|
if (typeof e == "string" && (e = document.querySelector(e)), !e) throw new Error("moTimeline: element not found");
|
|
56
|
-
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();
|
|
57
59
|
}
|
|
58
60
|
init() {
|
|
59
61
|
const e = this.element;
|
|
60
|
-
if (
|
|
62
|
+
if (h.has(e)) {
|
|
61
63
|
this.refresh();
|
|
62
64
|
return;
|
|
63
65
|
}
|
|
64
66
|
const t = Object.assign({}, this.settings, { lastItemIdx: 0 });
|
|
65
|
-
if (
|
|
66
|
-
const
|
|
67
|
-
e.classList.add("mo-animate", `mo-animate-${
|
|
68
|
-
|
|
69
|
-
|
|
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));
|
|
70
72
|
});
|
|
71
73
|
}, { threshold: 0.1 });
|
|
72
74
|
}
|
|
73
|
-
|
|
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();
|
|
74
80
|
}
|
|
75
81
|
refresh() {
|
|
76
|
-
|
|
77
|
-
const t = e.element,
|
|
78
|
-
|
|
79
|
-
e._setPostPosition(
|
|
82
|
+
f.instances.forEach((e) => {
|
|
83
|
+
const t = e.element, s = h.get(t);
|
|
84
|
+
s && (s.col = s.columnCount[b()], e._setDivider(), Array.from(t.children).forEach((o) => {
|
|
85
|
+
e._setPostPosition(o);
|
|
80
86
|
}));
|
|
81
87
|
});
|
|
82
88
|
}
|
|
@@ -103,53 +109,59 @@ const d = class d {
|
|
|
103
109
|
* @returns {HTMLElement} the inserted <li> element
|
|
104
110
|
*/
|
|
105
111
|
insertItem(e, t) {
|
|
106
|
-
const
|
|
107
|
-
if (!
|
|
108
|
-
const
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
else if (
|
|
112
|
-
const
|
|
113
|
-
Math.random() <
|
|
112
|
+
const s = this.element, o = this._getData();
|
|
113
|
+
if (!o) return;
|
|
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");
|
|
117
|
+
else if (o.randomFullWidth) {
|
|
118
|
+
const n = o.randomFullWidth === !0 ? 0.33 : o.randomFullWidth;
|
|
119
|
+
Math.random() < n && r.classList.add("mo-fullwidth", "js-mo-fullwidth");
|
|
114
120
|
}
|
|
115
|
-
return
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
}),
|
|
119
|
-
|
|
120
|
-
}),
|
|
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;
|
|
127
|
+
}
|
|
128
|
+
clear() {
|
|
129
|
+
const e = this._getData();
|
|
130
|
+
e && (this._observer && this._observer.disconnect(), this._adObserver && this._adObserver.disconnect(), Array.from(this.element.children).forEach((t) => {
|
|
131
|
+
(t.classList.contains("js-mo-item") || t.classList.contains("mo-ad-slot")) && t.remove();
|
|
132
|
+
}), e.lastItemIdx = 0, e.adSlots && (e._adRealCount = 0));
|
|
121
133
|
}
|
|
122
134
|
destroy() {
|
|
123
|
-
window.removeEventListener("resize", this._resizeHandler), this._observer && (this._observer.disconnect(), this._observer = null),
|
|
135
|
+
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) => {
|
|
124
136
|
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());
|
|
125
137
|
});
|
|
126
138
|
}
|
|
127
139
|
// ─── Private ────────────────────────────────────────────────────────────────
|
|
128
140
|
_getData() {
|
|
129
|
-
return
|
|
141
|
+
return h.get(this.element);
|
|
130
142
|
}
|
|
131
143
|
_setDivider() {
|
|
132
144
|
const e = this._getData();
|
|
133
|
-
e && (e.col = e.columnCount[
|
|
145
|
+
e && (e.col = e.columnCount[b()], this.element.classList.toggle("mo-twocol", e.col > 1));
|
|
134
146
|
}
|
|
135
147
|
_initItems() {
|
|
136
148
|
const e = this.element, t = this._getData();
|
|
137
149
|
if (!t) return;
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
140
|
-
if (
|
|
141
|
-
|
|
150
|
+
const s = t.lastItemIdx, o = Array.from(e.children), r = o.slice(s);
|
|
151
|
+
if (r.length !== 0) {
|
|
152
|
+
if (r.forEach((i, a) => {
|
|
153
|
+
i.id || (i.id = "moT" + crypto.randomUUID() + "_" + (a + s)), i.classList.add("mo-item", "js-mo-item");
|
|
142
154
|
}), this._setDivider(), t.randomFullWidth) {
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
!
|
|
155
|
+
const i = t.randomFullWidth === !0 ? 0.33 : t.randomFullWidth;
|
|
156
|
+
r.forEach((a) => {
|
|
157
|
+
!a.classList.contains("mo-fullwidth") && Math.random() < i && a.classList.add("mo-fullwidth", "js-mo-fullwidth");
|
|
146
158
|
});
|
|
147
159
|
}
|
|
148
|
-
|
|
149
|
-
t.showBadge && this._createBadge(
|
|
150
|
-
}), t.lastItemIdx =
|
|
151
|
-
|
|
152
|
-
|
|
160
|
+
r.forEach((i, a) => {
|
|
161
|
+
t.showBadge && this._createBadge(i, a + s + 1), t.showArrow && this._createArrow(i);
|
|
162
|
+
}), t.lastItemIdx = o.length, h.set(e, t), this.refresh(), this._observeItems(r), this._injectAdSlots(r), r.forEach((i) => {
|
|
163
|
+
i.querySelectorAll("img").forEach((a) => {
|
|
164
|
+
a.complete || a.addEventListener("load", this._resizeHandler, { once: !0 });
|
|
153
165
|
});
|
|
154
166
|
});
|
|
155
167
|
}
|
|
@@ -166,74 +178,104 @@ const d = class d {
|
|
|
166
178
|
if (!e) return null;
|
|
167
179
|
const t = this._getData();
|
|
168
180
|
if (!t) return null;
|
|
169
|
-
const
|
|
170
|
-
let c = 0,
|
|
171
|
-
if (
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
181
|
+
const s = t.col, o = w(e, ".js-mo-inverted")[0] || null, r = w(e, ".js-mo-item:not(.js-mo-inverted)")[0] || null, i = v(r), a = v(o), n = v(e);
|
|
182
|
+
let c = 0, d = 0;
|
|
183
|
+
if (s > 1) {
|
|
184
|
+
i.gppu > n.o + 1 && (c = 1), a.gppu > i.gppu && (c = 0);
|
|
185
|
+
const m = e.previousElementSibling;
|
|
186
|
+
m && Math.abs(n.o - v(m).o) < 40 && (d = 1);
|
|
175
187
|
}
|
|
176
|
-
return { lr: c, badge_offset:
|
|
188
|
+
return { lr: c, badge_offset: d };
|
|
177
189
|
}
|
|
178
190
|
_createBadge(e, t) {
|
|
179
|
-
const
|
|
180
|
-
if (
|
|
181
|
-
|
|
182
|
-
else if (
|
|
183
|
-
const
|
|
184
|
-
|
|
191
|
+
const s = this._getData(), o = document.createElement("span");
|
|
192
|
+
if (o.className = "mo-badge js-mo-badge", s.showCounterStyle === "none")
|
|
193
|
+
o.style.opacity = "0";
|
|
194
|
+
else if (s.showCounterStyle === "image") {
|
|
195
|
+
const r = document.createElement("img");
|
|
196
|
+
r.className = "mo-badge-icon", r.alt = "", r.src = e.dataset.moIcon || I, o.appendChild(r);
|
|
185
197
|
} else
|
|
186
|
-
|
|
187
|
-
e.prepend(
|
|
198
|
+
o.textContent = t;
|
|
199
|
+
e.prepend(o);
|
|
188
200
|
}
|
|
189
201
|
_createItemElement(e) {
|
|
190
202
|
const t = document.createElement("li");
|
|
191
203
|
e.icon && (t.dataset.moIcon = e.icon);
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
if (
|
|
196
|
-
|
|
204
|
+
const s = document.createElement("div");
|
|
205
|
+
s.className = "mo-card";
|
|
206
|
+
const o = this._getData();
|
|
207
|
+
if (o && typeof o.renderCard == "function")
|
|
208
|
+
o.renderCard(e, s);
|
|
197
209
|
else {
|
|
198
210
|
if (e.banner) {
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
if (
|
|
203
|
-
const
|
|
204
|
-
|
|
211
|
+
const i = document.createElement("div");
|
|
212
|
+
i.className = "mo-card-image";
|
|
213
|
+
const a = document.createElement("img");
|
|
214
|
+
if (a.className = "mo-banner", a.src = e.banner, a.alt = "", i.appendChild(a), e.avatar) {
|
|
215
|
+
const n = document.createElement("img");
|
|
216
|
+
n.className = "mo-avatar", n.src = e.avatar, n.alt = "", i.appendChild(n);
|
|
205
217
|
}
|
|
206
|
-
|
|
218
|
+
s.appendChild(i);
|
|
207
219
|
}
|
|
208
|
-
const
|
|
209
|
-
if (
|
|
210
|
-
const
|
|
211
|
-
|
|
220
|
+
const r = document.createElement("div");
|
|
221
|
+
if (r.className = "mo-card-body", e.title) {
|
|
222
|
+
const i = document.createElement("h3");
|
|
223
|
+
i.textContent = e.title, r.appendChild(i);
|
|
212
224
|
}
|
|
213
225
|
if (e.meta) {
|
|
214
|
-
const
|
|
215
|
-
|
|
226
|
+
const i = document.createElement("p");
|
|
227
|
+
i.className = "mo-meta", i.textContent = e.meta, r.appendChild(i);
|
|
216
228
|
}
|
|
217
229
|
if (e.text) {
|
|
218
|
-
const
|
|
219
|
-
|
|
230
|
+
const i = document.createElement("p");
|
|
231
|
+
i.textContent = e.text, r.appendChild(i);
|
|
220
232
|
}
|
|
221
|
-
|
|
233
|
+
s.appendChild(r);
|
|
222
234
|
}
|
|
223
|
-
return t.appendChild(
|
|
235
|
+
return t.appendChild(s), t;
|
|
224
236
|
}
|
|
225
237
|
_createArrow(e) {
|
|
226
238
|
const t = document.createElement("span");
|
|
227
239
|
t.className = "mo-arrow js-mo-arrow", e.prepend(t);
|
|
228
240
|
}
|
|
241
|
+
_injectAdSlots(e) {
|
|
242
|
+
const t = this._getData();
|
|
243
|
+
if (!t || !t.adSlots || !e.length) return;
|
|
244
|
+
const { mode: s, interval: o, style: r } = t.adSlots, i = r === "fullwidth", a = this.element;
|
|
245
|
+
let n = !1;
|
|
246
|
+
if (s === "every_n")
|
|
247
|
+
e.forEach((c, d) => {
|
|
248
|
+
if ((t._adRealCount + d + 1) % o === 0) {
|
|
249
|
+
const m = this._createAdSlot(i);
|
|
250
|
+
c.after(m), m.dataset.moAdPosition = String(Array.from(a.children).indexOf(m)), this._adObserver && this._adObserver.observe(m), i && (n = !0);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
else if (s === "random") {
|
|
254
|
+
let c = t._adRealCount % o, d = 0;
|
|
255
|
+
for (; d < e.length; ) {
|
|
256
|
+
const m = o - c, u = e.slice(d, d + m);
|
|
257
|
+
if (u.length === m) {
|
|
258
|
+
const E = u[Math.floor(Math.random() * u.length)], g = this._createAdSlot(i);
|
|
259
|
+
E.after(g), g.dataset.moAdPosition = String(Array.from(a.children).indexOf(g)), this._adObserver && this._adObserver.observe(g), i && (n = !0), c = 0;
|
|
260
|
+
} else
|
|
261
|
+
c += u.length;
|
|
262
|
+
d += m;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
t._adRealCount += e.length, n && this.refresh();
|
|
266
|
+
}
|
|
267
|
+
_createAdSlot(e) {
|
|
268
|
+
const t = document.createElement("li");
|
|
269
|
+
return t.className = "mo-ad-slot", e && t.classList.add("mo-fullwidth"), t;
|
|
270
|
+
}
|
|
229
271
|
_observeItems(e) {
|
|
230
272
|
this._observer && e.forEach((t) => {
|
|
231
273
|
t.classList.contains("mo-visible") || this._observer.observe(t);
|
|
232
274
|
});
|
|
233
275
|
}
|
|
234
276
|
};
|
|
235
|
-
|
|
236
|
-
let y =
|
|
277
|
+
p(f, "instances", /* @__PURE__ */ new Set());
|
|
278
|
+
let y = f;
|
|
237
279
|
export {
|
|
238
280
|
y as MoTimeline,
|
|
239
281
|
y as default
|
package/dist/moTimeline.umd.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(function(d,
|
|
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.12.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}clear(){const e=this._getData();e&&(this._observer&&this._observer.disconnect(),this._adObserver&&this._adObserver.disconnect(),Array.from(this.element.children).forEach(t=>{(t.classList.contains("js-mo-item")||t.classList.contains("mo-ad-slot"))&&t.remove()}),e.lastItemIdx=0,e.adSlots&&(e._adRealCount=0))}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.12.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.12.0
|
|
3
3
|
* Responsive two-column timeline layout library
|
|
4
4
|
* https://github.com/MattOpen/moTimeline
|
|
5
5
|
* MIT License
|
|
@@ -24,6 +24,7 @@ const DEFAULTS = {
|
|
|
24
24
|
randomFullWidth: 0, // 0 = off; 0–1 = probability per item; true = 0.33
|
|
25
25
|
animate: false, // false | 'fade' | 'slide'
|
|
26
26
|
renderCard: null, // (item, cardEl) => void — custom card renderer; skips built-in HTML
|
|
27
|
+
adSlots: null, // { mode, interval, style, onEnterViewport } — see docs
|
|
27
28
|
};
|
|
28
29
|
|
|
29
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>";
|
|
@@ -115,6 +116,20 @@ export class MoTimeline {
|
|
|
115
116
|
}, { threshold: 0.1 });
|
|
116
117
|
}
|
|
117
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
|
+
|
|
118
133
|
this._initialized = true;
|
|
119
134
|
window.addEventListener('resize', this._resizeHandler);
|
|
120
135
|
|
|
@@ -220,12 +235,37 @@ export class MoTimeline {
|
|
|
220
235
|
return newEl;
|
|
221
236
|
}
|
|
222
237
|
|
|
238
|
+
clear() {
|
|
239
|
+
const data = this._getData();
|
|
240
|
+
if (!data) return;
|
|
241
|
+
|
|
242
|
+
// Disconnect observers — they remain alive and will re-observe new items
|
|
243
|
+
if (this._observer) this._observer.disconnect();
|
|
244
|
+
if (this._adObserver) this._adObserver.disconnect();
|
|
245
|
+
|
|
246
|
+
// Remove all library-managed elements (real items + ad slots)
|
|
247
|
+
Array.from(this.element.children).forEach((child) => {
|
|
248
|
+
if (child.classList.contains('js-mo-item') || child.classList.contains('mo-ad-slot')) {
|
|
249
|
+
child.remove();
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Reset counters — ready for a fresh addItems() call
|
|
254
|
+
data.lastItemIdx = 0;
|
|
255
|
+
if (data.adSlots) data._adRealCount = 0;
|
|
256
|
+
}
|
|
257
|
+
|
|
223
258
|
destroy() {
|
|
224
259
|
window.removeEventListener('resize', this._resizeHandler);
|
|
225
260
|
if (this._observer) {
|
|
226
261
|
this._observer.disconnect();
|
|
227
262
|
this._observer = null;
|
|
228
263
|
}
|
|
264
|
+
if (this._adObserver) {
|
|
265
|
+
this._adObserver.disconnect();
|
|
266
|
+
this._adObserver = null;
|
|
267
|
+
}
|
|
268
|
+
Array.from(this.element.querySelectorAll('.mo-ad-slot')).forEach((s) => s.remove());
|
|
229
269
|
instanceData.delete(this.element);
|
|
230
270
|
MoTimeline.instances.delete(this);
|
|
231
271
|
this.element.style.removeProperty('--mo-card-border-radius');
|
|
@@ -300,6 +340,7 @@ export class MoTimeline {
|
|
|
300
340
|
this.refresh();
|
|
301
341
|
|
|
302
342
|
this._observeItems(newItems);
|
|
343
|
+
this._injectAdSlots(newItems);
|
|
303
344
|
|
|
304
345
|
// Re-layout after any unloaded images finish, because offsetHeight is
|
|
305
346
|
// based on text-only height until images are ready.
|
|
@@ -436,6 +477,57 @@ export class MoTimeline {
|
|
|
436
477
|
el.prepend(span);
|
|
437
478
|
}
|
|
438
479
|
|
|
480
|
+
_injectAdSlots(newItems) {
|
|
481
|
+
const data = this._getData();
|
|
482
|
+
if (!data || !data.adSlots || !newItems.length) return;
|
|
483
|
+
|
|
484
|
+
const { mode, interval, style } = data.adSlots;
|
|
485
|
+
const fullWidth = style === 'fullwidth';
|
|
486
|
+
const el = this.element;
|
|
487
|
+
let needsRefresh = false;
|
|
488
|
+
|
|
489
|
+
if (mode === 'every_n') {
|
|
490
|
+
newItems.forEach((item, i) => {
|
|
491
|
+
if ((data._adRealCount + i + 1) % interval === 0) {
|
|
492
|
+
const slot = this._createAdSlot(fullWidth);
|
|
493
|
+
item.after(slot);
|
|
494
|
+
slot.dataset.moAdPosition = String(Array.from(el.children).indexOf(slot));
|
|
495
|
+
if (this._adObserver) this._adObserver.observe(slot);
|
|
496
|
+
if (fullWidth) needsRefresh = true;
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
} else if (mode === 'random') {
|
|
500
|
+
let pageOffset = data._adRealCount % interval;
|
|
501
|
+
let i = 0;
|
|
502
|
+
while (i < newItems.length) {
|
|
503
|
+
const remaining = interval - pageOffset;
|
|
504
|
+
const chunk = newItems.slice(i, i + remaining);
|
|
505
|
+
if (chunk.length === remaining) {
|
|
506
|
+
const anchor = chunk[Math.floor(Math.random() * chunk.length)];
|
|
507
|
+
const slot = this._createAdSlot(fullWidth);
|
|
508
|
+
anchor.after(slot);
|
|
509
|
+
slot.dataset.moAdPosition = String(Array.from(el.children).indexOf(slot));
|
|
510
|
+
if (this._adObserver) this._adObserver.observe(slot);
|
|
511
|
+
if (fullWidth) needsRefresh = true;
|
|
512
|
+
pageOffset = 0;
|
|
513
|
+
} else {
|
|
514
|
+
pageOffset += chunk.length;
|
|
515
|
+
}
|
|
516
|
+
i += remaining;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
data._adRealCount += newItems.length;
|
|
521
|
+
if (needsRefresh) this.refresh();
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
_createAdSlot(fullWidth) {
|
|
525
|
+
const slot = document.createElement('li');
|
|
526
|
+
slot.className = 'mo-ad-slot';
|
|
527
|
+
if (fullWidth) slot.classList.add('mo-fullwidth');
|
|
528
|
+
return slot;
|
|
529
|
+
}
|
|
530
|
+
|
|
439
531
|
_observeItems(items) {
|
|
440
532
|
if (!this._observer) return;
|
|
441
533
|
items.forEach((item) => {
|