nodebb-plugin-facebook-post 1.0.20 → 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
@@ -293,6 +293,39 @@ Plugin.init = async function (params) {
293
293
  return res.json({ allowed: false, reason: 'error' });
294
294
  }
295
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
+ });
296
329
  };
297
330
 
298
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.20",
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');