nodebb-plugin-facebook-post 1.0.19 → 1.0.21

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 CHANGED
@@ -157,8 +157,7 @@ async function getPostContext(postData) {
157
157
  if (!topic) return null;
158
158
 
159
159
  const user = await User.getUserFields(post.uid, ['uid', 'username', 'userslug', 'reputation']);
160
- const url = await Topics.getTopicUrl(post.tid);
161
- const topicUrlAbs = absolutizeUrl(url);
160
+ const topicUrlAbs = absolutizeUrl(`/topic/${topic.slug}`);
162
161
 
163
162
  return { post, topic, user, topicUrlAbs };
164
163
  }
@@ -294,6 +293,39 @@ Plugin.init = async function (params) {
294
293
  return res.json({ allowed: false, reason: 'error' });
295
294
  }
296
295
  });
296
+
297
+ router.get('/api/facebook-post/search-place', middleware.ensureLoggedIn, async (req, res) => {
298
+ res.set('Cache-Control', 'no-store');
299
+ try {
300
+ await loadSettings();
301
+ if (!settings.fbPageAccessToken) return res.json({ results: [] });
302
+ const q = trimStr(req.query.q);
303
+ if (q.length < 2) return res.json({ results: [] });
304
+
305
+ const resp = await axios.get(
306
+ `https://graph.facebook.com/${settings.fbGraphVersion}/search`,
307
+ {
308
+ params: {
309
+ type: 'place',
310
+ q,
311
+ fields: 'id,name,location',
312
+ access_token: settings.fbPageAccessToken,
313
+ limit: 7,
314
+ },
315
+ timeout: 8000,
316
+ }
317
+ );
318
+ const data = (resp.data && resp.data.data) || [];
319
+ const results = data.map(p => ({
320
+ id: p.id,
321
+ name: p.name,
322
+ city: (p.location && (p.location.city || p.location.country)) || '',
323
+ }));
324
+ return res.json({ results });
325
+ } catch {
326
+ return res.json({ results: [] });
327
+ }
328
+ });
297
329
  };
298
330
 
299
331
  Plugin.addAdminNavigation = async function (header) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-facebook-post",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
4
4
  "description": "Auto-post new NodeBB topics to a fixed Facebook Page (text + NodeBB uploads + place id).",
5
5
  "main": "library.js",
6
6
  "dependencies": {
@@ -26,13 +26,18 @@
26
26
  </div>
27
27
 
28
28
  <div class="mb-2" data-fbpost-place-wrap style="display:none;">
29
- <label class="form-label" style="font-size: 12px; opacity: .8;">
30
- Lieu (Facebook Place ID) – optionnel
29
+ <label class="form-label" style="font-size:12px;opacity:.8;">
30
+ Lieu – optionnel
31
31
  </label>
32
- <input type="text" class="form-control" data-fbpost-place-id placeholder="ex: 123456789012345">
33
- <div class="form-text" style="font-size: 11px;">
34
- Utilisé comme <code>place</code> sur Facebook et <code>location_id</code> sur Instagram.
32
+ <div style="position:relative;">
33
+ <input type="text" class="form-control" data-fbpost-place-query
34
+ placeholder="Rechercher un lieu (ville, adresse…)" autocomplete="off">
35
+ <ul data-fbpost-place-results
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>
35
39
  </div>
40
+ <input type="hidden" data-fbpost-place-id>
36
41
  </div>
37
42
  </div>
38
43
  `;
@@ -56,6 +61,57 @@
56
61
  $placeWrap.toggle($enabled.is(':checked'));
57
62
  });
58
63
 
64
+ let _placeTimer = null;
65
+ const $query = $composer.find('[data-fbpost-place-query]');
66
+ const $results = $composer.find('[data-fbpost-place-results]');
67
+ const $placeId = $composer.find('[data-fbpost-place-id]');
68
+
69
+ function clearPlace() {
70
+ $placeId.val('');
71
+ }
72
+ function selectPlace(id, name, city) {
73
+ $placeId.val(id);
74
+ $query.val(name + (city ? ' – ' + city : ''));
75
+ $results.hide().empty();
76
+ }
77
+
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
+
59
115
  $(window).off('filter:composer.submit.fbpost')
60
116
  .on('filter:composer.submit.fbpost', function (ev2, submitData) {
61
117
  const enabled = $enabled.is(':checked');