);
}
function setButtonState(button, state) {
const hint = button.parentElement && button.parentElement.querySelector(‘[data-author-follow-hint]’);
const followLabel = button.dataset.followLabel || ‘Follow’;
const followingLabel = button.dataset.followingLabel || ‘Following’;
const signinLabel = button.dataset.signinLabel || ‘Sign in to follow’;
const loadingLabel = button.dataset.loadingLabel || ‘Saving…’;
const pendingAuthLabel = button.dataset.pendingAuthLabel || ‘Loading…’;
button.classList.remove(‘is-following’, ‘is-loading’, ‘is-auth-required’);
if (state === ‘loading’) {
button.classList.add(‘is-loading’);
button.disabled = true;
button.textContent = loadingLabel;
if (hint) {
hint.textContent=”Updating your followed authors…”;
}
return;
}
if (state === ‘pending-auth’) {
button.classList.add(‘is-loading’);
button.disabled = true;
button.textContent = pendingAuthLabel;
if (hint) {
hint.textContent=”Checking your sign-in status…”;
}
return;
}
button.disabled = false;
if (state === ‘following’) {
button.classList.add(‘is-following’);
button.textContent = followingLabel;
if (hint) {
hint.textContent = followingLabel === ‘Unfollow’
? ‘Remove this writer from your followed list.’
: ‘Click again to unfollow.’;
}
return;
}
if (state === ‘signin’) {
button.classList.add(‘is-auth-required’);
button.textContent = signinLabel;
if (hint) {
hint.textContent=”Sign in to follow writers and manage your list.”;
}
return;
}
button.textContent = followLabel;
if (hint) {
hint.textContent=”Click to follow.”;
}
}
function renderWidgets(scope) {
const root = scope || document;
root.querySelectorAll(‘[data-author-follow-widget]’).forEach(function (widget) {
const button = widget.querySelector(‘[data-author-follow-button]’);
if (!button) {
return;
}
const staffId = widget.dataset.staffId;
const hasToken = !!getBearerToken();
if (!isPianoIdentityReady() && !hasToken) {
setButtonState(button, ‘pending-auth’);
return;
}
if (!hasToken) {
setButtonState(button, ‘signin’);
return;
}
if (followedAuthorsMap.has(String(staffId))) {
setButtonState(button, ‘following’);
} else {
setButtonState(button, ‘follow’);
}
});
}
function renderManageList(container) {
if (!container) {
return;
}
const hasToken = !!getBearerToken();
if (!isPianoIdentityReady() && !hasToken) {
container.innerHTML = (
‘
‘
);
return;
}
if (!hasToken) {
container.innerHTML = (
‘
‘
);
return;
}
const followedAuthors = Array.from(followedAuthorsMap.values());
if (!followedAuthors.length) {
container.innerHTML = (
‘
‘
);
return;
}
container.innerHTML = followedAuthors
.map(function (author) {
return (
‘
‘
);
})
.join(”);
bindEvents(container);
renderWidgets(container);
}
async function refresh(scope, options) {
const forceFetch = !!(options && options.force);
if (!hasFollowWidgets(scope)) {
return;
}
// Wipe the cached map BEFORE the first render so a user-switch can’t
// momentarily display the previous user’s “Following” state.
discardCacheIfTokenChanged();
renderWidgets(scope);
const manageContainer = document.querySelector(‘[data-author-follow-manage-list]’);
const managePreferencesContainer = document.querySelector(‘[data-author-follow-manage-preferences]’);
const hasToken = !!getBearerToken();
if (!isPianoIdentityReady() && !hasToken) {
renderWidgets(scope);
renderManagePreferences(managePreferencesContainer);
renderManageList(manageContainer);
return;
}
if (!hasToken) {
renderManagePreferences(managePreferencesContainer);
renderManageList(manageContainer);
return;
}
try {
await loadFollowedAuthors(forceFetch);
renderWidgets(scope);
renderManagePreferences(managePreferencesContainer);
renderManageList(manageContainer);
} catch (error) {
console.warn(‘Unable to load followed authors.’, error);
if (error && error.code === ‘AUTH_REQUIRED’) {
renderWidgets(scope);
renderManagePreferences(managePreferencesContainer);
renderManageList(manageContainer);
}
}
}
function startLoginPoll() {
if (loginPoll) {
clearInterval(loginPoll);
}
let attempts = 0;
loginPoll = setInterval(function () {
attempts += 1;
if (getBearerToken() || isLoggedIn() || attempts > 25) {
clearInterval(loginPoll);
loginPoll = null;
refresh(document, { force: true });
}
}, 1000);
}
function stopPianoReadyPoll() {
if (pianoReadyPoll) {
clearInterval(pianoReadyPoll);
pianoReadyPoll = null;
}
}
function startPianoReadyPoll() {
stopPianoReadyPoll();
let attempts = 0;
pianoReadyPoll = setInterval(function () {
attempts += 1;
if (isPianoIdentityReady() || getBearerToken() || attempts > 40) {
stopPianoReadyPoll();
// Non-forced: if bindPianoInitRefresh already fetched, the TTL
// dedupes this call. If it lost the race, this call wins.
refresh(document);
}
}, 500);
}
function bindPianoInitRefresh() {
if (pianoInitBound) {
return;
}
pianoInitBound = whenPianoReady(function () {
// The Piano init callback is the canonical “identity is ready” signal;
// cancel the fallback poll so it can’t issue a redundant second fetch.
stopPianoReadyPoll();
refresh(document, { force: true });
});
}
async function handleWidgetClick(widget, button) {
const staffId = widget.dataset.staffId;
if (!getBearerToken()) {
setButtonState(button, isPianoIdentityReady() ? ‘signin’ : ‘pending-auth’);
if (typeof window.showPianoLogin === ‘function’) {
window.showPianoLogin();
startLoginPoll();
}
return;
}
// If the identity changed since the cache was last filled, drop the stale
// map before the follow/unfollow decision below — otherwise the click
// could issue the wrong action against the previous user’s state.
discardCacheIfTokenChanged();
setButtonState(button, ‘loading’);
try {
if (followedAuthorsMap.has(String(staffId))) {
await apiRequest(apiBaseUrl + “https://www.washingtontimes.com/” + staffId, { method: ‘DELETE’ });
followedAuthorsMap.delete(String(staffId));
removePushlyFollowedAuthorId(staffId);
} else {
const author = await apiRequest(apiBaseUrl + “https://www.washingtontimes.com/” + staffId, {
method: ‘PUT’,
body: JSON.stringify({
push_enabled: followDeliveryPreferences.push_enabled,
email_fallback_enabled: followDeliveryPreferences.email_fallback_enabled,
}),
});
followedAuthorsMap.set(String(staffId), author);
appendPushlyFollowedAuthorId(staffId);
}
saveStoredFollowDeliveryPreferences(
deriveFollowDeliveryPreferences(Array.from(followedAuthorsMap.values())),
);
syncPushlyFollowedAuthorsProfile();
renderManagePreferences(document.querySelector(‘[data-author-follow-manage-preferences]’));
renderWidgets(document);
renderManageList(document.querySelector(‘[data-author-follow-manage-list]’));
} catch (error) {
console.warn(‘Unable to update followed author.’, error);
if (error && error.code === ‘AUTH_REQUIRED’) {
setButtonState(button, ‘signin’);
}
renderWidgets(document);
}
}
function bindEvents(scope) {
const root = scope || document;
root.querySelectorAll(‘[data-author-follow-widget]’).forEach(function (widget) {
if (widget.dataset.followWidgetBound === ‘true’) {
return;
}
widget.dataset.followWidgetBound = ‘true’;
const button = widget.querySelector(‘[data-author-follow-button]’);
if (!button) {
return;
}
button.addEventListener(‘click’, function () {
handleWidgetClick(widget, button);
});
});
root.querySelectorAll(‘[data-author-follow-manage-preferences]’).forEach(function (container) {
if (container.dataset.followGlobalPreferencesBound === ‘true’) {
return;
}
container.dataset.followGlobalPreferencesBound = ‘true’;
async function handlePreferenceChange() {
const pushInput = container.querySelector(‘[data-author-follow-global-pref=”push”]’);
const emailInput = container.querySelector(‘[data-author-follow-global-pref=”email”]’);
if (!pushInput || !emailInput) {
return;
}
const previousPreferences = {
push_enabled: followDeliveryPreferences.push_enabled,
email_fallback_enabled: followDeliveryPreferences.email_fallback_enabled,
};
const payload = {
push_enabled: !!pushInput.checked,
email_fallback_enabled: !!emailInput.checked,
};
// Drop a stale map if the identity changed before iterating — we
// don’t want to issue follow updates against the previous user’s
// authors with the current user’s bearer token.
discardCacheIfTokenChanged();
const followedAuthors = Array.from(followedAuthorsMap.values());
saveStoredFollowDeliveryPreferences(payload);
managePreferencesPending = true;
pushInput.disabled = true;
emailInput.disabled = true;
try {
await Promise.all(
followedAuthors.map(function (author) {
return updateFollowPreferences(author.id, payload);
}),
);
renderManagePreferences(container);
renderWidgets(document);
renderManageList(document.querySelector(‘[data-author-follow-manage-list]’));
} catch (error) {
console.warn(‘Unable to update author follow preferences.’, error);
saveStoredFollowDeliveryPreferences(previousPreferences);
pushInput.checked = previousPreferences.push_enabled;
emailInput.checked = previousPreferences.email_fallback_enabled;
} finally {
managePreferencesPending = false;
pushInput.disabled = false;
emailInput.disabled = false;
}
}
container.addEventListener(‘change’, function (event) {
const target = event.target;
if (!target || !target.matches(‘[data-author-follow-global-pref]’)) {
return;
}
handlePreferenceChange();
});
});
}
function init(scope) {
const root = scope || document;
if (!hasFollowWidgets(root)) {
return;
}
bindEvents(root);
renderWidgets(root);
bindPianoInitRefresh();
startPianoReadyPoll();
refresh(root);
}
window.WTAuthorFollow = {
init: init,
refresh: refresh,
};
document.addEventListener(‘DOMContentLoaded’, function () {
init(document);
});
window.addEventListener(‘focus’, function () {
if (hasFollowWidgets(document)) {
refresh(document);
}
});
document.addEventListener(‘visibilitychange’, function () {
if (!document.hidden && hasFollowWidgets(document)) {
refresh(document);
}
});
} else {
window.WTAuthorFollow.init(document);
}
})();
FILE – Cuba’s President Raul Castro …
more >
President Trump declared that the U.S. is “freeing up Cuba” after the Justice Department indicted Cuban leader Raul Castro.
Mr. Trump described the U.S. actions taken against Cuban leaders as something that Cubans living in the U.S. and on the Caribbean Island have wanted for many years.
“It was a very big moment for people that, not only Cuban Americans, but people that came from Cuba that want to go back to Cuba, people that want to see their family in Cuba. I think it’s a very big day, very important day,” he said.
“I have so many Cuban friends in Miami, mostly in Miami and Florida, and they’re unbelievable people. They’re unbelievable entrepreneurs, and they’d like to go back,” he said. “I think they’re hopefully going to want to live here, but they want to go back. Maybe they’ll look, and we’ll see what happens. But we’re freeing up Cuba.”
The president described Cuba as a “failing nation” that is “falling apart” and has no oil. He said the U.S. is there to help Cuban Americans and their families in Cuba. He also recalled that he was supported by 94% of Cuban Americans in the last presidential election.
Mr. Trump declined to comment on whether the U.S. military would capture and arrest Mr. Castro as it did in January with Venezuelan leader Nicholas Maduro.
Mr. Castro spent years at the pinnacle of Cuba’s government alongside his late brother, Fidel Castro. He was indicted on federal charges of murder and conspiracy to kill Americans stemming from the 1996 downing of airplanes delivering aid to Cuban refugees.
Mr. Castro was first vice president and minister of defense at the time of the shootdown, which the U.S. said happened in international waters. The attack killed U.S. citizens who were part of Brothers to the Rescue, a group of Cuban exiles that flew pro-democracy propaganda missions to the island.
Latest Video
