Commit 999e8e60 authored by yPhil's avatar yPhil
Browse files

PTL.feed.js backPorts

parent de6626a9
Pipeline #417379 passed with stage
in 56 seconds
......@@ -2,109 +2,108 @@
PTL.feed = {
add:function($column, url, name, type, limit, status, iconhash, nbitems, lastitem, clickNew, isQueryString, progress) {
add: function($column, url, name, type, limit, status, iconhash, nbitems, lastitem, clickNew, isQueryString, progress) {
const $feed = $('<li>')
.attr('class', 'feed');
.attr('class', 'feed');
// const errVar = true;
// errVar = 'plop';
const $feedImg = $('<img>')
.attr({
src: '/static/images/rss.gif',
class: 'favicon',
width: '16px',
height: '16px'
})
.on("error", function() {
$(this).attr('src', '/static/images/rss.gif');
});
.attr({
src: '/static/images/rss.gif',
class: 'favicon',
width: '16px',
height: '16px'
})
.on("error", function() {
$(this).attr('src', '/static/images/rss.gif');
$(this).parent().parent().children('div.dataStore').data('iconhash', '');
PTL.tab.saveTabs();
});
const $newItemsBadge = $('<div>')
.attr('class', 'newItemsBadge hidden');
.attr({class: 'newItemsBadge hidden', title:PTL.tr('New items')});
const $feedIcon = $('<i>')
.attr({'class': 'feed-control feedIcon translate',
'title': PTL.tr('Fold / unfold this feed (%1)', url)})
.data('title', 'Fold / unfold this feed (%1)', url)
.click(function() {
if ($feedControls.data('status') == 'on') {
$(this).removeClass('fold')
.parent().parent().parent()
.children('div.feedBody')
.addClass('folded');
$feedControls.data('status', 'off');
$refreshIcon.removeClass('icon-refresh')
.addClass('icon-pin');
} else {
$(this).addClass('fold')
.parent().parent().parent()
.children('div.feedBody')
.removeClass('folded');
$feedControls.data('status', 'on');
$refreshIcon.removeClass('icon-pin')
.addClass('icon-refresh');
}
.attr({
'class': 'feed-control feedIcon translate',
'title': PTL.tr('Fold / unfold this feed (%1)', url)
})
.data('title', 'Fold / unfold this feed (%1)', url)
.click(function() {
if ($feedControls.data('status') == 'on') {
$(this).removeClass('fold')
.parent().parent().parent()
.children('div.feedBody')
.addClass('folded');
$feedControls.data('status', 'off');
$refreshIcon.removeClass('icon-refresh')
.addClass('icon-pin');
} else {
$(this).addClass('fold')
.parent().parent().parent()
.children('div.feedBody')
.removeClass('folded');
$feedControls.data('status', 'on');
$refreshIcon.removeClass('icon-pin')
.addClass('icon-refresh');
}
PTL.tab.saveTabs();
PTL.feed.populate($refreshIcon);
});
PTL.tab.saveTabs();
PTL.feed.populate($refreshIcon);
});
const $selectIcon = $('<i>')
.attr('class', 'feed-control translate icon-checkbox feedSelect')
.data('title', 'Select this feed (%1)', url)
.attr('title', PTL.tr('Select this feed (%1)', url))
.click(function() {
$(this).parent().parent().parent().parent()
.toggleClass('selected');
$(this).toggleClass('icon-checked icon-checkbox');
});
.attr('class', 'feed-control translate icon-checkbox feedSelect')
.data('title', 'Select this feed (%1)', url)
.attr('title', PTL.tr('Select this feed (%1)', url))
.click(function() {
$(this).parent().parent().parent().parent()
.toggleClass('selected');
$(this).toggleClass('icon-checked icon-checkbox');
});
const $deleteIcon = $('<i>')
.attr('class', 'feed-control translate icon-cancel feed-delete')
.data('title', 'Delete this feed (%1)', url)
.attr('title', PTL.tr('Delete this feed (%1)', url))
.click(function() {
$('.selected').removeClass('selected');
$('.icon-checked').toggleClass('icon-checked icon-checkbox');
PTL.dialog.killFeed($(this));
});
.attr('class', 'feed-control translate icon-trash-empty feed-delete')
.data('title', 'Delete this feed (%1)', url)
.attr('title', PTL.tr('Delete this feed (%1)', url))
.click(function() {
$('.selected').removeClass('selected');
$('.icon-checked').toggleClass('icon-checked icon-checkbox');
PTL.dialog.killFeed($(this));
});
const $prefsIcon = $('<i>')
.attr('class', 'feed-control translate icon-cog feedPrefs')
.data('title', 'Edit this feed (%1) parameters', url)
.attr('title', PTL.tr('Edit this feed (%1) parameters', url))
.click(function() {
$('.selected').removeClass('selected');
$('.icon-checked').toggleClass('icon-checked icon-checkbox');
PTL.dialog.feedPrefs($(this));
});
.attr('class', 'feed-control translate icon-cog feedPrefs')
.data('title', 'Edit this feed (%1) parameters', url)
.attr('title', PTL.tr('Edit this feed (%1) parameters', url))
.click(function() {
$('.selected').removeClass('selected');
$('.icon-checked').toggleClass('icon-checked icon-checkbox');
PTL.dialog.feedPrefs($(this));
});
const $refreshIcon = $('<i>')
.attr('class', 'feed-control translate icon-refresh feedRefresh')
.data('title', 'Refresh this feed (%1)', url)
.attr('title', PTL.tr('Refresh this feed (%1)', url))
.click(async function() {
// var plop = $(this).parent().parent().parent().next('div.feedBody').find('li').lengh;
$('.selected').removeClass('selected');
$('.icon-checked').toggleClass('icon-checked icon-checkbox');
await PTL.feed.populate($(this), progress);
});
.attr('class', 'feed-control translate icon-refresh feedRefresh')
.data('title', 'Refresh this feed (%1)', url)
.attr('title', PTL.tr('Refresh this feed (%1)', url))
.click(async function() {
$('.selected').removeClass('selected');
$('.icon-checked').toggleClass('icon-checked icon-checkbox');
await PTL.feed.populate($(this), progress);
});
const $feedControls = $('<div>')
.attr('class', 'feedControls dataStore')
.data('url', url)
.data('name', name)
.data('type', type)
.data('limit', limit)
.data('status', status)
.data('iconhash', iconhash)
.data('nbitems', nbitems)
.data('lastitem', lastitem);
.attr('class', 'feedControls dataStore')
.data('url', url)
.data('name', name)
.data('type', type)
.data('limit', limit)
.data('status', status)
.data('iconhash', iconhash)
.data('nbitems', nbitems)
.data('lastitem', lastitem);
$refreshIcon
.attr('data-url', url)
......@@ -125,34 +124,34 @@ PTL.feed = {
}
const $feedHandle = $('<div>')
.data('title', PTL.tr('Move this feed (%1)', url))
.attr({
title: PTL.tr('Move this feed (%1)', url),
class:'feedHandle'
});
.data('title', PTL.tr('Move this feed (%1)', url))
.attr({
title: PTL.tr('Move this feed (%1)', url),
class: 'feedHandle'
});
const $feedBody = $('<div>').attr('class', 'feedBody').css('height', limit),
$feedHeader = $('<div>').attr('class', 'feedHeader'),
$feedToggle = $('<div>').attr('class', 'feedToggle').append($feedIcon, $feedImg),
$selectDiv = $('<div>').append($selectIcon),
$deleteDiv = $('<div>').append($deleteIcon),
$prefsDiv = $('<div>').append($prefsIcon),
$reloadDiv = $('<div>').append($refreshIcon);
$feedHeader = $('<div>').attr('class', 'feedHeader'),
$feedToggle = $('<div>').attr('class', 'feedToggle').append($feedIcon, $feedImg),
$selectDiv = $('<div>').append($selectIcon),
$deleteDiv = $('<div>').append($deleteIcon),
$prefsDiv = $('<div>').append($prefsIcon),
$reloadDiv = $('<div>').append($refreshIcon);
const $titleDiv = $('<div>')
.attr({
title: name || PTL.tr('New feed'),
class:'feedTitle trucate'
});
.attr({
title: name || PTL.tr('New feed'),
class: 'feedTitle trucate'
});
const $titleLink = $('<a>')
.attr('href', url)
.attr('target', '_blank')
.html(name || PTL.tr('New feed'));
.attr('href', url)
.attr('target', '_blank')
.html(name || PTL.tr('New feed'));
$feedControls.hover (
function() {$(this).find('.collapsible').show();},
function() {$(this).find('.collapsible').hide('fade', 'fast');}
$feedControls.hover(
function() { $(this).find('.collapsible').show(); },
function() { $(this).find('.collapsible').hide('fade', 'fast'); }
);
if (!PTL.util.isMobile()) {
......@@ -164,7 +163,7 @@ PTL.feed = {
}
$feedHeader.hover (function() {
$feedHeader.hover(function() {
$(this).find('img.favicon').hide();
$feedIcon.removeClass('icon-rss').addClass('icon-down-circle');
......@@ -177,10 +176,10 @@ PTL.feed = {
});
$feedHeader.append($feedToggle,
$feedHandle,
$titleDiv.append($titleLink),
$newItemsBadge,
$feedControls.append($prefsDiv, $reloadDiv));
$feedHandle,
$titleDiv.append($titleLink),
$newItemsBadge,
$feedControls.append($prefsDiv, $reloadDiv));
$feed.append($feedHeader, $feedBody);
......@@ -193,20 +192,18 @@ PTL.feed = {
}
},
lastItems:function(feedItems, $dataStore) {
lastItems: function(feedItems, $dataStore) {
return new Promise((resolve, reject) => {
// console.log('feedItems: %s (%s)', JSON.stringify(feedItems));
const $feedBodyUl = $('<ul>').attr('class', 'feedBody'),
feedUrl = $dataStore.data('url'),
nbItems = $dataStore.data('nbitems'),
feedType = $dataStore.data('type');
feedUrl = $dataStore.data('url'),
nbItems = $dataStore.data('nbitems'),
feedType = $dataStore.data('type');
const l = PTL.util.getLocation(feedUrl),
p = l.protocol ? l.protocol + '//' : '//',
feedHost = p + l.hostname;
p = l.protocol ? l.protocol + '//' : '//',
feedHost = p + l.hostname;
var newItems = 0;
......@@ -218,7 +215,7 @@ PTL.feed = {
if (newItems == nbItems) break;
const $description = $.parseHTML(item.description),
imgTypes = ['image', 'image/jpg', 'image/jpeg', 'image/gif', 'image/png'];
imgTypes = ['image', 'image/jpg', 'image/jpeg', 'image/gif', 'image/png'];
let summary, imageUrl, audioUrl, audioType, videoUrl, videoType;
......@@ -237,12 +234,12 @@ PTL.feed = {
}
const $imageLink = $('<a>').attr('target', '_blank').attr('class', 'imageLink'),
$itemLink = $('<a>').attr('target', '_blank').attr('class', 'itemLink'),
$commentsLink = $('<a>').attr('target', '_blank').attr('class', 'commentsLink'),
$commentsIcon = $('<i>'),
$summary = $('<null>').append(PTL.util.sanitizeInput(summary)).text(),
$itemDiv = $('<div>').attr('class', 'itemDiv'),
$feedItem = $('<li>').attr('class', 'feedItem');
$itemLink = $('<a>').attr('target', '_blank').attr('class', 'itemLink'),
$commentsLink = $('<a>').attr('target', '_blank').attr('class', 'commentsLink'),
$commentsIcon = $('<i>'),
$summary = $('<null>').append(PTL.util.sanitizeInput(summary)).text(),
$itemDiv = $('<div>').attr('class', 'itemDiv'),
$feedItem = $('<li>').attr('class', 'feedItem');
let $image;
......@@ -265,7 +262,6 @@ PTL.feed = {
if (!imageUrl && typeof $tempDom.find('img').attr('src') !== 'undefined') {
imageUrl = $tempDom.find('img').attr('src');
if (typeof $tempDom.find('img').attr('title') !== 'undefined') {
// XKCD summary in the title of the description XML tag
$feedItem.attr('title', $tempDom.find('img').attr('title'));
}
......@@ -316,7 +312,7 @@ PTL.feed = {
if (!videoUrl && imageUrl && typeof imageUrl !== 'undefined' && !imageUrl.includes('pixel')) {
$imageLink
.attr('href', imageUrl.replace('http://','https://'))
.attr('href', imageUrl.replace('http://', 'https://'))
.attr('title', $summary.trim())
.attr('data-fancybox', 'gallery')
.attr('data-caption', '<a href="' + item.link + '" class="ui-button ui-corner-all" title="' + $summary.trim() + '">' + item.title + '</a>');
......@@ -327,7 +323,7 @@ PTL.feed = {
$image = $('<img>')
.attr('src', '/static/images/loading.gif')
.attr('data-srcset', imageUrl.replace('http://','https://'))
.attr('data-srcset', imageUrl.replace('http://', 'https://'))
.attr('srcset', '/static/images/loading.gif')
.attr('title', $summary.trim())
.attr('alt', item['mastodon:scope'] ? $summary.trim() : item.title)
......@@ -366,16 +362,16 @@ PTL.feed = {
});
},
appendAudioPlayer:function($itemDiv, audioUrl, audioType) {
appendAudioPlayer: function($itemDiv, audioUrl, audioType) {
const $audioLink = $('<a>').attr('target', '_blank').attr('class', 'audioLink'),
$audioIcon = $('<i>'),
audioPlayer = document.createElement('audio');
$audioIcon = $('<i>'),
audioPlayer = document.createElement('audio');
audioPlayer.controls = 'controls';
audioPlayer.src = audioUrl;
audioPlayer.type = audioType;
audioPlayer.preload = PTL.prefs.readConfig('mediaPreload');
audioPlayer.src = audioUrl;
audioPlayer.type = audioType;
audioPlayer.preload = PTL.prefs.readConfig('mediaPreload');
$itemDiv.append(audioPlayer);
......@@ -387,16 +383,16 @@ PTL.feed = {
.appendTo($audioLink);
},
appendVideoPlayer:function($itemDiv, videoUrl, videoType) {
appendVideoPlayer: function($itemDiv, videoUrl, videoType) {
const videoPlayer = document.createElement('video'),
$videoIcon = $('<i>'),
$videoLink = $('<a>').attr('target', '_blank').attr('class', 'videoLink');
const videoPlayer = document.createElement('video'),
$videoIcon = $('<i>'),
$videoLink = $('<a>').attr('target', '_blank').attr('class', 'videoLink');
videoPlayer.controls = 'controls';
videoPlayer.src = videoUrl;
videoPlayer.type = videoType;
videoPlayer.preload = PTL.prefs.readConfig('mediaPreload');
videoPlayer.src = videoUrl;
videoPlayer.type = videoType;
videoPlayer.preload = PTL.prefs.readConfig('mediaPreload');
$itemDiv.append(videoPlayer);
......@@ -410,56 +406,65 @@ PTL.feed = {
return $itemDiv;
},
errorFeed:function(error, feedUrl) {
errorFeed: function(error, feedUrl) {
console.log('pow: %s', feedUrl);
const type = (error.statusText) ? error.statusText : PTL.tr('Unknown error');
const errno = (error.responseJSON) ? error.responseJSON.errno : '0';
const message = (error.responseJSON) ? error.responseJSON.message : 'Empty';
const status = error.status;
const message = error.message;
const type = error.type;
const $validateLink = $('<a>')
.attr('href', 'https://validator.w3.org/feed/check.cgi?url=' + feedUrl);
.attr('href', 'https://validator.w3.org/feed/check.cgi?url=' + feedUrl);
const $validateLinkIcon = $('<i>')
.attr('class', 'itemIcon icon-w3c')
.attr('title', PTL.tr('Validate /verify this feed file with the W3C'))
.appendTo($validateLink);
const $reportLink = $('<a>')
.attr('href', 'https://framagit.org/yphil/petrolette/-/issues/new?issue[title]=Feed%20error&issue[description]=' + feedUrl + ' (' + type + ')');
.attr('href', 'https://framagit.org/yphil/petrolette/-/issues/new?issue[title]=Feed%20error&issue[description]=' + feedUrl + ' (' + type + ')');
const $reportLinkIcon = $('<i>')
.attr('class', 'itemIcon icon-petrolette')
.attr('title', PTL.tr('Report feed error'))
.appendTo($reportLink);
const $errKey = $('<strong>')
.attr('class', 'translate key')
.data('content', PTL.tr('Error:'))
.text(PTL.tr('Error:'));
.attr('class', 'translate key')
.data('content', PTL.tr('Type'))
.text(PTL.tr('Type'));
const $msgKey = $('<strong>')
.attr('class', 'translate key')
.data('content', PTL.tr('Message:'))
.text(PTL.tr('Message:'));
.attr('class', 'translate key')
.data('content', PTL.tr('Message'))
.text(PTL.tr('Message'));
const $errValue = $('<strong>')
.attr('class', 'value')
.text(type + ' (' + errno + ')');
.attr('class', 'value')
.text(type + ' (' + status + ')');
const $msgValue = $('<strong>')
.attr('class', 'value')
.text(message);
.attr('class', 'value')
.text(message);
const $errorItem = $('<li>')
.attr('class', 'feedItem error')
.append($validateLink, $reportLink)
.append($errKey)
.append('&nbsp;')
.append($errValue)
.append('<br>')
.append($msgKey)
.append('&nbsp;')
.append($msgValue);
.attr('class', 'feedItem error')
.append($validateLink)
.append($reportLink)
.append($errKey)
.append('&nbsp;:&nbsp;')
.append($errValue)
.append('<br>')
.append($msgKey)
.append('&nbsp;:&nbsp;')
.append($msgValue);
const $feedBodyUl = $('<ul>').attr('class', 'feedBody')
.append($errorItem);
.append($errorItem);
return $feedBodyUl;
},
fetchIcon:function(feedHost) {
fetchIcon: function(feedHost) {
return new Promise((resolve, reject) => {
......@@ -478,7 +483,7 @@ PTL.feed = {
});
},
fetchFeed:function(feedUrl, lastItem, nbItems) {
fetchFeed: function(feedUrl, lastItem, nbItems) {
return new Promise((resolve, reject) => {
$.get("/feed", {
......@@ -486,39 +491,37 @@ PTL.feed = {
dataType: 'json',
lastItem: lastItem,
nbItems: nbItems
}).done(function(data, textStatus, jqXHR) {
}).done(function(data, _textStatus, jqXHR) {
resolve(data);
}).fail(function(jqXHR, textStatus, errorThrown) {
reject(jqXHR);
reject(jqXHR, textStatus, errorThrown);
});
});
},
populate:async function($button, progress, newLimit) {
populate: async function($button, progress, newLimit) {
const $dataStore = $button.parent().parent(),
$refreshButton = $dataStore.find('i.feedRefresh.icon-refresh').addClass('spin'),
$feedHeader = $dataStore.parent(),
$feedLink = $feedHeader.children('div.feedTitle').children('a'),
$badge = $feedHeader.children('.newItemsBadge'),
$feedBody = $dataStore.parent().next('div.feedBody'),
$feedBodyUl = $feedBody.find('ul.feedBody'),
feedUrl = $dataStore.data('url'),
feedIconHash = $dataStore.data('iconhash'),
$feedToggle = $feedHeader.children('.feedToggle'),
$feedIcon = $feedToggle.children('.feedIcon').addClass('fold'),
$favIcon = $feedToggle.children('.favicon');
$refreshButton = $dataStore.find('i.feedRefresh.icon-refresh').addClass('spin'),
$feedHeader = $dataStore.parent(),
$feedLink = $feedHeader.children('div.feedTitle').children('a'),
$badge = $feedHeader.children('.newItemsBadge'),
$feedBody = $dataStore.parent().next('div.feedBody'),
$feedBodyUl = $feedBody.find('ul.feedBody'),
feedUrl = $dataStore.data('url'),
feedIconHash = $dataStore.data('iconhash'),
$feedToggle = $feedHeader.children('.feedToggle'),
$feedIcon = $feedToggle.children('.feedIcon').addClass('fold'),
$favIcon = $feedToggle.children('.favicon');
const l = PTL.util.getLocation(feedUrl),
feedProtocol = l.protocol ? l.protocol + '//' : '//',
feedHost = feedProtocol + l.hostname,
dateObj = new Date(),
timeStamp = dateObj.getUTCHours() + ":" + dateObj.getUTCMinutes() + ":" + dateObj.getUTCSeconds();
feedProtocol = l.protocol ? l.protocol + '//' : '//',
feedHost = feedProtocol + l.hostname,
dateObj = new Date(),
timeStamp = dateObj.getUTCHours() + ":" + dateObj.getUTCMinutes() + ":" + dateObj.getUTCSeconds();
var feedLastItem = $dataStore.data('lastitem');
$feedBodyUl.css('border', '1px solid red');
if ($dataStore.data('status') == 'on') {
$feedIcon.removeClass('fold');
} else {
......@@ -529,57 +532,45 @@ PTL.feed = {
.addClass('folded');
}
// console.log('lastItem: %s', feedLastItem, feedUrl);
if ($dataStore.data('status') == 'on') {
try {
$feedIcon.removeClass('fold');
$refreshButton.addClass('spin');
let fetchFeed = await PTL.feed.fetchFeed(feedUrl, feedLastItem);
let lastItems = await PTL.feed.lastItems(fetchFeed.feedItems, $dataStore);
$feedBody.html(lastItems[0]);
$feedIcon.removeClass('fold');
$refreshButton.addClass('spin');
$refreshButton.removeClass('spin');
let fetchFeed = await PTL.feed.fetchFeed(feedUrl, feedLastItem);
let lastItems = await PTL.feed.lastItems(fetchFeed.feedItems, $dataStore);
if (fetchFeed.totalNewItems > 0) {