Ever get the feeling that nothing makes sense anymore? That every bit of peer-reviewed research has some anti-research reviewed by a wholly different set of peers? There is a word for that: βepistemic collapseβ, or when a society, as a collective, loses its ability to distinguish truth from falsehood.
AllatRa, oD contributors JuliΓ‘n Reingold and Ignacio Conese report, is a doomsday cult that Ukrainian and Czech authorities are investigating for being pro-Russian and the Kremlin has proscribed for being extremist. They have met with the Pope, attended UN climate conferences, the European Parliament and the US Congress β all in the guise of fighting nano-plastic oceanic pollution, even as they deny that climate change is a man-made crisis. As Climate Week begins in London this Saturday, read our story to understand just how organisations such as AllatRa are creating just enough confusion to compromise urgent action to tackle the climate crisis.
Speaking of the collapse of meaning, the Makerfield results are in, and it seems the UK will soon have its sixth prime minister since David Cameron stepped down in the summer of 2016. Hurray for democracy! βAndy Burnham, not Labour, won this by-election,β writes openDemocracyβs Ethan Shone, but is he a candidate of continuity or change? Read more to find out.
Also in this issue, Paul Rogers on Burnham, military spending and the climate crisis (all in one column); openDemocracy editor Indra Warnes on the under-16 social media ban; continuing coverage of the Palestine Action trial and much more. We have a special podcast episode this week: βYou will die at 30β takes us to Ghana, where a young trans-woman seeks community under the shadow of one of the worldβs harshest crackdowns on the LGBTQI+ community.
r.json()).then(data => {
allLocations = data;
return data;
});
}
function fetchGroups() {
return fetch(restBase + '/source-groups', {
headers: { 'X-WP-Nonce': restNonce }
}).then(r => r.json()).then(data => {
allGroups = data;
return data;
});
}
// ββ Panel open/close ββββββββββββββββββββββββββββ
const $picker = $('#qtw-loc-picker');
// Position picker dynamically below the actual header so it never overlaps nav links
function positionPicker() {
var header = document.querySelector('.site-header');
if (window.innerWidth <= 768) {
// Mobile: let CSS handle static positioning, just clear any inline override
$picker.css({ position: '', top: '', left: '' });
return;
}
if (header) {
var rect2 = header.getBoundingClientRect();
$picker.css({ position: 'fixed', top: (rect2.bottom + 8) + 'px', left: '16px' });
}
}
positionPicker();
window.addEventListener('resize', positionPicker);
window.addEventListener('load', positionPicker);
setTimeout(positionPicker, 300);
setTimeout(positionPicker, 1000);
const $trigger = $('#qtw-lp-trigger');
const $panel = $('#qtw-lp-panel');
function showLockToast() {
var toast = document.getElementById('qtw-lock-toast');
if (!toast) {
toast = document.createElement('div');
toast.id = 'qtw-lock-toast';
toast.style.cssText = 'position:fixed;bottom:80px;left:50%;transform:translateX(-50%);background:#1e1e1e;border:1px solid #00c853;color:#f0f0f0;padding:10px 20px;border-radius:20px;font-size:13px;z-index:99999;pointer-events:auto;transition:opacity 0.3s;';
document.body.appendChild(toast);
}
toast.innerHTML = '\uD83D\uDD12 Location is locked.
Click to unlock ';
document.getElementById('qtw-unlock-link').addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
state.locked = false;
toast.style.opacity = '0';
$('#qtw-lp-lockchk').prop('checked', false).trigger('change');
const open = $panel.is(':hidden');
$panel.prop('hidden', false);
$trigger.attr('aria-expanded', true);
$picker.addClass('panel-open');
if (!allLocations.length) fetchLocations().then(() => renderLocList(0));
if (!allGroups.length) fetchGroups().then(renderGroupList);
});
toast.style.opacity = '1';
clearTimeout(window._toastTimer);
window._toastTimer = setTimeout(function(){ toast.style.opacity = '0'; }, 2500);
}
$trigger.on('click', function() {
if (state.locked) { showLockToast(); return; }
const open = !$panel.is(':hidden');
$panel.prop('hidden', open);
$trigger.attr('aria-expanded', !open);
$picker.toggleClass('panel-open', !open);
if (!open) {
if (!allLocations.length) fetchLocations().then(() => renderLocList(0));
if (!allGroups.length) fetchGroups().then(renderGroupList);
}
});
$(document).on('click', function(e) {
if (!$(e.target).closest('#qtw-loc-picker, #qtw-lp-modal').length) {
$panel.prop('hidden', true);
$picker.removeClass('panel-open');
}
});
// ββ Tabs ββββββββββββββββββββββββββββββββββββββββ
$('#qtw-help-toggle').on('click', function() {
const $help = $('#qtw-group-help');
const expanded = $help.prop('hidden') === false;
$help.prop('hidden', expanded);
$(this).attr('aria-expanded', !expanded);
$(this).text(expanded ? '? Help' : 'β Close');
});
$('.qtw-lp-tab').on('click', function() {
const tab = $(this).data('tab');
$('.qtw-lp-tab').removeClass('active');
$(this).addClass('active');
$('.qtw-lp-tabpane').prop('hidden', true);
$('[data-pane="' + tab + '"]').prop('hidden', false);
if (tab === 'group' && !allGroups.length) {
fetchGroups().then(renderGroupList);
}
});
// ββ Location list ββββββββββββββββββββββββββββββββ
function renderLocList(parentId) {
const $list = $('#qtw-lp-loclist');
const children = allLocations.filter(l => l.parent === parentId);
if (!children.length) {
$list.html('
No sub-locations
');
return;
}
$list.html('');
children.forEach(function(loc) {
const hasChildren = allLocations.some(l => l.parent === loc.id);
const selected = pending.location === loc.slug;
const $item = $('
' +
'' + escHtml(loc.name) + ' ' +
'' + (loc.count || 0) + ' ' +
(hasChildren ? 'βΈ ' : '') +
'
');
$item.on('click', function(e) {
e.stopPropagation();
if ($(e.target).hasClass('qtw-lp-item-drill')) {
drillDown(loc);
return;
}
pending.location = loc.slug;
$('#qtw-lp-current').text(loc.name);
renderLocList(parentId); // re-render to update selection
});
if (hasChildren) {
$item.find('.qtw-lp-item-drill').on('click', function(e) {
e.stopPropagation();
drillDown(loc);
});
}
$list.append($item);
});
}
function drillDown(loc) {
state.parent = loc.id;
// Update breadcrumb
const $bc = $('#qtw-lp-breadcrumb');
$bc.append(
'
βΊ ' +
'
' +
escHtml(loc.name) + ' '
);
renderLocList(loc.id);
}
// Breadcrumb navigation
$(document).on('click', '.qtw-lp-bc-item', function() {
const id = parseInt($(this).data('id') || 0);
const slug = $(this).data('slug') || '';
// Remove all breadcrumb items after this one
$(this).nextAll().remove();
if (slug) {
pending.location = slug;
$('#qtw-lp-current').text($(this).data('name'));
updateApplyLabel();
}
renderLocList(id);
});
// ββ Group list βββββββββββββββββββββββββββββββββββ
function renderGroupList() {
const $list = $('#qtw-lp-grouplist');
if (!allGroups.length) {
$list.html('
No groups available
');
return;
}
$list.html('');
const activeGroup = allGroups.find(g => g.id === pending.group_id);
if (activeGroup) {
$list.prepend('
β Active: ' + escHtml(activeGroup.title) + '
');
}
var $selectedItem = null;
allGroups.forEach(function(g) {
const selected = pending.group_id === g.id;
const $item = $('
' +
'' + escHtml(g.title) +
(g.preset ? ' preset ' : '') +
' ' +
(selected ? 'β ' : '') +
'
');
$item.on('click', function(e) {
e.stopPropagation();
if ($(e.target).hasClass('qtw-lp-group-delete')) return;
if ($(e.target).hasClass('qtw-lp-group-edit')) return;
pending.group_id = selected ? 0 : g.id;
if (pending.group_id) pending.location = '';
updateApplyLabel();
// Update visual selection without full re-render
$('.qtw-lp-item').removeClass('selected');
$('.qtw-lp-item-check').remove();
if (pending.group_id) {
$(this).addClass('selected');
$(this).find('.qtw-lp-item-name').after('
β ');
}
});
if (!g.preset) {
// Edit button
const $edit = $('
β ');
$edit.on('click', function(e) {
e.stopPropagation();
editingGroupId = g.id;
// Pre-populate modal
$('#qtw-sg-name').val(g.title);
selectedFeeds.clear();
if (g.feeds) g.feeds.forEach(f => selectedFeeds.add(f));
$('#qtw-sg-feeds').val('');
updateSourceCount();
// Hide clone row when editing
$('#qtw-sg-clone').closest('label').hide();
// Set modal title
$('#qtw-lp-modal h3').first().text('Edit group');
$('#qtw-sg-save').text('Save changes');
$('#qtw-sg-save-as').prop('hidden', false);
// Populate location
selectedLocations = new Set(g.location || []);
updateLocChips();
$('#qtw-sg-date-from').val(g.date_from || '');
$('#qtw-sg-notify-email').prop('checked', g.notify_email !== false);
wizStep(2);
loadSources();
$('#qtw-lp-modal').prop('hidden', false);
});
$item.append($edit);
// Delete button
const $del = $('
β ');
$del.on('click', function(e) {
e.stopPropagation();
if (!confirm('Delete group "' + escHtml(g.title) + '"? This cannot be undone.')) return;
fetch(restBase + '/source-groups/' + g.id, {
method: 'DELETE',
headers: { 'X-WP-Nonce': restNonce }
}).then(r => r.json()).then(function(data) {
if (data.deleted) {
if (pending.group_id === g.id) pending.group_id = 0;
fetchGroups().then(renderGroupList);
} else {
alert('Could not delete group.');
}
});
});
$item.append($del);
}
$list.append($item);
if (selected) $selectedItem = $item;
});
if ($selectedItem) {
setTimeout(function() { $selectedItem[0].scrollIntoView({ block: 'nearest' }); }, 50);
}
}
// ββ Location search ββββββββββββββββββββββββββββββ
$('#qtw-lp-search').on('input', function() {
const q = $(this).val().trim().toLowerCase();
if (!q) { renderLocList(0); return; }
const matches = allLocations.filter(l => l.name.toLowerCase().includes(q));
const $list = $('#qtw-lp-loclist');
$list.html('');
if (!matches.length) { $list.html('
No results
'); return; }
matches.forEach(function(loc) {
const selected = pending.location === loc.slug;
const $item = $('
' +
'' + escHtml(loc.name) + ' ' +
'' + (loc.count || 0) + ' ' +
'
');
$item.on('click', function(e) {
e.stopPropagation();
pending.location = loc.slug;
$('#qtw-lp-current').text(loc.name);
$('#qtw-lp-search').val('');
renderLocList(0);
});
$list.append($item);
});
});
// ββ Lock toggle ββββββββββββββββββββββββββββββββββ
var lockChkReady = false;
setTimeout(function(){ lockChkReady = true; }, 500);
$('#qtw-lp-lockchk').on('change', function() {
if (lockChkReady === false) return;
const lock = loggedIn && $(this).is(':checked');
state.locked = lock;
// Save lock state immediately
$.post(vars.ajax_url, {
action: 'qtw_set_location',
nonce: vars.nonce,
location: state.location,
group_id: state.group_id,
lock: lock ? 1 : 0,
}, function(res) {
if (res.success) {
const $lockIcon = $('#qtw-lp-trigger .qtw-lp-lock');
if (lock) {
if (!$lockIcon.length) $trigger.find('.qtw-lp-caret').before('
π ');
} else {
$lockIcon.remove();
}
}
});
});
// ββ Apply ββββββββββββββββββββββββββββββββββββββββ
function updateApplyLabel() {
const $btn = $('#qtw-lp-apply');
if (pending.group_id) {
const g = allGroups.find(g => g.id === pending.group_id);
$btn.text('π Fetch from ' + (g ? g.title : 'group'));
} else if (pending.location) {
$btn.text('π Fetch from ' + (pending.location.replace(/-/g, ' ')));
} else {
$btn.text('π Fetch News');
}
}
$('#qtw-lp-apply').on('click', function() {
$(this).text('β³ Fetchingβ¦').prop('disabled', true);
const lock = loggedIn && $('#qtw-lp-lockchk').is(':checked');
$.post(vars.ajax_url, {
action: 'qtw_set_location',
nonce: vars.nonce,
location: pending.location,
group_id: pending.group_id,
lock: lock ? 1 : 0,
}, function(res) {
if (res.success) {
state.location = pending.location;
state.group_id = pending.group_id;
state.locked = lock;
// Update lock icon
const $lockIcon = $('#qtw-lp-trigger .qtw-lp-lock');
if (lock) {
if (!$lockIcon.length) $trigger.find('.qtw-lp-caret').before('
π ');
} else {
$lockIcon.remove();
}
$panel.prop('hidden', true);
$picker.removeClass('panel-open');
updateApplyLabel();
$('#qtw-lp-apply').prop('disabled', false);
// Reload the feed if qtw_news_feed function exists
if (typeof window.qtw_reload_feed === 'function') {
window.qtw_reload_feed(pending.location, pending.group_id);
} else {
// Fallback: reload the page with location param
const url = new URL(window.location.href);
url.searchParams.set('news_location', pending.location);
if (pending.group_id) url.searchParams.set('group', pending.group_id);
else url.searchParams.delete('group');
window.location.href = url.toString();
}
}
});
});
// ββ Clear ββββββββββββββββββββββββββββββββββββββββ
$('#qtw-lp-clear').on('click', function() {
pending.location = '';
pending.group_id = 0;
$('#qtw-lp-current').text('All');
renderLocList(0);
renderGroupList();
});
// Pre-fill feeds when clone changes
$('#qtw-sg-clone').on('change', function() {
const id = parseInt($(this).val());
if (!id) return;
const group = allGroups.find(g => g.id === id);
if (group) {
$('#qtw-sg-feeds').val((group.feeds || []).join('\n'));
selectedLocations = new Set(group.location || []);
updateLocChips();
}
});
// ββ Wizard state ββββββββββββββββββββββββββββββββ
let allSources = [];
let selectedFeeds = new Set();
let selectedLocations = new Set();
let editingGroupId = 0;
function wizStep(n) {
$('.qtw-wiz-pane').prop('hidden', true);
$('#qtw-wiz-' + n).prop('hidden', false);
$('.qtw-wiz-step').removeClass('active done');
for (let i = 1; i < n; i++) $('[data-step="' + i + '"]').addClass('done');
$('[data-step="' + n + '"]').addClass('active');
}
function loadSources() {
if (allSources.length) { renderSources(''); return; }
$('#qtw-src-list').html('
Loadingβ¦
');
fetch(restBase + '/sources', { headers: { 'X-WP-Nonce': restNonce } })
.then(r => r.json()).then(function(data) {
allSources = data.sort((a,b) => a.title.localeCompare(b.title));
renderSources('');
});
}
function renderSources(q) {
const $list = $('#qtw-src-list');
$list.html('');
const filtered = q ? allSources.filter(s => s.title.toLowerCase().includes(q.toLowerCase())) : allSources;
if (!filtered.length) { $list.html('
No results
'); return; }
filtered.forEach(function(s) {
const sel = selectedFeeds.has(s.feed);
const typeLabel = s.type === 'youtube' ? 'βΆ YouTube' : 'β
RSS';
const $item = $('
' +
'' + escHtml(s.title) + '' + typeLabel + ' ' +
(sel ? 'β ' : '') +
'
');
$item.on('click', function() {
if (selectedFeeds.has(s.feed)) {
selectedFeeds.delete(s.feed);
} else {
selectedFeeds.add(s.feed);
}
updateSourceCount();
renderSources($('#qtw-src-search').val());
});
$list.append($item);
});
}
function updateSourceCount() {
$('#qtw-src-count').text(selectedFeeds.size + ' selected');
}
function loadLocationsForGroup() {
if (allLocations.length) { renderLocPicker(''); return; }
fetchLocations().then(() => renderLocPicker(''));
}
function renderLocPicker(q) {
const $list = $('#qtw-sg-loc-list');
$list.html('');
const sorted = allLocations.slice().sort((a,b) => a.name.localeCompare(b.name));
const filtered = q ? sorted.filter(l => l.name.toLowerCase().includes(q.toLowerCase())) : sorted;
if (!filtered.length) { $list.html('
No results
'); return; }
filtered.slice(0, 100).forEach(function(l) {
const sel = selectedLocations.has(l.slug);
const $item = $('
' +
'' + escHtml(l.name) + ' ' +
(sel ? 'β ' : '') +
'
');
$item.on('click', function() {
if (selectedLocations.has(l.slug)) {
selectedLocations.delete(l.slug);
} else {
selectedLocations.add(l.slug);
}
updateLocChips();
renderLocPicker($('#qtw-sg-loc-search').val());
});
$list.append($item);
});
}
function updateLocChips() {
$('#qtw-sg-loc-count').text(selectedLocations.size + ' selected');
const $chips = $('#qtw-sg-loc-chips');
$chips.html('');
selectedLocations.forEach(function(slug) {
const loc = allLocations.find(l => l.slug === slug);
const label = loc ? loc.name : slug;
const $chip = $('
' + escHtml(label) +
' β ');
$chip.find('.qtw-sg-loc-chip-remove').on('click', function() {
selectedLocations.delete(slug);
updateLocChips();
renderLocPicker($('#qtw-sg-loc-search').val());
});
$chips.append($chip);
});
}
// Wizard navigation
$('#qtw-wiz-1-next').on('click', function() {
const name = $('#qtw-sg-name').val().trim();
if (!name) { alert('Please enter a name for your group.'); return; }
// Pre-load sources from clone if selected
const clone_id = parseInt($('#qtw-sg-clone').val()) || 0;
if (clone_id && selectedFeeds.size === 0) {
const group = allGroups.find(g => g.id === clone_id);
if (group && group.feeds) group.feeds.forEach(f => selectedFeeds.add(f));
}
wizStep(2);
loadSources();
});
$('#qtw-wiz-2-back').on('click', function() { wizStep(1); });
$('#qtw-wiz-2-next').on('click', function() { wizStep(3); loadLocationsForGroup(); updateLocChips(); });
$('#qtw-sg-loc-search').on('input', function() {
renderLocPicker($(this).val().trim());
});
$('#qtw-wiz-3-back').on('click', function() { wizStep(2); });
$('#qtw-src-search').on('input', function() {
renderSources($(this).val().trim());
});
$('#qtw-advanced-toggle').on('click', function() {
const $adv = $('#qtw-advanced-feeds');
$adv.prop('hidden', !$adv.prop('hidden'));
$(this).text($adv.prop('hidden') ? '+ Add by RSS URL (advanced)' : 'β Hide advanced');
});
$('#qtw-sg-cancel, #qtw-sg-cancel2').on('click', function() {
$('#qtw-lp-modal').prop('hidden', true);
selectedFeeds.clear();
wizStep(1);
});
// Open modal
$('#qtw-lp-create-group').on('click', function() {
$('#qtw-sg-name').val('');
$('#qtw-sg-feeds').val('');
selectedFeeds.clear();
updateSourceCount();
selectedLocations.clear();
updateLocChips();
$('#qtw-sg-date-from').val('');
$('#qtw-sg-notify-email').prop('checked', true);
$('#qtw-sg-save-as').prop('hidden', true);
$('#qtw-lp-modal h3').first().text('Name your group');
$('#qtw-sg-save').text('Save group');
$('#qtw-sg-clone').closest('label').show();
wizStep(1);
// Populate clone dropdown
const $clone = $('#qtw-sg-clone');
$clone.find('option:not(:first)').remove();
allGroups.filter(g => g.preset).forEach(function(g) {
$clone.append('
' + escHtml(g.title) + ' ');
});
$('#qtw-lp-modal').prop('hidden', false);
});
$('#qtw-sg-save-as').on('click', function() {
const newName = prompt('Enter a name for the new group:', $('#qtw-sg-name').val().trim() + ' (copy)');
if (!newName || !newName.trim()) return;
const savedEditingId = editingGroupId;
editingGroupId = 0; // force POST (create) instead of PUT (update)
$('#qtw-sg-name').val(newName.trim());
$('#qtw-sg-save').trigger('click');
editingGroupId = savedEditingId;
});
$('#qtw-sg-save').on('click', function() {
const name = $('#qtw-sg-name').val().trim();
const clone_id = parseInt($('#qtw-sg-clone').val()) || 0;
const location = [...selectedLocations];
const dateFrom = $('#qtw-sg-date-from').val();
const notifyEmail = $('#qtw-sg-notify-email').is(':checked');
const advFeeds = $('#qtw-sg-feeds').val().split(/\r?\n/).map(f => f.trim()).filter(Boolean);
const feeds = [...new Set([...selectedFeeds, ...advFeeds])];
if (!name) { alert('Please enter a name for your group.'); return; }
if (!feeds.length && !clone_id) { if (!confirm('No sources were selected and no preset was cloned. This group will show no news. Save anyway?')) return; }
const isEditing = editingGroupId > 0;
const url = isEditing ? restBase + '/source-groups/' + editingGroupId : restBase + '/source-groups';
const method = isEditing ? 'PUT' : 'POST';
const body = isEditing
? JSON.stringify({ title: name, location: location, feeds: feeds, date_from: dateFrom, notify_email: notifyEmail })
: JSON.stringify({ title: name, clone_from: clone_id, location: location, feeds: feeds, loc_up: true, date_from: dateFrom, notify_email: notifyEmail });
fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': restNonce,
},
body: body,
})
.then(r => r.json())
.then(function(data) {
if (data.id) {
$('#qtw-lp-modal').prop('hidden', true);
selectedFeeds.clear();
selectedLocations.clear();
updateLocChips();
$('#qtw-sg-date-from').val('');
$('#qtw-sg-notify-email').prop('checked', true);
editingGroupId = 0;
$('#qtw-sg-clone').closest('label').show();
$('#qtw-sg-save-as').prop('hidden', true);
$('#qtw-lp-modal h3').first().text('Name your group');
$('#qtw-sg-save').text('Save group');
wizStep(1);
if (!isEditing) pending.group_id = data.id;
fetchGroups().then(function() {
renderGroupList();
$('[data-tab="group"]').trigger('click');
if (confirm(isEditing ? 'Group updated! Fetch news now?' : 'Your group was saved! Fetch news from this group now?')) {
if (notifyEmail) {
$.post(vars.ajax_url, {
action: 'qtw_notify_group_fetch',
nonce: vars.nonce,
group_id: data.id,
});
}
$('#qtw-lp-apply').trigger('click');
}
});
}
});
});
// ββ Utility ββββββββββββββββββββββββββββββββββββββ
function escHtml(str) {
return String(str)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"');
}
})(jQuery);