nodebb-plugin-ezoic-infinite 0.5.3 → 0.5.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/public/client.js +51 -40
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "Ezoic ads with infinite scroll using a pool of placeholder IDs",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/public/client.js CHANGED
@@ -1,6 +1,8 @@
1
1
  /* globals ajaxify */
2
2
  'use strict';
3
3
 
4
+ window.ezoicInfiniteLoaded = true;
5
+
4
6
  let cachedConfig;
5
7
  let lastFetch = 0;
6
8
  let debounceTimer;
@@ -22,14 +24,30 @@ function parsePool(raw) {
22
24
  ));
23
25
  }
24
26
 
27
+ /**
28
+ * Harmony: the real post wrapper is usually [component="post"][data-pid]
29
+ * We must avoid counting nested nodes like component="post/parent" or other elements
30
+ * that can also carry data-pid in some setups.
31
+ */
25
32
  function getTopicPosts() {
26
- const $p = $('[component="post"]').not('.ezoic-ad-post');
27
- if ($p.length) return $p;
33
+ const $primary = $('[component="post"][data-pid]');
34
+ if ($primary.length) return $primary.not('.ezoic-ad-post');
35
+
36
+ // Fallback: top-level nodes with data-pid that contain the post content,
37
+ // excluding nodes nested inside another data-pid container.
38
+ const $top = $('[data-pid]').filter(function () {
39
+ const $el = $(this);
40
+ const hasContent = $el.find('[component="post/content"]').length > 0;
41
+ const nested = $el.parents('[data-pid]').length > 0;
42
+ return hasContent && !nested;
43
+ });
44
+ if ($top.length) return $top.not('.ezoic-ad-post');
45
+
28
46
  return $('.posts .post').not('.ezoic-ad-post');
29
47
  }
30
48
 
31
- function isLi($el) {
32
- return ($el && $el.length && (($el.prop('tagName') || '').toUpperCase() === 'LI'));
49
+ function tagName($el) {
50
+ return ($el && $el.length ? (($el.prop('tagName') || '').toUpperCase()) : '');
33
51
  }
34
52
 
35
53
  function removePlaceholdersByPool(pool) {
@@ -42,43 +60,25 @@ function removeAdWrappers() {
42
60
  }
43
61
 
44
62
  function computeWindowSlots(totalItems, interval, poolSize) {
63
+ // totalItems posts -> number of ad slots at positions interval, 2*interval, ...
45
64
  const slots = Math.floor(totalItems / interval);
46
65
  if (slots <= 0) return [];
66
+
67
+ // IMPORTANT:
68
+ // We cannot display more than poolSize ads at once because Ezoic placeholder IDs
69
+ // must be unique on the page. If slots > poolSize, we only render the latest poolSize slots.
47
70
  const start = Math.max(1, slots - poolSize + 1);
48
71
  const out = [];
49
72
  for (let s = start; s <= slots; s++) out.push(s);
50
73
  return out;
51
74
  }
52
75
 
53
- function makeBetweenWrapper($targetPost, placeholderId) {
54
- if (isLi($targetPost)) {
55
- return (
56
- '<li class="ezoic-ad-between list-unstyled" data-ezoic-ad="1">' +
57
- '<div id="ezoic-pub-ad-placeholder-' + placeholderId + '"></div>' +
58
- '</li>'
59
- );
60
- }
61
- return '<div class="ezoic-ad-between" id="ezoic-pub-ad-placeholder-' + placeholderId + '"></div>';
62
- }
63
-
64
- function makeAdMessageWrapper($targetPost, placeholderId) {
65
- if (isLi($targetPost)) {
66
- return (
67
- '<li class="post ezoic-ad-post" data-ezoic-ad="1">' +
68
- '<div class="content">' +
69
- '<div id="ezoic-pub-ad-placeholder-' + placeholderId + '"></div>' +
70
- '</div>' +
71
- '</li>'
72
- );
76
+ function makeWrapperLike($target, classes, innerHtml) {
77
+ const t = tagName($target);
78
+ if (t === 'LI') {
79
+ return '<li class="' + classes + ' list-unstyled" data-ezoic-ad="1">' + innerHtml + '</li>';
73
80
  }
74
-
75
- return (
76
- '<div class="post ezoic-ad-post" data-ezoic-ad="1">' +
77
- '<div class="content">' +
78
- '<div id="ezoic-pub-ad-placeholder-' + placeholderId + '"></div>' +
79
- '</div>' +
80
- '</div>'
81
- );
81
+ return '<div class="' + classes + '" data-ezoic-ad="1">' + innerHtml + '</div>';
82
82
  }
83
83
 
84
84
  function insertBetweenPosts($posts, pool, interval) {
@@ -89,12 +89,13 @@ function insertBetweenPosts($posts, pool, interval) {
89
89
  const activeIds = [];
90
90
  for (let i = 0; i < slotsToRender.length; i++) {
91
91
  const slotNumber = slotsToRender[i];
92
- const id = pool[i];
93
- const index = slotNumber * interval - 1;
92
+ const id = pool[i]; // map latest slots to pool in order
93
+ const index = slotNumber * interval - 1; // 0-based index of the post after which we insert
94
94
  const $target = $posts.eq(index);
95
95
  if (!$target.length) continue;
96
96
 
97
- $target.after(makeBetweenWrapper($target, id));
97
+ const html = makeWrapperLike($target, 'ezoic-ad-between', '<div id="ezoic-pub-ad-placeholder-' + id + '"></div>');
98
+ $target.after(html);
98
99
  activeIds.push(id);
99
100
  }
100
101
  return activeIds;
@@ -113,14 +114,17 @@ function insertAdMessagesBetweenReplies($posts, pool, interval) {
113
114
  const $target = $posts.eq(index);
114
115
  if (!$target.length) continue;
115
116
 
116
- $target.after(makeAdMessageWrapper($target, id));
117
+ const inner = '<div class="content"><div id="ezoic-pub-ad-placeholder-' + id + '"></div></div>';
118
+ const html = makeWrapperLike($target, 'post ezoic-ad-post', inner);
119
+ $target.after(html);
117
120
  activeIds.push(id);
118
121
  }
119
122
  return activeIds;
120
123
  }
121
124
 
122
125
  async function refreshAds() {
123
- const cfg = await fetchConfig();
126
+ let cfg;
127
+ try { cfg = await fetchConfig(); } catch (e) { return; }
124
128
  if (!cfg || cfg.excluded) return;
125
129
 
126
130
  const betweenPool = parsePool(cfg.placeholderIds);
@@ -132,6 +136,7 @@ async function refreshAds() {
132
136
  const $posts = getTopicPosts();
133
137
  if (!$posts.length) return;
134
138
 
139
+ // Clean first
135
140
  removeAdWrappers();
136
141
  removePlaceholdersByPool(betweenPool);
137
142
  removePlaceholdersByPool(messagePool);
@@ -146,18 +151,24 @@ async function refreshAds() {
146
151
  activeIds.push(...insertAdMessagesBetweenReplies($posts, messagePool, messageInterval));
147
152
  }
148
153
 
154
+ // Ezoic render
149
155
  if (activeIds.length && window.ezstandalone && typeof window.ezstandalone.destroyPlaceholders === 'function') {
150
156
  try { window.ezstandalone.destroyPlaceholders(); } catch (e) {}
151
157
  }
152
158
  activeIds.forEach(id => {
153
- try { window.ezstandalone && typeof window.ezstandalone.showAds === 'function' && window.ezstandalone.showAds(id); } catch (e) {}
159
+ try {
160
+ if (window.ezstandalone && typeof window.ezstandalone.showAds === 'function') {
161
+ window.ezstandalone.showAds(id);
162
+ }
163
+ } catch (e) {}
154
164
  });
155
165
  }
156
166
 
157
167
  function debounceRefresh() {
158
168
  clearTimeout(debounceTimer);
159
- debounceTimer = setTimeout(refreshAds, 100);
169
+ debounceTimer = setTimeout(refreshAds, 150);
160
170
  }
161
171
 
172
+ $(document).ready(debounceRefresh);
162
173
  $(window).on('action:ajaxify.end action:posts.loaded action:topic.loaded', debounceRefresh);
163
- setTimeout(debounceRefresh, 800);
174
+ setTimeout(debounceRefresh, 1500);