summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xclasses/api.php6
-rwxr-xr-xclasses/article.php173
-rwxr-xr-xclasses/feeds.php6
-rwxr-xr-xclasses/handler/public.php13
-rwxr-xr-xclasses/rpc.php2
-rwxr-xr-xinclude/controls.php31
-rw-r--r--js/App.js18
-rw-r--r--js/Article.js58
-rwxr-xr-xjs/Headlines.js2
-rw-r--r--plugins/shorten_expanded/init.js27
10 files changed, 136 insertions, 200 deletions
diff --git a/classes/api.php b/classes/api.php
index 6debad2f7..2531f0017 100755
--- a/classes/api.php
+++ b/classes/api.php
@@ -311,8 +311,6 @@ class API extends Handler {
while ($line = $sth->fetch()) {
- $attachments = Article::get_article_enclosures($line['id']);
-
$article = array(
"id" => $line["id"],
"guid" => $line["guid"],
@@ -326,7 +324,7 @@ class API extends Handler {
"author" => $line["author"],
"updated" => (int) strtotime($line["updated"]),
"feed_id" => $line["feed_id"],
- "attachments" => $attachments,
+ "attachments" => Article::get_enclosures($line['id']),
"score" => (int)$line["score"],
"feed_title" => $line["feed_title"],
"note" => $line["note"],
@@ -736,7 +734,7 @@ class API extends Handler {
"tags" => $tags,
);
- $enclosures = Article::get_article_enclosures($line['id']);
+ $enclosures = Article::get_enclosures($line['id']);
if ($include_attachments)
$headline_row['attachments'] = $enclosures;
diff --git a/classes/article.php b/classes/article.php
index 5ea936985..00d9d09c5 100755
--- a/classes/article.php
+++ b/classes/article.php
@@ -352,145 +352,62 @@ class Article extends Handler_Protected {
}
}
- static function format_article_enclosures($id, $always_display_enclosures,
- $article_content, $hide_images = false) {
-
- $result = self::get_article_enclosures($id);
- $rv = '';
+ static function format_enclosures($id,
+ $always_display_enclosures,
+ $article_content,
+ $hide_images = false) {
+
+ $enclosures = self::get_enclosures($id);
+ $rv = [];
+ $enclosures_formatted = "";
+
+ /*foreach ($enclosures as &$enc) {
+ array_push($enclosures, [
+ "type" => $enc["content_type"],
+ "filename" => basename($enc["content_url"]),
+ "url" => $enc["content_url"],
+ "title" => $enc["title"],
+ "width" => (int) $enc["width"],
+ "height" => (int) $enc["height"]
+ ]);
+ }*/
PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_FORMAT_ENCLOSURES,
- function ($result) use (&$rv) {
+ function ($result) use (&$enclosures_formatted, &$enclosures) {
if (is_array($result)) {
- $rv = $result[0];
- $result = $result[1];
+ $enclosures_formatted = $result[0];
+ $enclosures = $result[1];
} else {
- $rv = $result;
+ $enclosures_formatted = $result;
}
},
- $rv, $result, $id, $always_display_enclosures, $article_content, $hide_images);
-
- if ($rv === '' && !empty($result)) {
- $entries_html = array();
- $entries = array();
- $entries_inline = array();
-
- foreach ($result as $line) {
-
- PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_ENCLOSURE_ENTRY,
- function($result) use (&$line) {
- $line = $result;
- },
- $line, $id);
-
- $url = $line["content_url"];
- $ctype = $line["content_type"];
- $title = $line["title"];
- $width = $line["width"];
- $height = $line["height"];
-
- if (!$ctype) $ctype = __("unknown type");
-
- //$filename = substr($url, strrpos($url, "/")+1);
- $filename = basename($url);
-
- $player = format_inline_player($url, $ctype);
-
- if ($player) array_push($entries_inline, $player);
-
-# $entry .= " <a target=\"_blank\" href=\"" . htmlspecialchars($url) . "\" rel=\"noopener noreferrer\">" .
-# $filename . " (" . $ctype . ")" . "</a>";
-
- $entry = "<div onclick=\"Article.popupOpenUrl('".htmlspecialchars($url)."')\"
- dojoType=\"dijit.MenuItem\">$filename ($ctype)</div>";
-
- array_push($entries_html, $entry);
-
- $entry = array();
-
- $entry["type"] = $ctype;
- $entry["filename"] = $filename;
- $entry["url"] = $url;
- $entry["title"] = $title;
- $entry["width"] = $width;
- $entry["height"] = $height;
+ $enclosures_formatted, $enclosures, $id, $always_display_enclosures, $article_content, $hide_images);
- array_push($entries, $entry);
- }
-
- if ($_SESSION['uid'] && !get_pref("STRIP_IMAGES") && !$_SESSION["bw_limit"]) {
- if ($always_display_enclosures ||
- !preg_match("/<img/i", $article_content)) {
-
- foreach ($entries as $entry) {
-
- $retval = null;
-
- PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_RENDER_ENCLOSURE,
- function($result) use (&$retval) {
- $retval = $result;
- },
- $entry, $hide_images);
-
- if (!empty($retval)) {
- $rv .= $retval;
- } else {
-
- if (preg_match("/image/", $entry["type"])) {
-
- if (!$hide_images) {
- $encsize = '';
- if ($entry['height'] > 0)
- $encsize .= ' height="' . intval($entry['height']) . '"';
- if ($entry['width'] > 0)
- $encsize .= ' width="' . intval($entry['width']) . '"';
- $rv .= "<p><img loading=\"lazy\"
- alt=\"".htmlspecialchars($entry["filename"])."\"
- src=\"" .htmlspecialchars($entry["url"]) . "\"
- " . $encsize . " /></p>";
- } else {
- $rv .= "<p><a target=\"_blank\" rel=\"noopener noreferrer\"
- href=\"".htmlspecialchars($entry["url"])."\"
- >" .htmlspecialchars($entry["url"]) . "</a></p>";
- }
-
- if ($entry['title']) {
- $rv.= "<div class=\"enclosure_title\">${entry['title']}</div>";
- }
- }
- }
- }
- }
- }
-
- if (count($entries_inline) > 0) {
- //$rv .= "<hr clear='both'/>";
- foreach ($entries_inline as $entry) { $rv .= $entry; };
- $rv .= "<br clear='both'/>";
- }
+ if (!empty($enclosures_formatted)) {
+ $rv['formatted'] = $enclosures_formatted;
+ return $rv;
+ }
- $rv .= "<div class=\"attachments\" dojoType=\"fox.form.DropDownButton\">".
- "<span>" . __('Attachments')."</span>";
+ $rv['can_inline'] = isset($_SESSION["uid"]) &&
+ empty($_SESSION["bw_limit"]) &&
+ !get_pref("STRIP_IMAGES") &&
+ ($always_display_enclosures || !preg_match("/<img/i", $article_content));
- $rv .= "<div dojoType=\"dijit.Menu\" style=\"display: none;\">";
+ $rv['inline_text_only'] = $hide_images && $rv['can_inline'];
- foreach ($entries as $entry) {
- if ($entry["title"])
- $title = " &mdash; " . truncate_string($entry["title"], 30);
- else
- $title = "";
+ $rv['entries'] = [];
- if ($entry["filename"])
- $filename = truncate_middle(htmlspecialchars($entry["filename"]), 60);
- else
- $filename = "";
+ foreach ($enclosures as $enc) {
- $rv .= "<div onclick='Article.popupOpenUrl(\"".htmlspecialchars($entry["url"])."\")'
- dojoType=\"dijit.MenuItem\">".$filename . $title."</div>";
+ // this is highly approximate
+ $enc["filename"] = basename($enc["content_url"]);
- };
-
- $rv .= "</div>";
- $rv .= "</div>";
+ PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_ENCLOSURE_ENTRY,
+ function ($result) use (&$enc) {
+ $enc = $result;
+ },
+ $enc, $id);
+ array_push($rv['entries'], $enc);
}
return $rv;
@@ -613,7 +530,7 @@ class Article extends Handler_Protected {
}
}
- static function get_article_enclosures($id) {
+ static function get_enclosures($id) {
$pdo = Db::pdo();
@@ -625,7 +542,7 @@ class Article extends Handler_Protected {
$cache = new DiskCache("images");
- while ($line = $sth->fetch()) {
+ while ($line = $sth->fetch(PDO::FETCH_ASSOC)) {
if ($cache->exists(sha1($line["content_url"]))) {
$line["content_url"] = $cache->getUrl(sha1($line["content_url"]));
diff --git a/classes/feeds.php b/classes/feeds.php
index ba320b52f..d49fe7698 100755
--- a/classes/feeds.php
+++ b/classes/feeds.php
@@ -283,8 +283,10 @@ class Feeds extends Handler_Protected {
$this->mark_timestamp(" pre-enclosures");
- $line["enclosures"] = Article::format_article_enclosures($id, $line["always_display_enclosures"],
- $line["content"], $line["hide_images"]);
+ $line["enclosures"] = Article::format_enclosures($id,
+ $line["always_display_enclosures"],
+ $line["content"],
+ $line["hide_images"]);
$this->mark_timestamp(" enclosures");
diff --git a/classes/handler/public.php b/classes/handler/public.php
index 79f3a9e6c..0613e9a28 100755
--- a/classes/handler/public.php
+++ b/classes/handler/public.php
@@ -131,7 +131,7 @@ class Handler_Public extends Handler {
$tpl->addBlock('category');
}
- $enclosures = Article::get_article_enclosures($line["id"]);
+ $enclosures = Article::get_enclosures($line["id"]);
if (count($enclosures) > 0) {
foreach ($enclosures as $e) {
@@ -218,7 +218,7 @@ class Handler_Public extends Handler {
}
}
- $enclosures = Article::get_article_enclosures($line["id"]);
+ $enclosures = Article::get_enclosures($line["id"]);
if (count($enclosures) > 0) {
$article['enclosures'] = array();
@@ -356,9 +356,7 @@ class Handler_Public extends Handler {
$line['content'] = DiskCache::rewriteUrls($line['content']);
- $enclosures = Article::get_article_enclosures($line["id"]);
-
- header("Content-Type: text/html");
+ header("Content-Type: text/html");
$rv .= "<!DOCTYPE html>
<html><head>
@@ -392,6 +390,7 @@ class Handler_Public extends Handler {
$rv .= "</head>";
+ $enclosures = Article::get_enclosures($line["id"]);
list ($og_image, $og_stream) = Article::get_article_image($enclosures, $line['content'], $line["site_url"]);
if ($og_image) {
@@ -436,10 +435,10 @@ class Handler_Public extends Handler {
$rv .= $line["content"];
- $rv .= Article::format_article_enclosures($id,
+ /* $rv .= Article::format_article_enclosures($id,
$line["always_display_enclosures"],
$line["content"],
- $line["hide_images"]);
+ $line["hide_images"]); */
$rv .= "</div>"; # content
diff --git a/classes/rpc.php b/classes/rpc.php
index f6b57775d..e0753a08e 100755
--- a/classes/rpc.php
+++ b/classes/rpc.php
@@ -192,9 +192,7 @@ class RPC extends Handler_Protected {
}
function sanityCheck() {
- $_SESSION["hasAudio"] = clean($_REQUEST["hasAudio"]) === "true";
$_SESSION["hasSandbox"] = clean($_REQUEST["hasSandbox"]) === "true";
- $_SESSION["hasMp3"] = clean($_REQUEST["hasMp3"]) === "true";
$_SESSION["clientTzOffset"] = clean($_REQUEST["clientTzOffset"]);
$reply = array();
diff --git a/include/controls.php b/include/controls.php
index e6678db9a..f706931db 100755
--- a/include/controls.php
+++ b/include/controls.php
@@ -298,37 +298,6 @@ function print_error($msg) {
return print format_error($msg);
}
-function format_inline_player($url, $ctype) {
-
- $entry = "";
-
- $url = htmlspecialchars($url);
-
- if (strpos($ctype, "audio/") === 0) {
-
- $entry .= "<div class='inline-player'>";
-
- if ($_SESSION["hasAudio"] && (strpos($ctype, "ogg") !== false ||
- $_SESSION["hasMp3"])) {
-
- $entry .= "<audio preload=\"none\" controls>
- <source type=\"$ctype\" src=\"$url\"/>
- </audio> ";
-
- }
-
- if ($entry) $entry .= "<a target=\"_blank\" rel=\"noopener noreferrer\"
- href=\"$url\">" . basename($url) . "</a>";
-
- $entry .= "</div>";
-
- return $entry;
-
- }
-
- return "";
-}
-
function print_label_select($name, $value, $attributes = "") {
$pdo = Db::pdo();
diff --git a/js/App.js b/js/App.js
index 0a72d1b12..3a31438c5 100644
--- a/js/App.js
+++ b/js/App.js
@@ -586,6 +586,10 @@ const App = {
isPrefs() {
return this.is_prefs;
},
+ audioCanPlay: function(ctype) {
+ const a = document.createElement('audio');
+ return a.canPlayType(ctype);
+ },
init: function(parser, is_prefs) {
this.is_prefs = is_prefs;
window.onerror = this.Error.onWindowError;
@@ -604,17 +608,11 @@ const App = {
this.initHotkeyActions();
this.enableCsrfSupport();
- const a = document.createElement('audio');
- const hasAudio = !!a.canPlayType;
- const hasSandbox = "sandbox" in document.createElement("iframe");
- const hasMp3 = !!(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, ''));
- const clientTzOffset = new Date().getTimezoneOffset() * 60;
-
const params = {
- op: "rpc", method: "sanityCheck", hasAudio: hasAudio,
- hasMp3: hasMp3,
- clientTzOffset: clientTzOffset,
- hasSandbox: hasSandbox
+ op: "rpc",
+ method: "sanityCheck",
+ clientTzOffset: new Date().getTimezoneOffset() * 60,
+ hasSandbox: "sandbox" in document.createElement("iframe")
};
xhrPost("backend.php", params, (transport) => {
diff --git a/js/Article.js b/js/Article.js
index f8b0415b9..efe33bc99 100644
--- a/js/Article.js
+++ b/js/Article.js
@@ -140,6 +140,62 @@ const Article = {
Headlines.toggleUnread(id, 0);
},
+ renderEnclosures: function (enclosures) {
+
+ // enclosure list was handled by backend (HOOK_FORMAT_ENCLOSURES)
+ if (enclosures.formatted)
+ return enclosures.formatted;
+
+ return `
+ ${enclosures.can_inline ?
+ `<div class='attachments-inline'>
+ ${enclosures.entries.map((enc) => {
+ if (!enclosures.inline_text_only) {
+ if (enc.content_type && enc.content_type.indexOf("image/") != -1) {
+ return `<p>
+ <img loading="lazy"
+ width="${enc.width ? enc.width : ''}"
+ height="${enc.height ? enc.height : ''}"
+ src="${App.escapeHtml(enc.content_url)}"
+ title="${App.escapeHtml(enc.title ? enc.title : enc.content_url)}"/>
+ </p>`
+ } else if (enc.content_type && enc.content_type.indexOf("audio/") != -1 && App.audioCanPlay(enc.content_type)) {
+ return `<p class='inline-player' title="${App.escapeHtml(enc.content_url)}">
+ <audio preload="none" controls="controls">
+ <source type="${App.escapeHtml(enc.content_type)}" src="${App.escapeHtml(enc.content_url)}"/>
+ </audio>
+ </p>
+ `;
+ } else {
+ return `<p>
+ <a target="_blank" href="${App.escapeHtml(enc.content_url)}"
+ title="${App.escapeHtml(enc.title ? enc.title : enc.content_url)}"
+ rel="noopener noreferrer">${App.escapeHtml(enc.content_url)}</a>
+ </p>`
+ }
+ } else {
+ return `<p>
+ <a target="_blank" href="${App.escapeHtml(enc.content_url)}"
+ title="${App.escapeHtml(enc.title ? enc.title : enc.content_url)}"
+ rel="noopener noreferrer">${App.escapeHtml(enc.content_url)}</a>
+ </p>`
+ }
+ }).join("")}
+ </div>` : ''}
+ ${enclosures.entries.length > 0 ?
+ `<div class="attachments" dojoType="fox.form.DropDownButton">
+ <span>${__('Attachments')}</span>
+ <div dojoType="dijit.Menu" style="display: none">
+ ${enclosures.entries.map((enc) => `
+ <div onclick='Article.popupOpenUrl("${App.escapeHtml(enc.content_url)}")'
+ title="${App.escapeHtml(enc.title ? enc.title : enc.content_url)}" dojoType="dijit.MenuItem">
+ ${enc.title ? enc.title : enc.filename}
+ </div>
+ `).join("")}
+ </div>
+ </div>` : ''}
+ `
+ },
render: function (article) {
App.cleanupMemory("content-insert");
@@ -241,7 +297,7 @@ const Article = {
<div id="POSTNOTE-${hl.id}">${hl.note}</div>
<div class="content" lang="${hl.lang ? hl.lang : 'en'}">
${hl.content}
- ${hl.enclosures}
+ ${Article.renderEnclosures(hl.enclosures)}
</div>
</div>`;
diff --git a/js/Headlines.js b/js/Headlines.js
index 94541b974..dadf79c1a 100755
--- a/js/Headlines.js
+++ b/js/Headlines.js
@@ -488,7 +488,7 @@ const Headlines = {
<img src="${App.getInitParam('icon_indicator_white')}">
</div>
<div class="intermediate">
- ${hl.enclosures}
+ ${Article.renderEnclosures(hl.enclosures)}
</div>
<div class="footer" onclick="event.stopPropagation()">
diff --git a/plugins/shorten_expanded/init.js b/plugins/shorten_expanded/init.js
index 30bfac6ba..181e426a4 100644
--- a/plugins/shorten_expanded/init.js
+++ b/plugins/shorten_expanded/init.js
@@ -1,3 +1,5 @@
+/* global Plugins, __, require, PluginHost */
+
const _shorten_expanded_threshold = 1.5; //window heights
Plugins.Shorten_Expanded = {
@@ -22,26 +24,23 @@ require(['dojo/_base/kernel', 'dojo/ready'], function (dojo, ready) {
window.setTimeout(function() {
if (row) {
- const c_inner = row.select(".content-inner")[0];
- const c_inter = row.select(".intermediate")[0];
+ const content = row.querySelector(".content-inner");
+ const attachments = row.querySelector(".attachments-inline");
- if (c_inner && c_inter &&
+ if (content && attachments &&
row.offsetHeight >= _shorten_expanded_threshold * window.innerHeight) {
- let tmp = document.createElement("div");
-
- c_inter.select("> *:not([class*='attachments'])").each(function(p) {
- p.parentNode.removeChild(p);
- tmp.appendChild(p);
- });
-
- c_inner.innerHTML = `<div class="content-shrink-wrap">
- ${c_inner.innerHTML}
- ${tmp.innerHTML}</div>
+ content.innerHTML = `
+ <div class="content-shrink-wrap">
+ ${content.innerHTML}
+ ${attachments.innerHTML}
+ </div>
<button dojoType="dijit.form.Button" class="alt-info expand-prompt" onclick="return Plugins.Shorten_Expanded.expand('${row.id}')" href="#">
${__("Click to expand article")}</button>`;
- dojo.parser.parse(c_inner);
+ attachments.innerHTML = "";
+
+ dojo.parser.parse(content);
}
}
}, 150);