nodebb-plugin-facebook-post 1.0.28 → 1.0.30
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/library.js +3 -43
- package/package.json +1 -1
- package/static/lib/composer.js +30 -100
package/library.js
CHANGED
|
@@ -14,7 +14,6 @@ const DEFAULT_SETTINGS = {
|
|
|
14
14
|
categoriesWhitelist: '',
|
|
15
15
|
minimumReputation: 0,
|
|
16
16
|
maxImages: 4,
|
|
17
|
-
enablePlaceTagging: true,
|
|
18
17
|
};
|
|
19
18
|
|
|
20
19
|
function bool(v) {
|
|
@@ -51,7 +50,6 @@ async function loadSettings() {
|
|
|
51
50
|
settings.excerptMaxLen = int(settings.excerptMaxLen, DEFAULT_SETTINGS.excerptMaxLen);
|
|
52
51
|
settings.minimumReputation = int(settings.minimumReputation, 0);
|
|
53
52
|
settings.maxImages = int(settings.maxImages, DEFAULT_SETTINGS.maxImages);
|
|
54
|
-
settings.enablePlaceTagging = bool(settings.enablePlaceTagging);
|
|
55
53
|
settings.categoriesWhitelist = trimStr(settings.categoriesWhitelist);
|
|
56
54
|
|
|
57
55
|
const env = readEnv();
|
|
@@ -192,14 +190,13 @@ async function uploadPhotoToFacebook(urlAbs) {
|
|
|
192
190
|
return resp.data && resp.data.id;
|
|
193
191
|
}
|
|
194
192
|
|
|
195
|
-
async function publishFeedPost({ message, link, photoIds
|
|
193
|
+
async function publishFeedPost({ message, link, photoIds }) {
|
|
196
194
|
const endpoint = `https://graph.facebook.com/${settings.fbGraphVersion}/${settings.fbPageId}/feed`;
|
|
197
195
|
|
|
198
196
|
const form = new URLSearchParams();
|
|
199
197
|
form.append('message', String(message || ''));
|
|
200
198
|
form.append('access_token', String(settings.fbPageAccessToken));
|
|
201
199
|
if (link) form.append('link', String(link));
|
|
202
|
-
if (placeId) form.append('place', String(placeId));
|
|
203
200
|
if (Array.isArray(photoIds) && photoIds.length) {
|
|
204
201
|
photoIds.forEach((id, idx) => {
|
|
205
202
|
form.append(`attached_media[${idx}]`, JSON.stringify({ media_fbid: id }));
|
|
@@ -225,8 +222,6 @@ async function postToFacebook(ctx) {
|
|
|
225
222
|
.filter(isForumHosted)
|
|
226
223
|
.slice(0, Math.max(0, settings.maxImages));
|
|
227
224
|
|
|
228
|
-
const placeId = (settings.enablePlaceTagging && trimStr(ctx.post.fbPlaceId)) || null;
|
|
229
|
-
|
|
230
225
|
const lines = [`\uD83D\uDCDD ${topicTitle}`];
|
|
231
226
|
if (excerpt) lines.push(excerpt);
|
|
232
227
|
lines.push(`\uD83D\uDD17 ${link}`);
|
|
@@ -240,7 +235,7 @@ async function postToFacebook(ctx) {
|
|
|
240
235
|
if (id) photoIds.push(id);
|
|
241
236
|
}
|
|
242
237
|
|
|
243
|
-
return publishFeedPost({ message, link, photoIds
|
|
238
|
+
return publishFeedPost({ message, link, photoIds });
|
|
244
239
|
}
|
|
245
240
|
|
|
246
241
|
const Plugin = {};
|
|
@@ -294,42 +289,7 @@ Plugin.init = async function (params) {
|
|
|
294
289
|
}
|
|
295
290
|
});
|
|
296
291
|
|
|
297
|
-
|
|
298
|
-
const winston = require.main.require('winston');
|
|
299
|
-
res.set('Cache-Control', 'no-store');
|
|
300
|
-
try {
|
|
301
|
-
await loadSettings();
|
|
302
|
-
if (!settings.fbPageAccessToken) return res.json({ results: [] });
|
|
303
|
-
const q = trimStr(req.query.q);
|
|
304
|
-
if (q.length < 2) return res.json({ results: [] });
|
|
305
|
-
|
|
306
|
-
const resp = await axios.get(
|
|
307
|
-
`https://graph.facebook.com/${settings.fbGraphVersion}/search`,
|
|
308
|
-
{
|
|
309
|
-
params: {
|
|
310
|
-
type: 'place',
|
|
311
|
-
q,
|
|
312
|
-
fields: 'id,name,location',
|
|
313
|
-
access_token: settings.fbPageAccessToken,
|
|
314
|
-
limit: 7,
|
|
315
|
-
},
|
|
316
|
-
timeout: 8000,
|
|
317
|
-
}
|
|
318
|
-
);
|
|
319
|
-
const data = (resp.data && resp.data.data) || [];
|
|
320
|
-
winston.info(`[facebook-post] search-place: q="${q}" → ${data.length} résultat(s)`);
|
|
321
|
-
const results = data.map(p => ({
|
|
322
|
-
id: p.id,
|
|
323
|
-
name: p.name,
|
|
324
|
-
city: (p.location && (p.location.city || p.location.country)) || '',
|
|
325
|
-
}));
|
|
326
|
-
return res.json({ results });
|
|
327
|
-
} catch (e) {
|
|
328
|
-
const detail = e?.response?.data ? JSON.stringify(e.response.data) : e?.message;
|
|
329
|
-
winston.warn(`[facebook-post] search-place erreur: ${detail}`);
|
|
330
|
-
return res.json({ results: [] });
|
|
331
|
-
}
|
|
332
|
-
});
|
|
292
|
+
|
|
333
293
|
};
|
|
334
294
|
|
|
335
295
|
Plugin.addAdminNavigation = async function (header) {
|
package/package.json
CHANGED
package/static/lib/composer.js
CHANGED
|
@@ -16,114 +16,45 @@
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
function injectUI($composer) {
|
|
19
|
-
if ($composer.find('[data-fbpost-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
style="display:none;position:absolute;z-index:9999;background:#fff;
|
|
37
|
-
border:1px solid #ccc;border-radius:4px;list-style:none;
|
|
38
|
-
margin:0;padding:0;width:100%;max-height:200px;overflow-y:auto;"></ul>
|
|
39
|
-
</div>
|
|
40
|
-
<input type="hidden" data-fbpost-place-id>
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
`;
|
|
44
|
-
|
|
45
|
-
const $write = $composer.find('.write').first();
|
|
46
|
-
if ($write.is('textarea')) {
|
|
47
|
-
// .write est la textarea elle-même — injecter après son conteneur parent
|
|
48
|
-
$write.parent().after(html);
|
|
49
|
-
} else if ($write.length) {
|
|
50
|
-
$write.prepend(html);
|
|
51
|
-
} else {
|
|
52
|
-
const $target = $composer.find('.composer-body, .composer-content').first();
|
|
53
|
-
if ($target.length) $target.prepend(html);
|
|
54
|
-
else $composer.prepend(html);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const $enabled = $composer.find('[data-fbpost-enabled]');
|
|
58
|
-
const $placeWrap = $composer.find('[data-fbpost-place-wrap]');
|
|
59
|
-
|
|
60
|
-
$enabled.on('change', function () {
|
|
61
|
-
$placeWrap.toggle($enabled.is(':checked'));
|
|
19
|
+
if ($composer.find('[data-fbpost-btn]').length) return;
|
|
20
|
+
|
|
21
|
+
const $btn = $(`
|
|
22
|
+
<button type="button" class="btn btn-sm btn-link" data-fbpost-btn
|
|
23
|
+
title="Publier ce topic sur Facebook (cliquer pour activer)"
|
|
24
|
+
style="opacity:0.4; color:#1877F2; font-size:1.2em; padding:2px 6px;">
|
|
25
|
+
<i class="fab fa-facebook-f"></i>
|
|
26
|
+
</button>
|
|
27
|
+
`);
|
|
28
|
+
|
|
29
|
+
$btn.on('click', function () {
|
|
30
|
+
const active = $(this).data('fbpost-active');
|
|
31
|
+
$(this).data('fbpost-active', !active)
|
|
32
|
+
.attr('title', !active
|
|
33
|
+
? 'Publier sur Facebook (actif — cliquer pour désactiver)'
|
|
34
|
+
: 'Publier ce topic sur Facebook (cliquer pour activer)')
|
|
35
|
+
.css('opacity', !active ? '1' : '0.4');
|
|
62
36
|
});
|
|
63
37
|
|
|
64
|
-
|
|
65
|
-
const $
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
$
|
|
38
|
+
// Injecter dans la barre d'outils du composeur
|
|
39
|
+
const $toolbar = $composer.find('.toolbar, .formatting-bar, [data-toolbar]').first();
|
|
40
|
+
if ($toolbar.length) {
|
|
41
|
+
// Si la toolbar contient des <li>, on enveloppe
|
|
42
|
+
if ($toolbar.find('li').length) {
|
|
43
|
+
$toolbar.append($('<li>').append($btn));
|
|
44
|
+
} else {
|
|
45
|
+
$toolbar.append($btn);
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
// Fallback : avant la zone de texte
|
|
49
|
+
$composer.find('.write').first().before($btn);
|
|
76
50
|
}
|
|
77
51
|
|
|
78
|
-
$query.on('input', function () {
|
|
79
|
-
clearPlace();
|
|
80
|
-
clearTimeout(_placeTimer);
|
|
81
|
-
const q = $query.val().trim();
|
|
82
|
-
if (q.length < 2) { $results.hide().empty(); return; }
|
|
83
|
-
_placeTimer = setTimeout(async function () {
|
|
84
|
-
try {
|
|
85
|
-
const res = await fetch('/api/facebook-post/search-place?q=' + encodeURIComponent(q), {
|
|
86
|
-
credentials: 'same-origin', cache: 'no-store',
|
|
87
|
-
});
|
|
88
|
-
if (!res.ok) return;
|
|
89
|
-
const json = await res.json();
|
|
90
|
-
$results.empty();
|
|
91
|
-
if (!json.results || !json.results.length) { $results.hide(); return; }
|
|
92
|
-
json.results.forEach(function (p) {
|
|
93
|
-
const label = p.name + (p.city ? ' – ' + p.city : '');
|
|
94
|
-
$('<li>')
|
|
95
|
-
.text(label)
|
|
96
|
-
.css({ padding: '6px 10px', cursor: 'pointer' })
|
|
97
|
-
.on('mousedown', function (e) {
|
|
98
|
-
e.preventDefault();
|
|
99
|
-
selectPlace(p.id, p.name, p.city);
|
|
100
|
-
})
|
|
101
|
-
.appendTo($results);
|
|
102
|
-
});
|
|
103
|
-
$results.show();
|
|
104
|
-
} catch { /* ignore */ }
|
|
105
|
-
}, 350);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
$query.on('blur', function () {
|
|
109
|
-
setTimeout(function () { $results.hide(); }, 200);
|
|
110
|
-
});
|
|
111
|
-
$query.on('focus', function () {
|
|
112
|
-
if ($results.children().length) $results.show();
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// NodeBB 4.x fires 'action:composer.submit' with { composerData } (the object
|
|
116
|
-
// sent to the socket). Modifying composerData by reference is enough.
|
|
117
52
|
$(window).off('action:composer.submit.fbpost')
|
|
118
53
|
.on('action:composer.submit.fbpost', function (ev2, data) {
|
|
119
|
-
const enabled =
|
|
54
|
+
const enabled = !!$composer.find('[data-fbpost-btn]').data('fbpost-active');
|
|
120
55
|
const postData = (data && data.composerData) || (data && data.postData) || data;
|
|
121
56
|
if (!postData || typeof postData !== 'object') return;
|
|
122
57
|
postData.fbPostEnabled = enabled;
|
|
123
|
-
if (enabled) {
|
|
124
|
-
const placeId = $composer.find('[data-fbpost-place-id]').val();
|
|
125
|
-
if (placeId) postData.fbPlaceId = placeId;
|
|
126
|
-
}
|
|
127
58
|
});
|
|
128
59
|
}
|
|
129
60
|
|
|
@@ -141,4 +72,3 @@
|
|
|
141
72
|
}
|
|
142
73
|
});
|
|
143
74
|
})();
|
|
144
|
-
|