2
.gitignore
vendored
@@ -2,13 +2,13 @@
|
||||
*~
|
||||
*.DS_Store
|
||||
#*
|
||||
lib/floIcon.php
|
||||
.idea/*
|
||||
config.php
|
||||
feed-icons/*
|
||||
cache/*/*
|
||||
lock/*
|
||||
tags
|
||||
plugins/fever
|
||||
cache/htmlpurifier/*/*ser
|
||||
lib/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/*/*ser
|
||||
web.config
|
||||
|
||||
17
README.md
@@ -4,12 +4,25 @@ Tiny Tiny RSS
|
||||
Web-based news feed aggregator, designed to allow you to read news from
|
||||
any location, while feeling as close to a real desktop application as possible.
|
||||
|
||||
http://tt-rss.org
|
||||
http://tt-rss.org (http://mirror.tt-rss.org)
|
||||
|
||||
Licensed under GNU GPL version 2
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright (c) 2005 Andrew Dolgov (unless explicitly stated otherwise).
|
||||
|
||||
Uses Silk icons by Mark James: http://www.famfamfam.com/lab/icons/silk/
|
||||
|
||||
## Requirements
|
||||
|
||||
* Compatible web browser (http://tt-rss.org/wiki/CompatibleBrowsers)
|
||||
|
||||
@@ -21,9 +21,6 @@
|
||||
|
||||
<div class="rss">
|
||||
|
||||
<img class="feedicon" src="images/pub_set.svg" style="width : 64px; height : 64px;"
|
||||
alt="feed icon"/>
|
||||
|
||||
<h1><xsl:value-of select="atom:title"/></h1>
|
||||
|
||||
<p class="description">This feed has been exported from
|
||||
|
||||
101
classes/api.php
@@ -2,7 +2,7 @@
|
||||
|
||||
class API extends Handler {
|
||||
|
||||
const API_LEVEL = 7;
|
||||
const API_LEVEL = 9;
|
||||
|
||||
const STATUS_OK = 0;
|
||||
const STATUS_ERR = 1;
|
||||
@@ -77,6 +77,7 @@ class API extends Handler {
|
||||
$this->wrap(self::STATUS_OK, array("session_id" => session_id(),
|
||||
"api_level" => self::API_LEVEL));
|
||||
} else { // else we are not logged in
|
||||
user_error("Failed login attempt for $login from {$_SERVER['REMOTE_ADDR']}", E_USER_WARNING);
|
||||
$this->wrap(self::STATUS_ERR, array("error" => "LOGIN_ERROR"));
|
||||
}
|
||||
} else {
|
||||
@@ -199,11 +200,15 @@ class API extends Handler {
|
||||
$include_nested = sql_bool_to_bool($_REQUEST["include_nested"]);
|
||||
$sanitize_content = !isset($_REQUEST["sanitize"]) ||
|
||||
sql_bool_to_bool($_REQUEST["sanitize"]);
|
||||
$force_update = sql_bool_to_bool($_REQUEST["force_update"]);
|
||||
|
||||
$override_order = false;
|
||||
switch ($_REQUEST["order_by"]) {
|
||||
case "title":
|
||||
$override_order = "ttrss_entries.title";
|
||||
break;
|
||||
case "date_reverse":
|
||||
$override_order = "date_entered, updated";
|
||||
$override_order = "score DESC, date_entered, updated";
|
||||
break;
|
||||
case "feed_dates":
|
||||
$override_order = "updated DESC";
|
||||
@@ -218,7 +223,7 @@ class API extends Handler {
|
||||
$headlines = $this->api_get_headlines($feed_id, $limit, $offset,
|
||||
$filter, $is_cat, $show_excerpt, $show_content, $view_mode, $override_order,
|
||||
$include_attachments, $since_id, $search, $search_mode,
|
||||
$include_nested, $sanitize_content);
|
||||
$include_nested, $sanitize_content, $force_update);
|
||||
|
||||
$this->wrap(self::STATUS_OK, $headlines);
|
||||
} else {
|
||||
@@ -309,8 +314,8 @@ class API extends Handler {
|
||||
|
||||
if ($article_id) {
|
||||
|
||||
$query = "SELECT id,title,link,content,cached_content,feed_id,comments,int_id,
|
||||
marked,unread,published,score,
|
||||
$query = "SELECT id,title,link,content,feed_id,comments,int_id,
|
||||
marked,unread,published,score,note,lang,
|
||||
".SUBSTRING_FOR_DATE."(updated,1,16) as updated,
|
||||
author,(SELECT title FROM ttrss_feeds WHERE id = feed_id) AS feed_title
|
||||
FROM ttrss_entries,ttrss_user_entries
|
||||
@@ -338,11 +343,13 @@ class API extends Handler {
|
||||
"comments" => $line["comments"],
|
||||
"author" => $line["author"],
|
||||
"updated" => (int) strtotime($line["updated"]),
|
||||
"content" => $line["cached_content"] != "" ? $line["cached_content"] : $line["content"],
|
||||
"content" => $line["content"],
|
||||
"feed_id" => $line["feed_id"],
|
||||
"attachments" => $attachments,
|
||||
"score" => (int)$line["score"],
|
||||
"feed_title" => $line["feed_title"]
|
||||
"feed_title" => $line["feed_title"],
|
||||
"note" => $line["note"],
|
||||
"lang" => $line["lang"]
|
||||
);
|
||||
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE_API) as $p) {
|
||||
@@ -423,14 +430,14 @@ class API extends Handler {
|
||||
|
||||
$checked = false;
|
||||
foreach ($article_labels as $al) {
|
||||
if ($al[0] == $line['id']) {
|
||||
if (feed_to_label_id($al[0]) == $line['id']) {
|
||||
$checked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
array_push($rv, array(
|
||||
"id" => (int)$line['id'],
|
||||
"id" => (int)label_to_feed_id($line['id']),
|
||||
"caption" => $line['caption'],
|
||||
"fg_color" => $line['fg_color'],
|
||||
"bg_color" => $line['bg_color'],
|
||||
@@ -447,7 +454,7 @@ class API extends Handler {
|
||||
$assign = (bool) $this->dbh->escape_string($_REQUEST['assign']) == "true";
|
||||
|
||||
$label = $this->dbh->escape_string(label_find_caption(
|
||||
$label_id, $_SESSION["uid"]));
|
||||
feed_to_label_id($label_id), $_SESSION["uid"]));
|
||||
|
||||
$num_updated = 0;
|
||||
|
||||
@@ -511,7 +518,7 @@ class API extends Handler {
|
||||
if ($unread || !$unread_only) {
|
||||
|
||||
$row = array(
|
||||
"id" => $cv["id"],
|
||||
"id" => (int) $cv["id"],
|
||||
"title" => $cv["description"],
|
||||
"unread" => $cv["counter"],
|
||||
"cat_id" => -2,
|
||||
@@ -557,7 +564,7 @@ class API extends Handler {
|
||||
|
||||
if ($unread || !$unread_only) {
|
||||
$row = array(
|
||||
"id" => $line["id"],
|
||||
"id" => (int) $line["id"],
|
||||
"title" => $line["title"],
|
||||
"unread" => $unread,
|
||||
"is_cat" => true,
|
||||
@@ -626,7 +633,28 @@ class API extends Handler {
|
||||
$filter, $is_cat, $show_excerpt, $show_content, $view_mode, $order,
|
||||
$include_attachments, $since_id,
|
||||
$search = "", $search_mode = "",
|
||||
$include_nested = false, $sanitize_content = true) {
|
||||
$include_nested = false, $sanitize_content = true, $force_update = false) {
|
||||
|
||||
if ($force_update && $feed_id > 0 && is_numeric($feed_id)) {
|
||||
// Update the feed if required with some basic flood control
|
||||
|
||||
$result = db_query(
|
||||
"SELECT cache_images,".SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated
|
||||
FROM ttrss_feeds WHERE id = '$feed_id'");
|
||||
|
||||
if (db_num_rows($result) != 0) {
|
||||
$last_updated = strtotime(db_fetch_result($result, 0, "last_updated"));
|
||||
$cache_images = sql_bool_to_bool(db_fetch_result($result, 0, "cache_images"));
|
||||
|
||||
if (!$cache_images && time() - $last_updated > 120) {
|
||||
include "rssfuncs.php";
|
||||
update_rss_feed($feed_id, true, true);
|
||||
} else {
|
||||
db_query("UPDATE ttrss_feeds SET last_updated = '1970-01-01', last_update_started = '1970-01-01'
|
||||
WHERE id = '$feed_id'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$qfh_ret = queryFeedHeadlines($feed_id, $limit,
|
||||
$view_mode, $is_cat, $search, $search_mode,
|
||||
@@ -638,11 +666,31 @@ class API extends Handler {
|
||||
$headlines = array();
|
||||
|
||||
while ($line = db_fetch_assoc($result)) {
|
||||
$line["content_preview"] = truncate_string(strip_tags($line["content"]), 100);
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
|
||||
$line = $p->hook_query_headlines($line, 100, true);
|
||||
}
|
||||
|
||||
$is_updated = ($line["last_read"] == "" &&
|
||||
($line["unread"] != "t" && $line["unread"] != "1"));
|
||||
|
||||
$tags = explode(",", $line["tag_cache"]);
|
||||
$labels = json_decode($line["label_cache"], true);
|
||||
|
||||
$label_cache = $line["label_cache"];
|
||||
$labels = false;
|
||||
|
||||
if ($label_cache) {
|
||||
$label_cache = json_decode($label_cache, true);
|
||||
|
||||
if ($label_cache) {
|
||||
if ($label_cache["no-labels"] == 1)
|
||||
$labels = array();
|
||||
else
|
||||
$labels = $label_cache;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_array($labels)) $labels = get_article_labels($line["id"]);
|
||||
|
||||
//if (!$tags) $tags = get_article_tags($line["id"]);
|
||||
//if (!$labels) $labels = get_article_labels($line["id"]);
|
||||
@@ -660,28 +708,22 @@ class API extends Handler {
|
||||
"tags" => $tags,
|
||||
);
|
||||
|
||||
if ($include_attachments)
|
||||
$headline_row['attachments'] = get_article_enclosures(
|
||||
$line['id']);
|
||||
if ($include_attachments)
|
||||
$headline_row['attachments'] = get_article_enclosures(
|
||||
$line['id']);
|
||||
|
||||
if ($show_excerpt) {
|
||||
$excerpt = truncate_string(strip_tags($line["content_preview"]), 100);
|
||||
$headline_row["excerpt"] = $excerpt;
|
||||
}
|
||||
if ($show_excerpt)
|
||||
$headline_row["excerpt"] = $line["content_preview"];
|
||||
|
||||
if ($show_content) {
|
||||
|
||||
if ($line["cached_content"] != "") {
|
||||
$line["content_preview"] =& $line["cached_content"];
|
||||
}
|
||||
|
||||
if ($sanitize_content) {
|
||||
$headline_row["content"] = sanitize(
|
||||
$line["content_preview"],
|
||||
$line["content"],
|
||||
sql_bool_to_bool($line['hide_images']),
|
||||
false, $line["site_url"]);
|
||||
false, $line["site_url"], false, $line["id"]);
|
||||
} else {
|
||||
$headline_row["content"] = $line["content_preview"];
|
||||
$headline_row["content"] = $line["content"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,7 +741,10 @@ class API extends Handler {
|
||||
$headline_row["always_display_attachments"] = sql_bool_to_bool($line["always_display_enclosures"]);
|
||||
|
||||
$headline_row["author"] = $line["author"];
|
||||
|
||||
$headline_row["score"] = (int)$line["score"];
|
||||
$headline_row["note"] = $line["note"];
|
||||
$headline_row["lang"] = $line["lang"];
|
||||
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE_API) as $p) {
|
||||
$headline_row = $p->hook_render_article_api(array("headline" => $headline_row));
|
||||
|
||||
@@ -30,7 +30,6 @@ class Article extends Handler_Protected {
|
||||
$id = $this->dbh->escape_string($_REQUEST["id"]);
|
||||
$cids = explode(",", $this->dbh->escape_string($_REQUEST["cids"]));
|
||||
$mode = $this->dbh->escape_string($_REQUEST["mode"]);
|
||||
$omode = $this->dbh->escape_string($_REQUEST["omode"]);
|
||||
|
||||
// in prefetch mode we only output requested cids, main article
|
||||
// just gets marked as read (it already exists in client cache)
|
||||
@@ -108,7 +107,7 @@ class Article extends Handler_Protected {
|
||||
|
||||
// only check for our user data here, others might have shared this with different content etc
|
||||
$result = db_query("SELECT id FROM ttrss_entries, ttrss_user_entries WHERE
|
||||
link = '$url' AND ref_id = id AND owner_uid = '$owner_uid' LIMIT 1");
|
||||
guid = '$guid' AND ref_id = id AND owner_uid = '$owner_uid' LIMIT 1");
|
||||
|
||||
if (db_num_rows($result) != 0) {
|
||||
$ref_id = db_fetch_result($result, 0, "id");
|
||||
|
||||
@@ -26,9 +26,12 @@ class Db_Mysql implements IDb {
|
||||
}
|
||||
|
||||
function query($query, $die_on_error = true) {
|
||||
$result = mysql_query($query, $this->link);
|
||||
$result = @mysql_query($query, $this->link);
|
||||
if (!$result) {
|
||||
user_error("Query $query failed: " . ($this->link ? mysql_error($this->link) : "No connection"),
|
||||
$error = @mysql_error($this->link);
|
||||
|
||||
@mysql_query("ROLLBACK", $this->link);
|
||||
user_error("Query $query failed: " . ($this->link ? $error : "No connection"),
|
||||
$die_on_error ? E_USER_ERROR : E_USER_WARNING);
|
||||
}
|
||||
return $result;
|
||||
|
||||
@@ -24,9 +24,12 @@ class Db_Mysqli implements IDb {
|
||||
}
|
||||
|
||||
function query($query, $die_on_error = true) {
|
||||
$result = mysqli_query($this->link, $query);
|
||||
$result = @mysqli_query($this->link, $query);
|
||||
if (!$result) {
|
||||
user_error("Query $query failed: " . ($this->link ? mysqli_error($this->link) : "No connection"),
|
||||
$error = @mysqli_error($this->link);
|
||||
|
||||
@mysqli_query($this->link, "ROLLBACK");
|
||||
user_error("Query $query failed: " . ($this->link ? $error : "No connection"),
|
||||
$die_on_error ? E_USER_ERROR : E_USER_WARNING);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,11 +35,14 @@ class Db_Pgsql implements IDb {
|
||||
}
|
||||
|
||||
function query($query, $die_on_error = true) {
|
||||
$result = pg_query($query);
|
||||
$result = @pg_query($this->link, $query);
|
||||
|
||||
if (!$result) {
|
||||
$error = @pg_last_error($this->link);
|
||||
|
||||
@pg_query($this->link, "ROLLBACK");
|
||||
$query = htmlspecialchars($query); // just in case
|
||||
user_error("Query $query failed: " . ($this->link ? pg_last_error($this->link) : "No connection"),
|
||||
user_error("Query $query failed: " . ($this->link ? $error : "No connection"),
|
||||
$die_on_error ? E_USER_ERROR : E_USER_WARNING);
|
||||
}
|
||||
return $result;
|
||||
|
||||
@@ -16,7 +16,6 @@ class Dlg extends Handler_Protected {
|
||||
print __("If you have imported labels and/or filters, you might need to reload preferences to see your new data.") . "</p>";
|
||||
|
||||
print "<div class=\"prefFeedOPMLHolder\">";
|
||||
$owner_uid = $_SESSION["uid"];
|
||||
|
||||
$this->dbh->query("BEGIN");
|
||||
|
||||
@@ -176,7 +175,7 @@ class Dlg extends Handler_Protected {
|
||||
|
||||
while ($row = $this->dbh->fetch_assoc($result)) {
|
||||
$tmp = htmlspecialchars($row["tag_name"]);
|
||||
print "<option value=\"" . str_replace(" ", "%20", $tmp) . "\">$tmp</option>";
|
||||
print "<option value=\"$tmp\">$tmp</option>";
|
||||
}
|
||||
|
||||
print "</select>";
|
||||
|
||||
@@ -3,5 +3,8 @@ class FeedEnclosure {
|
||||
public $link;
|
||||
public $type;
|
||||
public $length;
|
||||
public $title;
|
||||
public $height;
|
||||
public $width;
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
class FeedItem_Atom extends FeedItem_Common {
|
||||
|
||||
function get_id() {
|
||||
$id = $this->elem->getElementsByTagName("id")->item(0);
|
||||
|
||||
@@ -30,6 +31,7 @@ class FeedItem_Atom extends FeedItem_Common {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function get_link() {
|
||||
$links = $this->elem->getElementsByTagName("link");
|
||||
|
||||
@@ -38,8 +40,13 @@ class FeedItem_Atom extends FeedItem_Common {
|
||||
(!$link->hasAttribute("rel")
|
||||
|| $link->getAttribute("rel") == "alternate"
|
||||
|| $link->getAttribute("rel") == "standout")) {
|
||||
$base = $this->xpath->evaluate("string(ancestor-or-self::*[@xml:base][1]/@xml:base)", $link);
|
||||
|
||||
if ($base)
|
||||
return rewrite_relative_url($base, trim($link->getAttribute("href")));
|
||||
else
|
||||
return trim($link->getAttribute("href"));
|
||||
|
||||
return $link->getAttribute("href");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +55,7 @@ class FeedItem_Atom extends FeedItem_Common {
|
||||
$title = $this->elem->getElementsByTagName("title")->item(0);
|
||||
|
||||
if ($title) {
|
||||
return $title->nodeValue;
|
||||
return trim($title->nodeValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +65,13 @@ class FeedItem_Atom extends FeedItem_Common {
|
||||
if ($content) {
|
||||
if ($content->hasAttribute('type')) {
|
||||
if ($content->getAttribute('type') == 'xhtml') {
|
||||
return $this->doc->saveXML($content->firstChild->nextSibling);
|
||||
for ($i = 0; $i < $content->childNodes->length; $i++) {
|
||||
$child = $content->childNodes->item($i);
|
||||
|
||||
if ($child->hasChildNodes()) {
|
||||
return $this->doc->saveXML($child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +85,13 @@ class FeedItem_Atom extends FeedItem_Common {
|
||||
if ($content) {
|
||||
if ($content->hasAttribute('type')) {
|
||||
if ($content->getAttribute('type') == 'xhtml') {
|
||||
return $this->doc->saveXML($content->firstChild->nextSibling);
|
||||
for ($i = 0; $i < $content->childNodes->length; $i++) {
|
||||
$child = $content->childNodes->item($i);
|
||||
|
||||
if ($child->hasChildNodes()) {
|
||||
return $this->doc->saveXML($child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,13 +106,13 @@ class FeedItem_Atom extends FeedItem_Common {
|
||||
|
||||
foreach ($categories as $cat) {
|
||||
if ($cat->hasAttribute("term"))
|
||||
array_push($cats, $cat->getAttribute("term"));
|
||||
array_push($cats, trim($cat->getAttribute("term")));
|
||||
}
|
||||
|
||||
$categories = $this->xpath->query("dc:subject", $this->elem);
|
||||
|
||||
foreach ($categories as $cat) {
|
||||
array_push($cats, $cat->nodeValue);
|
||||
array_push($cats, trim($cat->nodeValue));
|
||||
}
|
||||
|
||||
return $cats;
|
||||
@@ -126,6 +145,51 @@ class FeedItem_Atom extends FeedItem_Common {
|
||||
$enc->type = $enclosure->getAttribute("type");
|
||||
$enc->link = $enclosure->getAttribute("url");
|
||||
$enc->length = $enclosure->getAttribute("length");
|
||||
$enc->height = $enclosure->getAttribute("height");
|
||||
$enc->width = $enclosure->getAttribute("width");
|
||||
|
||||
$desc = $this->xpath->query("media:description", $enclosure)->item(0);
|
||||
if ($desc) $enc->title = strip_tags($desc->nodeValue);
|
||||
|
||||
array_push($encs, $enc);
|
||||
}
|
||||
|
||||
|
||||
$enclosures = $this->xpath->query("media:group", $this->elem);
|
||||
|
||||
foreach ($enclosures as $enclosure) {
|
||||
$enc = new FeedEnclosure();
|
||||
|
||||
$content = $this->xpath->query("media:content", $enclosure)->item(0);
|
||||
|
||||
if ($content) {
|
||||
$enc->type = $content->getAttribute("type");
|
||||
$enc->link = $content->getAttribute("url");
|
||||
$enc->length = $content->getAttribute("length");
|
||||
$enc->height = $content->getAttribute("height");
|
||||
$enc->width = $content->getAttribute("width");
|
||||
|
||||
$desc = $this->xpath->query("media:description", $content)->item(0);
|
||||
if ($desc) {
|
||||
$enc->title = strip_tags($desc->nodeValue);
|
||||
} else {
|
||||
$desc = $this->xpath->query("media:description", $enclosure)->item(0);
|
||||
if ($desc) $enc->title = strip_tags($desc->nodeValue);
|
||||
}
|
||||
|
||||
array_push($encs, $enc);
|
||||
}
|
||||
}
|
||||
|
||||
$enclosures = $this->xpath->query("media:thumbnail", $this->elem);
|
||||
|
||||
foreach ($enclosures as $enclosure) {
|
||||
$enc = new FeedEnclosure();
|
||||
|
||||
$enc->type = "image/generic";
|
||||
$enc->link = $enclosure->getAttribute("url");
|
||||
$enc->height = $enclosure->getAttribute("height");
|
||||
$enc->width = $enclosure->getAttribute("width");
|
||||
|
||||
array_push($encs, $enc);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,17 @@ abstract class FeedItem_Common extends FeedItem {
|
||||
$this->elem = $elem;
|
||||
$this->xpath = $xpath;
|
||||
$this->doc = $doc;
|
||||
|
||||
try {
|
||||
|
||||
$source = $elem->getElementsByTagName("source")->item(0);
|
||||
|
||||
// we don't need <source> element
|
||||
if ($source)
|
||||
$elem->removeChild($source);
|
||||
} catch (DOMException $e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
function get_author() {
|
||||
@@ -33,13 +44,26 @@ abstract class FeedItem_Common extends FeedItem {
|
||||
}
|
||||
}
|
||||
|
||||
// todo
|
||||
function get_comments_url() {
|
||||
//RSS only. Use a query here to avoid namespace clashes (e.g. with slash).
|
||||
//might give a wrong result if a default namespace was declared (possible with XPath 2.0)
|
||||
$com_url = $this->xpath->query("comments", $this->elem)->item(0);
|
||||
|
||||
if($com_url)
|
||||
return $com_url->nodeValue;
|
||||
|
||||
//Atom Threading Extension (RFC 4685) stuff. Could be used in RSS feeds, so it's in common.
|
||||
//'text/html' for type is too restrictive?
|
||||
$com_url = $this->xpath->query("atom:link[@rel='replies' and contains(@type,'text/html')]/@href", $this->elem)->item(0);
|
||||
|
||||
if($com_url)
|
||||
return $com_url->nodeValue;
|
||||
}
|
||||
|
||||
function get_comments_count() {
|
||||
$comments = $this->xpath->query("slash:comments", $this->elem)->item(0);
|
||||
//also query for ATE stuff here
|
||||
$query = "slash:comments|thread:total|atom:link[@rel='replies']/@thread:count";
|
||||
$comments = $this->xpath->query($query, $this->elem)->item(0);
|
||||
|
||||
if ($comments) {
|
||||
return $comments->nodeValue;
|
||||
|
||||
@@ -33,20 +33,20 @@ class FeedItem_RSS extends FeedItem_Common {
|
||||
|| $link->getAttribute("rel") == "alternate"
|
||||
|| $link->getAttribute("rel") == "standout")) {
|
||||
|
||||
return $link->getAttribute("href");
|
||||
return trim($link->getAttribute("href"));
|
||||
}
|
||||
}
|
||||
|
||||
$link = $this->elem->getElementsByTagName("guid")->item(0);
|
||||
|
||||
if ($link && $link->hasAttributes() && $link->getAttribute("isPermaLink") == "true") {
|
||||
return $link->nodeValue;
|
||||
return trim($link->nodeValue);
|
||||
}
|
||||
|
||||
$link = $this->elem->getElementsByTagName("link")->item(0);
|
||||
|
||||
if ($link) {
|
||||
return $link->nodeValue;
|
||||
return trim($link->nodeValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,21 +54,26 @@ class FeedItem_RSS extends FeedItem_Common {
|
||||
$title = $this->elem->getElementsByTagName("title")->item(0);
|
||||
|
||||
if ($title) {
|
||||
return $title->nodeValue;
|
||||
return trim($title->nodeValue);
|
||||
}
|
||||
}
|
||||
|
||||
function get_content() {
|
||||
$content = $this->xpath->query("content:encoded", $this->elem)->item(0);
|
||||
$contentA = $this->xpath->query("content:encoded", $this->elem)->item(0);
|
||||
$contentB = $this->elem->getElementsByTagName("description")->item(0);
|
||||
|
||||
if ($content) {
|
||||
return $content->nodeValue;
|
||||
if ($contentA && !$contentB) {
|
||||
return $contentA->nodeValue;
|
||||
}
|
||||
|
||||
$content = $this->elem->getElementsByTagName("description")->item(0);
|
||||
|
||||
if ($content) {
|
||||
return $content->nodeValue;
|
||||
if ($contentB && !$contentA) {
|
||||
return $contentB->nodeValue;
|
||||
}
|
||||
|
||||
if ($contentA && $contentB) {
|
||||
return mb_strlen($contentA->nodeValue) > mb_strlen($contentB->nodeValue) ?
|
||||
$contentA->nodeValue : $contentB->nodeValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,13 +90,13 @@ class FeedItem_RSS extends FeedItem_Common {
|
||||
$cats = array();
|
||||
|
||||
foreach ($categories as $cat) {
|
||||
array_push($cats, $cat->nodeValue);
|
||||
array_push($cats, trim($cat->nodeValue));
|
||||
}
|
||||
|
||||
$categories = $this->xpath->query("dc:subject", $this->elem);
|
||||
|
||||
foreach ($categories as $cat) {
|
||||
array_push($cats, $cat->nodeValue);
|
||||
array_push($cats, trim($cat->nodeValue));
|
||||
}
|
||||
|
||||
return $cats;
|
||||
@@ -108,6 +113,8 @@ class FeedItem_RSS extends FeedItem_Common {
|
||||
$enc->type = $enclosure->getAttribute("type");
|
||||
$enc->link = $enclosure->getAttribute("url");
|
||||
$enc->length = $enclosure->getAttribute("length");
|
||||
$enc->height = $enclosure->getAttribute("height");
|
||||
$enc->width = $enclosure->getAttribute("width");
|
||||
|
||||
array_push($encs, $enc);
|
||||
}
|
||||
@@ -120,6 +127,51 @@ class FeedItem_RSS extends FeedItem_Common {
|
||||
$enc->type = $enclosure->getAttribute("type");
|
||||
$enc->link = $enclosure->getAttribute("url");
|
||||
$enc->length = $enclosure->getAttribute("length");
|
||||
$enc->height = $enclosure->getAttribute("height");
|
||||
$enc->width = $enclosure->getAttribute("width");
|
||||
|
||||
$desc = $this->xpath->query("media:description", $enclosure)->item(0);
|
||||
if ($desc) $enc->title = strip_tags($desc->nodeValue);
|
||||
|
||||
array_push($encs, $enc);
|
||||
}
|
||||
|
||||
|
||||
$enclosures = $this->xpath->query("media:group", $this->elem);
|
||||
|
||||
foreach ($enclosures as $enclosure) {
|
||||
$enc = new FeedEnclosure();
|
||||
|
||||
$content = $this->xpath->query("media:content", $enclosure)->item(0);
|
||||
|
||||
if ($content) {
|
||||
$enc->type = $content->getAttribute("type");
|
||||
$enc->link = $content->getAttribute("url");
|
||||
$enc->length = $content->getAttribute("length");
|
||||
$enc->height = $content->getAttribute("height");
|
||||
$enc->width = $content->getAttribute("width");
|
||||
|
||||
$desc = $this->xpath->query("media:description", $content)->item(0);
|
||||
if ($desc) {
|
||||
$enc->title = strip_tags($desc->nodeValue);
|
||||
} else {
|
||||
$desc = $this->xpath->query("media:description", $enclosure)->item(0);
|
||||
if ($desc) $enc->title = strip_tags($desc->nodeValue);
|
||||
}
|
||||
|
||||
array_push($encs, $enc);
|
||||
}
|
||||
}
|
||||
|
||||
$enclosures = $this->xpath->query("media:thumbnail", $this->elem);
|
||||
|
||||
foreach ($enclosures as $enclosure) {
|
||||
$enc = new FeedEnclosure();
|
||||
|
||||
$enc->type = "image/generic";
|
||||
$enc->link = $enclosure->getAttribute("url");
|
||||
$enc->height = $enclosure->getAttribute("height");
|
||||
$enc->width = $enclosure->getAttribute("width");
|
||||
|
||||
array_push($encs, $enc);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
class FeedParser {
|
||||
private $doc;
|
||||
private $error;
|
||||
private $libxml_errors = array();
|
||||
private $items;
|
||||
private $link;
|
||||
private $title;
|
||||
@@ -12,27 +13,75 @@ class FeedParser {
|
||||
const FEED_RSS = 1;
|
||||
const FEED_ATOM = 2;
|
||||
|
||||
function normalize_encoding($data) {
|
||||
if (preg_match('/^(<\?xml[\t\n\r ].*?encoding[\t\n\r ]*=[\t\n\r ]*["\'])(.+?)(["\'].*?\?>)/s', $data, $matches) === 1) {
|
||||
$data = mb_convert_encoding($data, 'UTF-8', $matches[2]);
|
||||
|
||||
$data = preg_replace('/^<\?xml[\t\n\r ].*?\?>/s', $matches[1] . "UTF-8" . $matches[3] , $data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
function __construct($data) {
|
||||
libxml_use_internal_errors(true);
|
||||
libxml_clear_errors();
|
||||
$this->doc = new DOMDocument();
|
||||
$this->doc->loadXML($data);
|
||||
|
||||
mb_substitute_character("none");
|
||||
|
||||
$error = libxml_get_last_error();
|
||||
|
||||
if ($error && $error->code == 9) {
|
||||
libxml_clear_errors();
|
||||
// libxml compiled without iconv?
|
||||
if ($error && $error->code == 32) {
|
||||
$data = $this->normalize_encoding($data);
|
||||
|
||||
// we might want to try guessing input encoding here too
|
||||
$data = iconv("UTF-8", "UTF-8//IGNORE", $data);
|
||||
if ($data) {
|
||||
libxml_clear_errors();
|
||||
|
||||
$this->doc = new DOMDocument();
|
||||
$this->doc->loadXML($data);
|
||||
$this->doc = new DOMDocument();
|
||||
$this->doc->loadXML($data);
|
||||
|
||||
$error = libxml_get_last_error();
|
||||
$error = libxml_get_last_error();
|
||||
}
|
||||
}
|
||||
|
||||
$this->error = $this->format_error($error);
|
||||
// some terrible invalid unicode entity?
|
||||
if ($error) {
|
||||
foreach (libxml_get_errors() as $err) {
|
||||
if ($err->code == 9) {
|
||||
// if the source feed is not in utf8, next conversion will fail
|
||||
$data = $this->normalize_encoding($data);
|
||||
|
||||
// remove dangling bytes
|
||||
$data = mb_convert_encoding($data, 'UTF-8', 'UTF-8');
|
||||
|
||||
// apparently not all UTF-8 characters are valid for XML
|
||||
$data = preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $data);
|
||||
|
||||
if ($data) {
|
||||
libxml_clear_errors();
|
||||
|
||||
$this->doc = new DOMDocument();
|
||||
$this->doc->loadXML($data);
|
||||
|
||||
$error = libxml_get_last_error();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
foreach (libxml_get_errors() as $error) {
|
||||
if ($error->level == LIBXML_ERR_FATAL) {
|
||||
if(!isset($this->error)) //currently only the first error is reported
|
||||
$this->error = $this->format_error($error);
|
||||
$this->libxml_errors [] = $this->format_error($error);
|
||||
}
|
||||
}
|
||||
}
|
||||
libxml_clear_errors();
|
||||
|
||||
$this->items = array();
|
||||
@@ -48,27 +97,32 @@ class FeedParser {
|
||||
$xpath->registerNamespace('slash', 'http://purl.org/rss/1.0/modules/slash/');
|
||||
$xpath->registerNamespace('dc', 'http://purl.org/dc/elements/1.1/');
|
||||
$xpath->registerNamespace('content', 'http://purl.org/rss/1.0/modules/content/');
|
||||
$xpath->registerNamespace('thread', 'http://purl.org/syndication/thread/1.0');
|
||||
|
||||
$this->xpath = $xpath;
|
||||
|
||||
$root = $xpath->query("(//atom03:feed|//atom:feed|//channel|//rdf:rdf|//rdf:RDF)")->item(0);
|
||||
$root = $xpath->query("(//atom03:feed|//atom:feed|//channel|//rdf:rdf|//rdf:RDF)");
|
||||
|
||||
if ($root) {
|
||||
switch (mb_strtolower($root->tagName)) {
|
||||
case "rdf:rdf":
|
||||
$this->type = $this::FEED_RDF;
|
||||
break;
|
||||
case "channel":
|
||||
$this->type = $this::FEED_RSS;
|
||||
break;
|
||||
case "feed":
|
||||
$this->type = $this::FEED_ATOM;
|
||||
break;
|
||||
default:
|
||||
if( !isset($this->error) ){
|
||||
$this->error = "Unknown/unsupported feed type";
|
||||
if ($root && $root->length > 0) {
|
||||
$root = $root->item(0);
|
||||
|
||||
if ($root) {
|
||||
switch (mb_strtolower($root->tagName)) {
|
||||
case "rdf:rdf":
|
||||
$this->type = $this::FEED_RDF;
|
||||
break;
|
||||
case "channel":
|
||||
$this->type = $this::FEED_RSS;
|
||||
break;
|
||||
case "feed":
|
||||
$this->type = $this::FEED_ATOM;
|
||||
break;
|
||||
default:
|
||||
if( !isset($this->error) ){
|
||||
$this->error = "Unknown/unsupported feed type";
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch ($this->type) {
|
||||
@@ -151,6 +205,10 @@ class FeedParser {
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if ($this->title) $this->title = trim($this->title);
|
||||
if ($this->link) $this->link = trim($this->link);
|
||||
|
||||
} else {
|
||||
if( !isset($this->error) ){
|
||||
$this->error = "Unknown/unsupported feed type";
|
||||
@@ -173,6 +231,10 @@ class FeedParser {
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
function errors() {
|
||||
return $this->libxml_errors;
|
||||
}
|
||||
|
||||
function get_link() {
|
||||
return $this->link;
|
||||
}
|
||||
@@ -194,7 +256,7 @@ class FeedParser {
|
||||
|
||||
foreach ($links as $link) {
|
||||
if (!$rel || $link->hasAttribute('rel') && $link->getAttribute('rel') == $rel) {
|
||||
array_push($rv, $link->getAttribute('href'));
|
||||
array_push($rv, trim($link->getAttribute('href')));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -203,7 +265,7 @@ class FeedParser {
|
||||
|
||||
foreach ($links as $link) {
|
||||
if (!$rel || $link->hasAttribute('rel') && $link->getAttribute('rel') == $rel) {
|
||||
array_push($rv, $link->getAttribute('href'));
|
||||
array_push($rv, trim($link->getAttribute('href')));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -13,12 +13,6 @@ class Feeds extends Handler_Protected {
|
||||
$feed_id, $is_cat, $search,
|
||||
$search_mode, $view_mode, $error, $feed_last_updated) {
|
||||
|
||||
$page_prev_link = "viewFeedGoPage(-1)";
|
||||
$page_next_link = "viewFeedGoPage(1)";
|
||||
$page_first_link = "viewFeedGoPage(0)";
|
||||
|
||||
$catchup_page_link = "catchupPage()";
|
||||
$catchup_feed_link = "catchupCurrentFeed()";
|
||||
$catchup_sel_link = "catchupSelection()";
|
||||
|
||||
$archive_sel_link = "archiveSelection()";
|
||||
@@ -43,14 +37,24 @@ class Feeds extends Handler_Protected {
|
||||
$search_q = "";
|
||||
}
|
||||
|
||||
$reply .= "<span class=\"holder\">";
|
||||
|
||||
$rss_link = htmlspecialchars(get_self_url_prefix() .
|
||||
"/public.php?op=rss&id=$feed_id$cat_q$search_q");
|
||||
|
||||
// right part
|
||||
|
||||
$reply .= "<span class='r'>";
|
||||
$reply .= "<span id='selected_prompt'></span>";
|
||||
$reply .= "<span id='feed_title'>";
|
||||
$error_class = $error ? "error" : "";
|
||||
|
||||
$reply .= "<span class='r'>
|
||||
<a href=\"#\"
|
||||
title=\"".__("View as RSS feed")."\"
|
||||
onclick=\"displayDlg('".__("View as RSS")."','generatedFeed', '$feed_id:$is_cat:$rss_link')\">
|
||||
<img class=\"noborder\" src=\"images/pub_set.png\"></a>";
|
||||
|
||||
|
||||
# $reply .= "<span>";
|
||||
$reply .= "<span id='feed_title' class='$error_class'>";
|
||||
|
||||
if ($feed_site_url) {
|
||||
$last_updated = T_sprintf("Last updated: %s",
|
||||
@@ -58,10 +62,11 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
$target = "target=\"_blank\"";
|
||||
$reply .= "<a title=\"$last_updated\" $target href=\"$feed_site_url\">".
|
||||
truncate_string($feed_title,30)."</a>";
|
||||
truncate_string($feed_title, 30)."</a>";
|
||||
|
||||
if ($error) {
|
||||
$reply .= " (<span class=\"error\" title=\"$error\">Error</span>)";
|
||||
$error = htmlspecialchars($error);
|
||||
$reply .= " <img title=\"$error\" src='images/error.png' alt='error' class=\"noborder\">";
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -70,17 +75,16 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
$reply .= "</span>";
|
||||
|
||||
$reply .= "
|
||||
<a href=\"#\"
|
||||
title=\"".__("View as RSS feed")."\"
|
||||
onclick=\"displayDlg('".__("View as RSS")."','generatedFeed', '$feed_id:$is_cat:$rss_link')\">
|
||||
<img class=\"noborder\" style=\"vertical-align : middle\" src=\"images/pub_set.svg\"></a>";
|
||||
|
||||
$reply .= "</span>";
|
||||
|
||||
# $reply .= "</span>";
|
||||
|
||||
// left part
|
||||
|
||||
$reply .= __('Select:')."
|
||||
$reply .= "<span class=\"main\">";
|
||||
$reply .= "<span id='selected_prompt'></span>";
|
||||
|
||||
$reply .= "
|
||||
<a href=\"#\" onclick=\"$sel_all_link\">".__('All')."</a>,
|
||||
<a href=\"#\" onclick=\"$sel_unread_link\">".__('Unread')."</a>,
|
||||
<a href=\"#\" onclick=\"$sel_inv_link\">".__('Invert')."</a>,
|
||||
@@ -129,14 +133,14 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
$reply .= "</select>";
|
||||
|
||||
//$reply .= "</div>";
|
||||
|
||||
//$reply .= "</h2";
|
||||
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HEADLINE_TOOLBAR_BUTTON) as $p) {
|
||||
echo $p->hook_headline_toolbar_button($feed_id, $is_cat);
|
||||
$reply .= $p->hook_headline_toolbar_button($feed_id, $is_cat);
|
||||
}
|
||||
|
||||
$reply .= "</span></span>";
|
||||
|
||||
return $reply;
|
||||
}
|
||||
|
||||
@@ -145,7 +149,7 @@ class Feeds extends Handler_Protected {
|
||||
$override_order = false, $include_children = false) {
|
||||
|
||||
if (isset($_REQUEST["DevForceUpdate"]))
|
||||
header("Content-Type: text/plain");
|
||||
header("Content-Type: text/plain; charset=utf-8");
|
||||
|
||||
$disable_cache = false;
|
||||
|
||||
@@ -244,6 +248,8 @@ class Feeds extends Handler_Protected {
|
||||
false, 0, $include_children);
|
||||
}
|
||||
|
||||
$vfeed_group_enabled = get_pref("VFEED_GROUP_BY_FEED") && $feed != -6;
|
||||
|
||||
if ($_REQUEST["debug"]) $timing_info = print_checkpoint("H1", $timing_info);
|
||||
|
||||
$result = $qfh_ret[0];
|
||||
@@ -252,6 +258,7 @@ class Feeds extends Handler_Protected {
|
||||
$last_error = $qfh_ret[3];
|
||||
$last_updated = strpos($qfh_ret[4], '1970-') === FALSE ?
|
||||
make_local_datetime($qfh_ret[4], false) : __("Never");
|
||||
$highlight_words = $qfh_ret[5];
|
||||
|
||||
$vgroup_last_feed = $vgr_last_feed;
|
||||
|
||||
@@ -274,6 +281,12 @@ class Feeds extends Handler_Protected {
|
||||
}
|
||||
} */
|
||||
|
||||
if ($offset == 0) {
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HEADLINES_BEFORE) as $p) {
|
||||
$reply['content'] .= $p->hook_headlines_before($feed, $cat_view, $qfh_ret);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->dbh->num_rows($result) > 0) {
|
||||
|
||||
$lnum = $offset;
|
||||
@@ -281,13 +294,21 @@ class Feeds extends Handler_Protected {
|
||||
$num_unread = 0;
|
||||
$cur_feed_title = '';
|
||||
|
||||
$fresh_intl = get_pref("FRESH_ARTICLE_MAX_AGE") * 60 * 60;
|
||||
|
||||
if ($_REQUEST["debug"]) $timing_info = print_checkpoint("PS", $timing_info);
|
||||
|
||||
$expand_cdm = get_pref('CDM_EXPANDED');
|
||||
|
||||
while ($line = $this->dbh->fetch_assoc($result)) {
|
||||
$line["content_preview"] = "— " . truncate_string(strip_tags($line["content"]), 250);
|
||||
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
|
||||
$line = $p->hook_query_headlines($line, 250, false);
|
||||
}
|
||||
|
||||
if (get_pref('SHOW_CONTENT_PREVIEW')) {
|
||||
$content_preview = $line["content_preview"];
|
||||
}
|
||||
|
||||
$id = $line["id"];
|
||||
$feed_id = $line["feed_id"];
|
||||
$label_cache = $line["label_cache"];
|
||||
@@ -306,7 +327,7 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
if (!is_array($labels)) $labels = get_article_labels($id);
|
||||
|
||||
$labels_str = "<span id=\"HLLCTR-$id\">";
|
||||
$labels_str = "<span class=\"HLLCTR-$id\">";
|
||||
$labels_str .= format_article_labels($labels, $id);
|
||||
$labels_str .= "</span>";
|
||||
|
||||
@@ -323,24 +344,24 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
if (sql_bool_to_bool($line["marked"])) {
|
||||
$marked_pic = "<img
|
||||
src=\"images/mark_set.svg\"
|
||||
src=\"images/mark_set.png\"
|
||||
class=\"markedPic\" alt=\"Unstar article\"
|
||||
onclick='toggleMark($id)'>";
|
||||
$class .= " marked";
|
||||
} else {
|
||||
$marked_pic = "<img
|
||||
src=\"images/mark_unset.svg\"
|
||||
src=\"images/mark_unset.png\"
|
||||
class=\"markedPic\" alt=\"Star article\"
|
||||
onclick='toggleMark($id)'>";
|
||||
}
|
||||
|
||||
if (sql_bool_to_bool($line["published"])) {
|
||||
$published_pic = "<img src=\"images/pub_set.svg\"
|
||||
$published_pic = "<img src=\"images/pub_set.png\"
|
||||
class=\"pubPic\"
|
||||
alt=\"Unpublish article\" onclick='togglePub($id)'>";
|
||||
$class .= " published";
|
||||
} else {
|
||||
$published_pic = "<img src=\"images/pub_unset.svg\"
|
||||
$published_pic = "<img src=\"images/pub_unset.png\"
|
||||
class=\"pubPic\"
|
||||
alt=\"Publish article\" onclick='togglePub($id)'>";
|
||||
}
|
||||
@@ -360,11 +381,6 @@ class Feeds extends Handler_Protected {
|
||||
$date_entered_fmt = T_sprintf("Imported at %s",
|
||||
make_local_datetime($line["date_entered"], false));
|
||||
|
||||
if (get_pref('SHOW_CONTENT_PREVIEW')) {
|
||||
$content_preview = truncate_string(strip_tags($line["content_preview"]),
|
||||
250);
|
||||
}
|
||||
|
||||
$score = $line["score"];
|
||||
|
||||
$score_pic = "images/" . get_score_pic($score);
|
||||
@@ -377,9 +393,9 @@ class Feeds extends Handler_Protected {
|
||||
title=\"$score\">";
|
||||
|
||||
if ($score > 500) {
|
||||
$hlc_suffix = "H";
|
||||
$hlc_suffix = "high";
|
||||
} else if ($score < -100) {
|
||||
$hlc_suffix = "L";
|
||||
$hlc_suffix = "low";
|
||||
} else {
|
||||
$hlc_suffix = "";
|
||||
}
|
||||
@@ -395,7 +411,7 @@ class Feeds extends Handler_Protected {
|
||||
if ($has_feed_icon) {
|
||||
$feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"".ICONS_URL."/$feed_id.ico\" alt=\"\">";
|
||||
} else {
|
||||
$feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"images/pub_set.svg\" alt=\"\">";
|
||||
$feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"images/pub_set.png\" alt=\"\">";
|
||||
}
|
||||
|
||||
$entry_site_url = $line["site_url"];
|
||||
@@ -413,7 +429,7 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
if (!get_pref('COMBINED_DISPLAY_MODE')) {
|
||||
|
||||
if (get_pref('VFEED_GROUP_BY_FEED')) {
|
||||
if ($vfeed_group_enabled) {
|
||||
if ($feed_id != $vgroup_last_feed && $line["feed_title"]) {
|
||||
|
||||
$cur_feed_title = $line["feed_title"];
|
||||
@@ -421,12 +437,12 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
$cur_feed_title = htmlspecialchars($cur_feed_title);
|
||||
|
||||
$vf_catchup_link = "(<a class='catchup' onclick='catchupFeedInGroup($feed_id);' href='#'>".__('Mark as read')."</a>)";
|
||||
$vf_catchup_link = "<a class='catchup' onclick='catchupFeedInGroup($feed_id);' href='#'>".__('mark feed as read')."</a>";
|
||||
|
||||
$reply['content'] .= "<div class='cdmFeedTitle'>".
|
||||
"<div style=\"float : right\">$feed_icon_img</div>".
|
||||
"<a class='title' href=\"#\" onclick=\"viewfeed($feed_id)\">".
|
||||
$line["feed_title"]."</a> $vf_catchup_link</div>";
|
||||
$reply['content'] .= "<div id='FTITLE-$feed_id' class='cdmFeedTitle'>".
|
||||
"<div style='float : right'>$feed_icon_img</div>".
|
||||
"<a class='title' href=\"#\" onclick=\"viewfeed($feed_id)\">". $line["feed_title"]."</a>
|
||||
$vf_catchup_link</div>";
|
||||
|
||||
}
|
||||
}
|
||||
@@ -434,7 +450,7 @@ class Feeds extends Handler_Protected {
|
||||
$mouseover_attrs = "onmouseover='postMouseIn(event, $id)'
|
||||
onmouseout='postMouseOut($id)'";
|
||||
|
||||
$reply['content'] .= "<div class='hl $class' id='RROW-$id' $mouseover_attrs>";
|
||||
$reply['content'] .= "<div class='hl $class' orig-feed-id='$feed_id' id='RROW-$id' $mouseover_attrs>";
|
||||
|
||||
$reply['content'] .= "<div class='hlLeft'>";
|
||||
|
||||
@@ -448,16 +464,14 @@ class Feeds extends Handler_Protected {
|
||||
$reply['content'] .= "</div>";
|
||||
|
||||
$reply['content'] .= "<div onclick='return hlClicked(event, $id)'
|
||||
class=\"hlTitle\"><span class='hlContent$hlc_suffix'>";
|
||||
$reply['content'] .= "<a id=\"RTITLE-$id\" class=\"title\"
|
||||
class=\"hlTitle\"><span class='hlContent $hlc_suffix'>";
|
||||
$reply['content'] .= "<a id=\"RTITLE-$id\" class=\"title $hlc_suffix\"
|
||||
href=\"" . htmlspecialchars($line["link"]) . "\"
|
||||
onclick=\"\">" .
|
||||
truncate_string($line["title"], 200);
|
||||
|
||||
if (get_pref('SHOW_CONTENT_PREVIEW')) {
|
||||
if ($content_preview) {
|
||||
$reply['content'] .= "<span class=\"contentPreview\"> - $content_preview</span>";
|
||||
}
|
||||
$reply['content'] .= "<span class=\"contentPreview\">" . $line["content_preview"] . "</span>";
|
||||
}
|
||||
|
||||
$reply['content'] .= "</a></span>";
|
||||
@@ -466,17 +480,18 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
$reply['content'] .= "</div>";
|
||||
|
||||
$reply['content'] .= "<span class=\"hlUpdated\">";
|
||||
|
||||
if (!get_pref('VFEED_GROUP_BY_FEED')) {
|
||||
if (!$vfeed_group_enabled) {
|
||||
if (@$line["feed_title"]) {
|
||||
$rgba = @$rgba_cache[$feed_id];
|
||||
|
||||
$reply['content'] .= "<a class=\"hlFeed\" style=\"background : rgba($rgba, 0.3)\" href=\"#\" onclick=\"viewfeed($feed_id)\">".
|
||||
truncate_string($line["feed_title"],30)."</a>";
|
||||
$reply['content'] .= "<span class=\"hlFeed\"><a style=\"background : rgba($rgba, 0.3)\" href=\"#\" onclick=\"viewfeed($feed_id)\">".
|
||||
truncate_string($line["feed_title"],30)."</a></span>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$reply['content'] .= "<span class=\"hlUpdated\">";
|
||||
|
||||
$reply['content'] .= "<div title='$date_entered_fmt'>$updated_fmt</div>
|
||||
</span>";
|
||||
|
||||
@@ -484,12 +499,12 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
$reply['content'] .= $score_pic;
|
||||
|
||||
if ($line["feed_title"] && !get_pref('VFEED_GROUP_BY_FEED')) {
|
||||
if ($line["feed_title"] && !$vfeed_group_enabled) {
|
||||
|
||||
$reply['content'] .= "<span onclick=\"viewfeed($feed_id)\"
|
||||
style=\"cursor : pointer\"
|
||||
title=\"".htmlspecialchars($line['feed_title'])."\">
|
||||
$feed_icon_img<span>";
|
||||
$feed_icon_img</span>";
|
||||
}
|
||||
|
||||
$reply['content'] .= "</div>";
|
||||
@@ -502,14 +517,14 @@ class Feeds extends Handler_Protected {
|
||||
else
|
||||
$tags = false;
|
||||
|
||||
$line["content"] = sanitize($line["content_preview"],
|
||||
sql_bool_to_bool($line['hide_images']), false, $entry_site_url);
|
||||
$line["content"] = sanitize($line["content"],
|
||||
sql_bool_to_bool($line['hide_images']), false, $entry_site_url, $highlight_words, $line["id"]);
|
||||
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE_CDM) as $p) {
|
||||
$line = $p->hook_render_article_cdm($line);
|
||||
}
|
||||
|
||||
if (get_pref('VFEED_GROUP_BY_FEED') && $line["feed_title"]) {
|
||||
if ($vfeed_group_enabled && $line["feed_title"]) {
|
||||
if ($feed_id != $vgroup_last_feed) {
|
||||
|
||||
$cur_feed_title = $line["feed_title"];
|
||||
@@ -517,7 +532,7 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
$cur_feed_title = htmlspecialchars($cur_feed_title);
|
||||
|
||||
$vf_catchup_link = "(<a class='catchup' onclick='javascript:catchupFeedInGroup($feed_id);' href='#'>".__('mark as read')."</a>)";
|
||||
$vf_catchup_link = "<a class='catchup' onclick='catchupFeedInGroup($feed_id);' href='#'>".__('mark feed as read')."</a>";
|
||||
|
||||
$has_feed_icon = feed_has_icon($feed_id);
|
||||
|
||||
@@ -527,7 +542,7 @@ class Feeds extends Handler_Protected {
|
||||
//$feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"images/blank_icon.gif\" alt=\"\">";
|
||||
}
|
||||
|
||||
$reply['content'] .= "<div class='cdmFeedTitle'>".
|
||||
$reply['content'] .= "<div id='FTITLE-$feed_id' class='cdmFeedTitle'>".
|
||||
"<div style=\"float : right\">$feed_icon_img</div>".
|
||||
"<a href=\"#\" class='title' onclick=\"viewfeed($feed_id)\">".
|
||||
$line["feed_title"]."</a> $vf_catchup_link</div>";
|
||||
@@ -539,10 +554,10 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
$expanded_class = $expand_cdm ? "expanded" : "expandable";
|
||||
|
||||
$reply['content'] .= "<div class=\"cdm $expanded_class $class\"
|
||||
id=\"RROW-$id\" $mouseover_attrs>";
|
||||
$reply['content'] .= "<div class=\"cdm $hlc_suffix $expanded_class $class\"
|
||||
id=\"RROW-$id\" orig-feed-id='$feed_id' $mouseover_attrs>";
|
||||
|
||||
$reply['content'] .= "<div class=\"cdmHeader\" style=\"$row_background\">";
|
||||
$reply['content'] .= "<div class=\"cdmHeader\">";
|
||||
$reply['content'] .= "<div style=\"vertical-align : middle\">";
|
||||
|
||||
$reply['content'] .= "<input dojoType=\"dijit.form.CheckBox\"
|
||||
@@ -554,10 +569,17 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
$reply['content'] .= "</div>";
|
||||
|
||||
if ($highlight_words && count($highlight_words > 0)) {
|
||||
foreach ($highlight_words as $word) {
|
||||
$line["title"] = preg_replace("/(\Q$word\E)/i",
|
||||
"<span class=\"highlight\">$1</span>", $line["title"]);
|
||||
}
|
||||
}
|
||||
|
||||
$reply['content'] .= "<span id=\"RTITLE-$id\"
|
||||
onclick=\"return cdmClicked(event, $id);\"
|
||||
class=\"titleWrap$hlc_suffix\">
|
||||
<a class=\"title\"
|
||||
class=\"titleWrap $hlc_suffix\">
|
||||
<a class=\"title $hlc_suffix\"
|
||||
target=\"_blank\" href=\"".
|
||||
htmlspecialchars($line["link"])."\">".
|
||||
$line["title"] .
|
||||
@@ -574,11 +596,11 @@ class Feeds extends Handler_Protected {
|
||||
else
|
||||
$excerpt_hidden = "style=\"display : none\"";
|
||||
|
||||
$reply['content'] .= "<span $excerpt_hidden
|
||||
id=\"CEXC-$id\" class=\"cdmExcerpt\"> - $content_preview</span>";
|
||||
$reply['content'] .= "<span $excerpt_hidden id=\"CEXC-$id\" class=\"cdmExcerpt\">" . $content_preview . "</span>";
|
||||
|
||||
$reply['content'] .= "</span>";
|
||||
|
||||
if (!get_pref('VFEED_GROUP_BY_FEED')) {
|
||||
if (!$vfeed_group_enabled) {
|
||||
if (@$line["feed_title"]) {
|
||||
$rgba = @$rgba_cache[$feed_id];
|
||||
|
||||
@@ -615,7 +637,9 @@ class Feeds extends Handler_Protected {
|
||||
}
|
||||
$reply['content'] .= "</div>";
|
||||
|
||||
$reply['content'] .= "<div class=\"cdmContentInner\">";
|
||||
if (!$line['lang']) $line['lang'] = 'en';
|
||||
|
||||
$reply['content'] .= "<div class=\"cdmContentInner\" lang=\"".$line['lang']."\">";
|
||||
|
||||
if ($line["orig_feed_id"]) {
|
||||
|
||||
@@ -638,7 +662,7 @@ class Feeds extends Handler_Protected {
|
||||
$reply['content'] .= " ";
|
||||
|
||||
$reply['content'] .= "<a target='_blank' href='" . htmlspecialchars($tmp_line['feed_url']) . "'>";
|
||||
$reply['content'] .= "<img title='".__('Feed URL')."'class='tinyFeedIcon' src='images/pub_unset.svg'></a>";
|
||||
$reply['content'] .= "<img title='".__('Feed URL')."'class='tinyFeedIcon' src='images/pub_unset.png'></a>";
|
||||
|
||||
$reply['content'] .= "</div>";
|
||||
}
|
||||
@@ -685,10 +709,13 @@ class Feeds extends Handler_Protected {
|
||||
} else {
|
||||
$comments_url = htmlspecialchars($line["link"]);
|
||||
}
|
||||
$entry_comments = "<a target='_blank' href=\"$comments_url\">$num_comments comments</a>";
|
||||
$entry_comments = "<a class=\"postComments\"
|
||||
target='_blank' href=\"$comments_url\">$num_comments ".
|
||||
_ngettext("comment", "comments", $num_comments)."</a>";
|
||||
|
||||
} else {
|
||||
if ($line["comments"] && $line["link"] != $line["comments"]) {
|
||||
$entry_comments = "<a target='_blank' href=\"".htmlspecialchars($line["comments"])."\">comments</a>";
|
||||
$entry_comments = "<a class=\"postComments\" target='_blank' href=\"".htmlspecialchars($line["comments"])."\">".__("comments")."</a>";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -706,7 +733,7 @@ class Feeds extends Handler_Protected {
|
||||
$reply['content'] .= "</div>";
|
||||
$reply['content'] .= "</div>";
|
||||
|
||||
$reply['content'] .= "</div><hr/>";
|
||||
$reply['content'] .= "</div>";
|
||||
|
||||
$reply['content'] .= "</div>";
|
||||
|
||||
@@ -784,8 +811,6 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
if ($_REQUEST["debug"]) $timing_info = print_checkpoint("0", $timing_info);
|
||||
|
||||
$omode = $this->dbh->escape_string($_REQUEST["omode"]);
|
||||
|
||||
$feed = $this->dbh->escape_string($_REQUEST["feed"]);
|
||||
$method = $this->dbh->escape_string($_REQUEST["m"]);
|
||||
$view_mode = $this->dbh->escape_string($_REQUEST["view_mode"]);
|
||||
@@ -863,7 +888,7 @@ class Feeds extends Handler_Protected {
|
||||
$override_order = "ttrss_entries.title";
|
||||
break;
|
||||
case "date_reverse":
|
||||
$override_order = "date_entered, updated";
|
||||
$override_order = "score DESC, date_entered, updated";
|
||||
break;
|
||||
case "feed_dates":
|
||||
$override_order = "updated DESC";
|
||||
@@ -878,7 +903,7 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
//$topmost_article_ids = $ret[0];
|
||||
$headlines_count = $ret[1];
|
||||
$returned_feed = $ret[2];
|
||||
/* $returned_feed = $ret[2]; */
|
||||
$disable_cache = $ret[3];
|
||||
$vgroup_last_feed = $ret[4];
|
||||
|
||||
@@ -959,6 +984,10 @@ class Feeds extends Handler_Protected {
|
||||
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"op\" value=\"rpc\">";
|
||||
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"method\" value=\"addfeed\">";
|
||||
|
||||
print "<div id='fadd_multiple_notify' style='display : none'>";
|
||||
print_notice("Provided URL is a HTML page referencing multiple feeds, please select required feed from the dropdown menu below.");
|
||||
print "<p></div>";
|
||||
|
||||
print "<div class=\"dlgSec\">".__("Feed or site URL")."</div>";
|
||||
print "<div class=\"dlgSecCont\">";
|
||||
|
||||
@@ -1054,20 +1083,18 @@ class Feeds extends Handler_Protected {
|
||||
print " <select dojoType=\"dijit.form.Select\" name=\"limit\" onchange=\"dijit.byId('feedBrowserDlg').update()\">";
|
||||
|
||||
foreach (array(25, 50, 100, 200) as $l) {
|
||||
$issel = ($l == $limit) ? "selected=\"1\"" : "";
|
||||
print "<option $issel value=\"$l\">$l</option>";
|
||||
//$issel = ($l == $limit) ? "selected=\"1\"" : "";
|
||||
print "<option value=\"$l\">$l</option>";
|
||||
}
|
||||
|
||||
print "</select> ";
|
||||
|
||||
print "</div>";
|
||||
|
||||
$owner_uid = $_SESSION["uid"];
|
||||
|
||||
require_once "feedbrowser.php";
|
||||
|
||||
print "<ul class='browseFeedList' id='browseFeedList'>";
|
||||
print make_feed_browser($search, 25);
|
||||
print make_feed_browser("", 25);
|
||||
print "</ul>";
|
||||
|
||||
print "<div align='center'>
|
||||
@@ -1126,9 +1153,9 @@ class Feeds extends Handler_Protected {
|
||||
|
||||
print "<div class=\"dlgButtons\">";
|
||||
|
||||
if (!SPHINX_ENABLED) {
|
||||
if (count(PluginHost::getInstance()->get_hooks(PluginHost::HOOK_SEARCH)) == 0) {
|
||||
print "<div style=\"float : left\">
|
||||
<a class=\"visibleLink\" target=\"_blank\" href=\"http://tt-rss.org/wiki/SearchSyntax\">Search syntax</a>
|
||||
<a class=\"visibleLink\" target=\"_blank\" href=\"http://tt-rss.org/wiki/SearchSyntax\">".__("Search syntax")."</a>
|
||||
</div>";
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ class Handler_Public extends Handler {
|
||||
|
||||
private function generate_syndicated_feed($owner_uid, $feed, $is_cat,
|
||||
$limit, $offset, $search, $search_mode,
|
||||
$view_mode = false, $format = 'atom', $order = false) {
|
||||
$view_mode = false, $format = 'atom', $order = false, $orig_guid = false, $start_ts = false) {
|
||||
|
||||
require_once "lib/MiniTemplator.class.php";
|
||||
|
||||
@@ -15,11 +15,15 @@ class Handler_Public extends Handler {
|
||||
if (!$limit) $limit = 60;
|
||||
|
||||
$date_sort_field = "date_entered DESC, updated DESC";
|
||||
$date_check_field = "date_entered";
|
||||
|
||||
if ($feed == -2)
|
||||
if ($feed == -2 && !$is_cat) {
|
||||
$date_sort_field = "last_published DESC";
|
||||
else if ($feed == -1)
|
||||
$date_check_field = "last_published";
|
||||
} else if ($feed == -1 && !$is_cat) {
|
||||
$date_sort_field = "last_marked DESC";
|
||||
$date_check_field = "last_marked";
|
||||
}
|
||||
|
||||
switch ($order) {
|
||||
case "title":
|
||||
@@ -33,15 +37,18 @@ class Handler_Public extends Handler {
|
||||
break;
|
||||
}
|
||||
|
||||
//function queryFeedHeadlines($feed, $limit, $view_mode, $cat_view, $search, $search_mode, $override_order = false, $offset = 0, $owner_uid = 0, $filter = false, $since_id = 0, $include_children = false, $ignore_vfeed_group = false, $override_strategy = false, $override_vfeed = false, $start_ts = false) {
|
||||
|
||||
$qfh_ret = queryFeedHeadlines($feed,
|
||||
1, $view_mode, $is_cat, $search, $search_mode,
|
||||
$date_sort_field, $offset, $owner_uid,
|
||||
false, 0, false, true);
|
||||
false, 0, true, true, false, false, $start_ts);
|
||||
|
||||
$result = $qfh_ret[0];
|
||||
|
||||
if ($this->dbh->num_rows($result) != 0) {
|
||||
$ts = strtotime($this->dbh->fetch_result($result, 0, "date_entered"));
|
||||
|
||||
$ts = strtotime($this->dbh->fetch_result($result, 0, $date_check_field));
|
||||
|
||||
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
|
||||
strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $ts) {
|
||||
@@ -56,17 +63,17 @@ class Handler_Public extends Handler {
|
||||
$qfh_ret = queryFeedHeadlines($feed,
|
||||
$limit, $view_mode, $is_cat, $search, $search_mode,
|
||||
$date_sort_field, $offset, $owner_uid,
|
||||
false, 0, false, true);
|
||||
false, 0, true, true, false, false, $start_ts);
|
||||
|
||||
|
||||
$result = $qfh_ret[0];
|
||||
$feed_title = htmlspecialchars($qfh_ret[1]);
|
||||
$feed_site_url = $qfh_ret[2];
|
||||
$last_error = $qfh_ret[3];
|
||||
/* $last_error = $qfh_ret[3]; */
|
||||
|
||||
$feed_self_url = get_self_url_prefix() .
|
||||
"/public.php?op=rss&id=-2&key=" .
|
||||
get_feed_access_key(-2, false, $owner_uid);
|
||||
"/public.php?op=rss&id=$feed&key=" .
|
||||
get_feed_access_key($feed, false, $owner_uid);
|
||||
|
||||
if (!$feed_site_url) $feed_site_url = get_self_url_prefix();
|
||||
|
||||
@@ -85,16 +92,23 @@ class Handler_Public extends Handler {
|
||||
}
|
||||
|
||||
$tpl->setVariable('SELF_URL', htmlspecialchars(get_self_url_prefix()), true);
|
||||
|
||||
while ($line = $this->dbh->fetch_assoc($result)) {
|
||||
$line["content_preview"] = truncate_string(strip_tags($line["content"]), 100, '...');
|
||||
|
||||
$tpl->setVariable('ARTICLE_ID', htmlspecialchars($line['link']), true);
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
|
||||
$line = $p->hook_query_headlines($line);
|
||||
}
|
||||
|
||||
$tpl->setVariable('ARTICLE_ID',
|
||||
htmlspecialchars($orig_guid ? $line['link'] :
|
||||
get_self_url_prefix() .
|
||||
"/public.php?url=" . urlencode($line['link'])), true);
|
||||
$tpl->setVariable('ARTICLE_LINK', htmlspecialchars($line['link']), true);
|
||||
$tpl->setVariable('ARTICLE_TITLE', htmlspecialchars($line['title']), true);
|
||||
$tpl->setVariable('ARTICLE_EXCERPT',
|
||||
truncate_string(strip_tags($line["content_preview"]), 100, '...'), true);
|
||||
$tpl->setVariable('ARTICLE_EXCERPT', $line["content_preview"], true);
|
||||
|
||||
$content = sanitize($line["content_preview"], false, $owner_uid);
|
||||
$content = sanitize($line["content"], false, $owner_uid,
|
||||
$feed_site_url);
|
||||
|
||||
if ($line['note']) {
|
||||
$content = "<div style=\"$note_style\">Article note: " . $line['note'] . "</div>" .
|
||||
@@ -111,6 +125,9 @@ class Handler_Public extends Handler {
|
||||
|
||||
$tpl->setVariable('ARTICLE_AUTHOR', htmlspecialchars($line['author']), true);
|
||||
|
||||
$tpl->setVariable('ARTICLE_SOURCE_LINK', htmlspecialchars($line['site_url']), true);
|
||||
$tpl->setVariable('ARTICLE_SOURCE_TITLE', htmlspecialchars($line['feed_title'] ? $line['feed_title'] : $feed_title), true);
|
||||
|
||||
$tags = get_article_tags($line["id"], $owner_uid);
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
@@ -164,13 +181,17 @@ class Handler_Public extends Handler {
|
||||
$feed['articles'] = array();
|
||||
|
||||
while ($line = $this->dbh->fetch_assoc($result)) {
|
||||
$line["content_preview"] = truncate_string(strip_tags($line["content_preview"]), 100, '...');
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
|
||||
$line = $p->hook_query_headlines($line, 100);
|
||||
}
|
||||
$article = array();
|
||||
|
||||
$article['id'] = $line['link'];
|
||||
$article['link'] = $line['link'];
|
||||
$article['title'] = $line['title'];
|
||||
$article['excerpt'] = truncate_string(strip_tags($line["content_preview"]), 100, '...');
|
||||
$article['content'] = sanitize($line["content_preview"], false, $owner_uid);
|
||||
$article['excerpt'] = $line["content_preview"];
|
||||
$article['content'] = sanitize($line["content"], false, $owner_uid);
|
||||
$article['updated'] = date('c', strtotime($line["updated"]));
|
||||
|
||||
if ($line['note']) $article['note'] = $line['note'];
|
||||
@@ -256,16 +277,22 @@ class Handler_Public extends Handler {
|
||||
|
||||
function pubsub() {
|
||||
$mode = $this->dbh->escape_string($_REQUEST['hub_mode']);
|
||||
if (!$mode) $mode = $this->dbh->escape_string($_REQUEST['hub.mode']);
|
||||
|
||||
$feed_id = (int) $this->dbh->escape_string($_REQUEST['id']);
|
||||
$feed_url = $this->dbh->escape_string($_REQUEST['hub_topic']);
|
||||
|
||||
if (!$feed_url) $feed_url = $this->dbh->escape_string($_REQUEST['hub.topic']);
|
||||
|
||||
if (!PUBSUBHUBBUB_ENABLED) {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
echo "404 Not found";
|
||||
echo "404 Not found (Disabled by server)";
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: implement hub_verifytoken checking
|
||||
// TODO: store requested rel=self or whatever for verification
|
||||
// (may be different from stored feed url) e.g. http://url/ or http://url
|
||||
|
||||
$result = $this->dbh->query("SELECT feed_url FROM ttrss_feeds
|
||||
WHERE id = '$feed_id'");
|
||||
@@ -274,7 +301,8 @@ class Handler_Public extends Handler {
|
||||
|
||||
$check_feed_url = $this->dbh->fetch_result($result, 0, "feed_url");
|
||||
|
||||
if ($check_feed_url && ($check_feed_url == $feed_url || !$feed_url)) {
|
||||
// ignore url checking for the time being
|
||||
if ($check_feed_url && (true || $check_feed_url == $feed_url || !$feed_url)) {
|
||||
if ($mode == "subscribe") {
|
||||
|
||||
$this->dbh->query("UPDATE ttrss_feeds SET pubsub_state = 2
|
||||
@@ -303,11 +331,11 @@ class Handler_Public extends Handler {
|
||||
}
|
||||
} else {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
echo "404 Not found";
|
||||
echo "404 Not found (URL check failed)";
|
||||
}
|
||||
} else {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
echo "404 Not found";
|
||||
echo "404 Not found (Feed not found)";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -342,7 +370,7 @@ class Handler_Public extends Handler {
|
||||
function rss() {
|
||||
$feed = $this->dbh->escape_string($_REQUEST["id"]);
|
||||
$key = $this->dbh->escape_string($_REQUEST["key"]);
|
||||
$is_cat = $_REQUEST["is_cat"] != false;
|
||||
$is_cat = sql_bool_to_bool($_REQUEST["is_cat"]);
|
||||
$limit = (int)$this->dbh->escape_string($_REQUEST["limit"]);
|
||||
$offset = (int)$this->dbh->escape_string($_REQUEST["offset"]);
|
||||
|
||||
@@ -350,8 +378,10 @@ class Handler_Public extends Handler {
|
||||
$search_mode = $this->dbh->escape_string($_REQUEST["smode"]);
|
||||
$view_mode = $this->dbh->escape_string($_REQUEST["view-mode"]);
|
||||
$order = $this->dbh->escape_string($_REQUEST["order"]);
|
||||
$start_ts = $this->dbh->escape_string($_REQUEST["ts"]);
|
||||
|
||||
$format = $this->dbh->escape_string($_REQUEST['format']);
|
||||
$orig_guid = sql_bool_to_bool($_REQUEST["orig_guid"]);
|
||||
|
||||
if (!$format) $format = 'atom';
|
||||
|
||||
@@ -371,20 +401,24 @@ class Handler_Public extends Handler {
|
||||
|
||||
if ($owner_id) {
|
||||
$this->generate_syndicated_feed($owner_id, $feed, $is_cat, $limit,
|
||||
$offset, $search, $search_mode, $view_mode, $format, $order);
|
||||
$offset, $search, $search_mode, $view_mode, $format, $order, $orig_guid, $start_ts);
|
||||
} else {
|
||||
header('HTTP/1.1 403 Forbidden');
|
||||
}
|
||||
}
|
||||
|
||||
function updateTask() {
|
||||
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", false);
|
||||
}
|
||||
|
||||
function housekeepingTask() {
|
||||
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_HOUSE_KEEPING, "hook_house_keeping", false);
|
||||
}
|
||||
|
||||
function globalUpdateFeeds() {
|
||||
include "rssfuncs.php";
|
||||
// Update all feeds needing a update.
|
||||
update_daemon_common(0, true, false);
|
||||
housekeeping_common(false);
|
||||
|
||||
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", $op);
|
||||
RPC::updaterandomfeed_real($this->dbh);
|
||||
|
||||
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", false);
|
||||
}
|
||||
|
||||
function sharepopup() {
|
||||
@@ -393,11 +427,14 @@ class Handler_Public extends Handler {
|
||||
}
|
||||
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
print "<html><head><title>Tiny Tiny RSS</title>";
|
||||
print "<html><head><title>Tiny Tiny RSS</title>
|
||||
<link rel=\"shortcut icon\" type=\"image/png\" href=\"images/favicon.png\">
|
||||
<link rel=\"icon\" type=\"image/png\" sizes=\"72x72\" href=\"images/favicon-72px.png\">";
|
||||
|
||||
stylesheet_tag("css/utility.css");
|
||||
javascript_tag("lib/prototype.js");
|
||||
javascript_tag("lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls");
|
||||
echo stylesheet_tag("css/utility.css");
|
||||
echo stylesheet_tag("css/dijit.css");
|
||||
echo javascript_tag("lib/prototype.js");
|
||||
echo javascript_tag("lib/scriptaculous/scriptaculous.js?load=effects,controls");
|
||||
print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>
|
||||
</head><body id='sharepopup'>";
|
||||
|
||||
@@ -543,6 +580,7 @@ class Handler_Public extends Handler {
|
||||
}
|
||||
} else {
|
||||
$_SESSION["login_error_msg"] = __("Incorrect username or password");
|
||||
user_error("Failed login attempt for $login from {$_SERVER['REMOTE_ADDR']}", E_USER_WARNING);
|
||||
}
|
||||
|
||||
if ($_REQUEST['return']) {
|
||||
@@ -553,6 +591,18 @@ class Handler_Public extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
/* function subtest() {
|
||||
header("Content-type: text/plain; charset=utf-8");
|
||||
|
||||
$url = $_REQUEST["url"];
|
||||
|
||||
print "$url\n\n";
|
||||
|
||||
|
||||
print_r(get_feeds_from_html($url, fetch_file_contents($url)));
|
||||
|
||||
} */
|
||||
|
||||
function subscribe() {
|
||||
if (SINGLE_USER_MODE) {
|
||||
login_sequence();
|
||||
@@ -568,6 +618,9 @@ class Handler_Public extends Handler {
|
||||
<title>Tiny Tiny RSS</title>
|
||||
<link rel=\"stylesheet\" type=\"text/css\" href=\"css/utility.css\">
|
||||
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>
|
||||
<link rel=\"shortcut icon\" type=\"image/png\" href=\"images/favicon.png\">
|
||||
<link rel=\"icon\" type=\"image/png\" sizes=\"72x72\" href=\"images/favicon-72px.png\">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<img class=\"floatingLogo\" src=\"images/logo_small.png\"
|
||||
@@ -652,93 +705,6 @@ class Handler_Public extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe2() {
|
||||
$feed_url = $this->dbh->escape_string(trim($_REQUEST["feed_url"]));
|
||||
$cat_id = $this->dbh->escape_string($_REQUEST["cat_id"]);
|
||||
$from = $this->dbh->escape_string($_REQUEST["from"]);
|
||||
$feed_urls = array();
|
||||
|
||||
/* only read authentication information from POST */
|
||||
|
||||
$auth_login = $this->dbh->escape_string(trim($_POST["auth_login"]));
|
||||
$auth_pass = $this->dbh->escape_string(trim($_POST["auth_pass"]));
|
||||
|
||||
$rc = subscribe_to_feed($feed_url, $cat_id, $auth_login, $auth_pass);
|
||||
|
||||
switch ($rc) {
|
||||
case 1:
|
||||
print_notice(T_sprintf("Subscribed to <b>%s</b>.", $feed_url));
|
||||
break;
|
||||
case 2:
|
||||
print_error(T_sprintf("Could not subscribe to <b>%s</b>.", $feed_url));
|
||||
break;
|
||||
case 3:
|
||||
print_error(T_sprintf("No feeds found in <b>%s</b>.", $feed_url));
|
||||
break;
|
||||
case 0:
|
||||
print_warning(T_sprintf("Already subscribed to <b>%s</b>.", $feed_url));
|
||||
break;
|
||||
case 4:
|
||||
print_notice(__("Multiple feed URLs found."));
|
||||
$contents = @fetch_file_contents($url, false, $auth_login, $auth_pass);
|
||||
if (is_html($contents)) {
|
||||
$feed_urls = get_feeds_from_html($url, $contents);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
print_error(T_sprintf("Could not subscribe to <b>%s</b>.<br>Can't download the Feed URL.", $feed_url));
|
||||
break;
|
||||
}
|
||||
|
||||
if ($feed_urls) {
|
||||
print "<form action=\"backend.php\">";
|
||||
print "<input type=\"hidden\" name=\"op\" value=\"pref-feeds\">";
|
||||
print "<input type=\"hidden\" name=\"quiet\" value=\"1\">";
|
||||
print "<input type=\"hidden\" name=\"method\" value=\"add\">";
|
||||
|
||||
print "<select name=\"feed_url\">";
|
||||
|
||||
foreach ($feed_urls as $url => $name) {
|
||||
$url = htmlspecialchars($url);
|
||||
$name = htmlspecialchars($name);
|
||||
print "<option value=\"$url\">$name</option>";
|
||||
}
|
||||
|
||||
print "<input type=\"submit\" value=\"".__("Subscribe to selected feed")."\">";
|
||||
print "</form>";
|
||||
}
|
||||
|
||||
$tp_uri = get_self_url_prefix() . "/prefs.php";
|
||||
$tt_uri = get_self_url_prefix();
|
||||
|
||||
if ($rc <= 2){
|
||||
$result = $this->dbh->query("SELECT id FROM ttrss_feeds WHERE
|
||||
feed_url = '$feed_url' AND owner_uid = " . $_SESSION["uid"]);
|
||||
|
||||
$feed_id = $this->dbh->fetch_result($result, 0, "id");
|
||||
} else {
|
||||
$feed_id = 0;
|
||||
}
|
||||
|
||||
print "<p>";
|
||||
|
||||
if ($feed_id) {
|
||||
print "<form method=\"GET\" style='display: inline'
|
||||
action=\"$tp_uri\">
|
||||
<input type=\"hidden\" name=\"tab\" value=\"feedConfig\">
|
||||
<input type=\"hidden\" name=\"method\" value=\"editFeed\">
|
||||
<input type=\"hidden\" name=\"methodparam\" value=\"$feed_id\">
|
||||
<input type=\"submit\" value=\"".__("Edit subscription options")."\">
|
||||
</form>";
|
||||
}
|
||||
|
||||
print "<form style='display: inline' method=\"GET\" action=\"$tt_uri\">
|
||||
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
|
||||
</form></p>";
|
||||
|
||||
print "</body></html>";
|
||||
}
|
||||
|
||||
function index() {
|
||||
header("Content-Type: text/plain");
|
||||
print json_encode(array("error" => array("code" => 7)));
|
||||
@@ -747,11 +713,15 @@ class Handler_Public extends Handler {
|
||||
function forgotpass() {
|
||||
startup_gettext();
|
||||
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
print "<html><head><title>Tiny Tiny RSS</title>";
|
||||
@$hash = $_REQUEST["hash"];
|
||||
|
||||
stylesheet_tag("css/utility.css");
|
||||
javascript_tag("lib/prototype.js");
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
print "<html><head><title>Tiny Tiny RSS</title>
|
||||
<link rel=\"shortcut icon\" type=\"image/png\" href=\"images/favicon.png\">
|
||||
<link rel=\"icon\" type=\"image/png\" sizes=\"72x72\" href=\"images/favicon-72px.png\">";
|
||||
|
||||
echo stylesheet_tag("css/utility.css");
|
||||
echo javascript_tag("lib/prototype.js");
|
||||
|
||||
print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>
|
||||
</head><body id='forgotpass'>";
|
||||
@@ -762,8 +732,45 @@ class Handler_Public extends Handler {
|
||||
|
||||
@$method = $_POST['method'];
|
||||
|
||||
if (!$method) {
|
||||
print_notice(__("You will need to provide valid account name and email. New password will be sent on your email address."));
|
||||
if ($hash) {
|
||||
$login = $_REQUEST["login"];
|
||||
|
||||
if ($login) {
|
||||
$result = $this->dbh->query("SELECT id, resetpass_token FROM ttrss_users
|
||||
WHERE login = '$login'");
|
||||
|
||||
if ($this->dbh->num_rows($result) != 0) {
|
||||
$id = $this->dbh->fetch_result($result, 0, "id");
|
||||
$resetpass_token_full = $this->dbh->fetch_result($result, 0, "resetpass_token");
|
||||
list($timestamp, $resetpass_token) = explode(":", $resetpass_token_full);
|
||||
|
||||
if ($timestamp && $resetpass_token &&
|
||||
$timestamp >= time() - 15*60*60 &&
|
||||
$resetpass_token == $hash) {
|
||||
|
||||
$result = $this->dbh->query("UPDATE ttrss_users SET resetpass_token = NULL
|
||||
WHERE id = $id");
|
||||
|
||||
Pref_Users::resetUserPassword($id, true);
|
||||
|
||||
print "<p>"."Completed."."</p>";
|
||||
|
||||
} else {
|
||||
print_error("Some of the information provided is missing or incorrect.");
|
||||
}
|
||||
} else {
|
||||
print_error("Some of the information provided is missing or incorrect.");
|
||||
}
|
||||
} else {
|
||||
print_error("Some of the information provided is missing or incorrect.");
|
||||
}
|
||||
|
||||
print "<form method=\"GET\" action=\"index.php\">
|
||||
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
|
||||
</form>";
|
||||
|
||||
} else if (!$method) {
|
||||
print_notice(__("You will need to provide valid account name and email. A password reset link will be sent to your email address."));
|
||||
|
||||
print "<form method='POST' action='public.php'>";
|
||||
print "<input type='hidden' name='method' value='do'>";
|
||||
@@ -804,17 +811,57 @@ class Handler_Public extends Handler {
|
||||
|
||||
} else {
|
||||
|
||||
print_notice("Password reset instructions are being sent to your email address.");
|
||||
|
||||
$result = $this->dbh->query("SELECT id FROM ttrss_users
|
||||
WHERE login = '$login' AND email = '$email'");
|
||||
|
||||
if ($this->dbh->num_rows($result) != 0) {
|
||||
$id = $this->dbh->fetch_result($result, 0, "id");
|
||||
|
||||
Pref_Users::resetUserPassword($id, false);
|
||||
if ($id) {
|
||||
$resetpass_token = sha1(get_random_bytes(128));
|
||||
$resetpass_link = get_self_url_prefix() . "/public.php?op=forgotpass&hash=" . $resetpass_token .
|
||||
"&login=" . urlencode($login);
|
||||
|
||||
print "<p>";
|
||||
require_once 'classes/ttrssmailer.php';
|
||||
require_once "lib/MiniTemplator.class.php";
|
||||
|
||||
print "<p>"."Completed."."</p>";
|
||||
$tpl = new MiniTemplator;
|
||||
|
||||
$tpl->readTemplateFromFile("templates/resetpass_link_template.txt");
|
||||
|
||||
$tpl->setVariable('LOGIN', $login);
|
||||
$tpl->setVariable('RESETPASS_LINK', $resetpass_link);
|
||||
|
||||
$tpl->addBlock('message');
|
||||
|
||||
$message = "";
|
||||
|
||||
$tpl->generateOutputToString($message);
|
||||
|
||||
$mail = new ttrssMailer();
|
||||
|
||||
$rc = $mail->quickMail($email, $login,
|
||||
__("[tt-rss] Password reset request"),
|
||||
$message, false);
|
||||
|
||||
if (!$rc) print_error($mail->ErrorInfo);
|
||||
|
||||
$resetpass_token_full = $this->dbh->escape_string(time() . ":" . $resetpass_token);
|
||||
|
||||
$result = $this->dbh->query("UPDATE ttrss_users
|
||||
SET resetpass_token = '$resetpass_token_full'
|
||||
WHERE login = '$login' AND email = '$email'");
|
||||
|
||||
//Pref_Users::resetUserPassword($id, false);
|
||||
|
||||
print "<p>";
|
||||
|
||||
print "<p>"."Completed."."</p>";
|
||||
} else {
|
||||
print_error("User ID not found.");
|
||||
}
|
||||
|
||||
print "<form method=\"GET\" action=\"index.php\">
|
||||
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
|
||||
@@ -853,6 +900,8 @@ class Handler_Public extends Handler {
|
||||
<title>Database Updater</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<link rel="stylesheet" type="text/css" href="css/utility.css"/>
|
||||
<link rel=\"shortcut icon\" type=\"image/png\" href=\"images/favicon.png\">
|
||||
<link rel=\"icon\" type=\"image/png\" sizes=\"72x72\" href=\"images/favicon-72px.png\">
|
||||
</head>
|
||||
<style type="text/css">
|
||||
span.ok { color : #009000; font-weight : bold; }
|
||||
|
||||
@@ -97,7 +97,7 @@ class Opml extends Handler_Protected {
|
||||
$html_url_qpart = "";
|
||||
}
|
||||
|
||||
$out .= "<outline text=\"$title\" xmlUrl=\"$url\" $html_url_qpart/>\n";
|
||||
$out .= "<outline type=\"rss\" text=\"$title\" xmlUrl=\"$url\" $html_url_qpart/>\n";
|
||||
}
|
||||
|
||||
if ($cat_title) $out .= "</outline>\n";
|
||||
@@ -190,6 +190,7 @@ class Opml extends Handler_Protected {
|
||||
}
|
||||
|
||||
$tmp_line["cat_filter"] = sql_bool_to_bool($tmp_line["cat_filter"]);
|
||||
$tmp_line["inverse"] = sql_bool_to_bool($tmp_line["inverse"]);
|
||||
|
||||
unset($tmp_line["feed_id"]);
|
||||
unset($tmp_line["cat_id"]);
|
||||
@@ -256,8 +257,8 @@ class Opml extends Handler_Protected {
|
||||
$feed_title = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('text')->nodeValue, 0, 250));
|
||||
if (!$feed_title) $feed_title = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('title')->nodeValue, 0, 250));
|
||||
|
||||
$feed_url = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('xmlUrl')->nodeValue, 0, 250));
|
||||
if (!$feed_url) $feed_url = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('xmlURL')->nodeValue, 0, 250));
|
||||
$feed_url = $this->dbh->escape_string($attrs->getNamedItem('xmlUrl')->nodeValue);
|
||||
if (!$feed_url) $feed_url = $this->dbh->escape_string($attrs->getNamedItem('xmlURL')->nodeValue);
|
||||
|
||||
$site_url = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('htmlUrl')->nodeValue, 0, 250));
|
||||
|
||||
@@ -363,9 +364,10 @@ class Opml extends Handler_Protected {
|
||||
$cat_filter = bool_to_sql_bool($rule["cat_filter"]);
|
||||
$reg_exp = $this->dbh->escape_string($rule["reg_exp"]);
|
||||
$filter_type = (int)$rule["filter_type"];
|
||||
$inverse = bool_to_sql_bool($rule["inverse"]);
|
||||
|
||||
$this->dbh->query("INSERT INTO ttrss_filters2_rules (feed_id,cat_id,filter_id,filter_type,reg_exp,cat_filter)
|
||||
VALUES ($feed_id, $cat_id, $filter_id, $filter_type, '$reg_exp', $cat_filter)");
|
||||
$this->dbh->query("INSERT INTO ttrss_filters2_rules (feed_id,cat_id,filter_id,filter_type,reg_exp,cat_filter,inverse)
|
||||
VALUES ($feed_id, $cat_id, $filter_id, $filter_type, '$reg_exp', $cat_filter,$inverse)");
|
||||
}
|
||||
|
||||
foreach ($filter["actions"] as $action) {
|
||||
|
||||
@@ -37,6 +37,12 @@ class PluginHost {
|
||||
const HOOK_PREFS_EDIT_FEED = 20;
|
||||
const HOOK_PREFS_SAVE_FEED = 21;
|
||||
const HOOK_FETCH_FEED = 22;
|
||||
const HOOK_QUERY_HEADLINES = 23;
|
||||
const HOOK_HOUSE_KEEPING = 24;
|
||||
const HOOK_SEARCH = 25;
|
||||
const HOOK_FORMAT_ENCLOSURES = 26;
|
||||
const HOOK_SUBSCRIBE_FEED = 27;
|
||||
const HOOK_HEADLINES_BEFORE = 28;
|
||||
|
||||
const KIND_ALL = 1;
|
||||
const KIND_SYSTEM = 2;
|
||||
@@ -73,6 +79,16 @@ class PluginHost {
|
||||
return $this->dbh;
|
||||
}
|
||||
|
||||
function get_plugin_names() {
|
||||
$names = array();
|
||||
|
||||
foreach ($this->plugins as $p) {
|
||||
array_push($names, get_class($p));
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
function get_plugins() {
|
||||
return $this->plugins;
|
||||
}
|
||||
@@ -97,7 +113,7 @@ class PluginHost {
|
||||
|
||||
function del_hook($type, $sender) {
|
||||
if (is_array($this->hooks[$type])) {
|
||||
$key = array_Search($this->hooks[$type], $sender);
|
||||
$key = array_Search($sender, $this->hooks[$type]);
|
||||
if ($key !== FALSE) {
|
||||
unset($this->hooks[$type][$key]);
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ class Pref_Feeds extends Handler_Protected {
|
||||
$cat['unread'] = 0;
|
||||
$cat['child_unread'] = 0;
|
||||
$cat['auxcounter'] = 0;
|
||||
$cat['parent_id'] = $cat_id;
|
||||
|
||||
$cat['items'] = $this->get_category_items($line['id']);
|
||||
|
||||
@@ -395,7 +396,7 @@ class Pref_Feeds extends Handler_Protected {
|
||||
# print_r($data['items']);
|
||||
|
||||
if (is_array($data) && is_array($data['items'])) {
|
||||
$cat_order_id = 0;
|
||||
# $cat_order_id = 0;
|
||||
|
||||
$data_map = array();
|
||||
$root_item = false;
|
||||
@@ -494,7 +495,7 @@ class Pref_Feeds extends Handler_Protected {
|
||||
$feed_id = $this->dbh->escape_string($_REQUEST["feed_id"]);
|
||||
|
||||
if (is_file($icon_file) && $feed_id) {
|
||||
if (filesize($icon_file) < 20000) {
|
||||
if (filesize($icon_file) < 65535) {
|
||||
|
||||
$result = $this->dbh->query("SELECT id FROM ttrss_feeds
|
||||
WHERE id = '$feed_id' AND owner_uid = ". $_SESSION["uid"]);
|
||||
@@ -572,8 +573,9 @@ class Pref_Feeds extends Handler_Protected {
|
||||
$last_error = $this->dbh->fetch_result($result, 0, "last_error");
|
||||
|
||||
if ($last_error) {
|
||||
print " <span title=\"".htmlspecialchars($last_error)."\"
|
||||
class=\"feed_error\">(error)</span>";
|
||||
print " <img src=\"images/error.png\" alt=\"(error)\"
|
||||
style=\"vertical-align : middle\"
|
||||
title=\"".htmlspecialchars($last_error)."\">";
|
||||
|
||||
}
|
||||
|
||||
@@ -736,9 +738,9 @@ class Pref_Feeds extends Handler_Protected {
|
||||
<input type=\"hidden\" name=\"op\" value=\"pref-feeds\">
|
||||
<input type=\"hidden\" name=\"feed_id\" value=\"$feed_id\">
|
||||
<input type=\"hidden\" name=\"method\" value=\"uploadicon\">
|
||||
<button dojoType=\"dijit.form.Button\" onclick=\"return uploadFeedIcon();\"
|
||||
<button class=\"small\" dojoType=\"dijit.form.Button\" onclick=\"return uploadFeedIcon();\"
|
||||
type=\"submit\">".__('Replace')."</button>
|
||||
<button dojoType=\"dijit.form.Button\" onclick=\"return removeFeedIcon($feed_id);\"
|
||||
<button class=\"small\" dojoType=\"dijit.form.Button\" onclick=\"return removeFeedIcon($feed_id);\"
|
||||
type=\"submit\">".__('Remove')."</button>
|
||||
</form>";
|
||||
|
||||
@@ -792,31 +794,10 @@ class Pref_Feeds extends Handler_Protected {
|
||||
print "<div class=\"dlgSec\">".__("Feed")."</div>";
|
||||
print "<div class=\"dlgSecCont\">";
|
||||
|
||||
/* Title */
|
||||
|
||||
print "<input dojoType=\"dijit.form.ValidationTextBox\"
|
||||
disabled=\"1\" style=\"font-size : 16px; width : 20em;\" required=\"1\"
|
||||
name=\"title\" value=\"\">";
|
||||
|
||||
$this->batch_edit_cbox("title");
|
||||
|
||||
/* Feed URL */
|
||||
|
||||
print "<br/>";
|
||||
|
||||
print __('URL:') . " ";
|
||||
print "<input dojoType=\"dijit.form.ValidationTextBox\" disabled=\"1\"
|
||||
required=\"1\" regExp='^(http|https)://.*' style=\"width : 20em\"
|
||||
name=\"feed_url\" value=\"\">";
|
||||
|
||||
$this->batch_edit_cbox("feed_url");
|
||||
|
||||
/* Category */
|
||||
|
||||
if (get_pref('ENABLE_FEED_CATS')) {
|
||||
|
||||
print "<br/>";
|
||||
|
||||
print __('Place in category:') . " ";
|
||||
|
||||
print_feed_cat_select("cat_id", false,
|
||||
@@ -862,7 +843,7 @@ class Pref_Feeds extends Handler_Protected {
|
||||
|
||||
$this->batch_edit_cbox("auth_login");
|
||||
|
||||
print "<br/><input dojoType=\"dijit.form.TextBox\" type=\"password\" name=\"auth_pass\"
|
||||
print "<hr/> <input dojoType=\"dijit.form.TextBox\" type=\"password\" name=\"auth_pass\"
|
||||
placeHolder=\"".__("Password")."\" disabled=\"1\"
|
||||
value=\"\">";
|
||||
|
||||
@@ -982,7 +963,7 @@ class Pref_Feeds extends Handler_Protected {
|
||||
|
||||
if (!$batch) {
|
||||
|
||||
$result = $this->dbh->query("UPDATE ttrss_feeds SET
|
||||
$this->dbh->query("UPDATE ttrss_feeds SET
|
||||
$category_qpart
|
||||
title = '$feed_title', feed_url = '$feed_link',
|
||||
update_interval = '$upd_intl',
|
||||
@@ -1279,13 +1260,18 @@ class Pref_Feeds extends Handler_Protected {
|
||||
$interval_qpart = "DATE_SUB(NOW(), INTERVAL 3 MONTH)";
|
||||
}
|
||||
|
||||
$result = $this->dbh->query("SELECT COUNT(*) AS num_inactive FROM ttrss_feeds WHERE
|
||||
// could be performance-intensive and prevent feeds pref-panel from showing
|
||||
if (!defined('_DISABLE_INACTIVE_FEEDS') || !_DISABLE_INACTIVE_FEEDS) {
|
||||
$result = $this->dbh->query("SELECT COUNT(*) AS num_inactive FROM ttrss_feeds WHERE
|
||||
(SELECT MAX(updated) FROM ttrss_entries, ttrss_user_entries WHERE
|
||||
ttrss_entries.id = ref_id AND
|
||||
ttrss_user_entries.feed_id = ttrss_feeds.id) < $interval_qpart AND
|
||||
ttrss_feeds.owner_uid = ".$_SESSION["uid"]);
|
||||
|
||||
$num_inactive = $this->dbh->fetch_result($result, 0, "num_inactive");
|
||||
$num_inactive = $this->dbh->fetch_result($result, 0, "num_inactive");
|
||||
} else {
|
||||
$num_inactive = 0;
|
||||
}
|
||||
|
||||
if ($num_inactive > 0) {
|
||||
$inactive_button = "<button dojoType=\"dijit.form.Button\"
|
||||
@@ -1492,15 +1478,6 @@ class Pref_Feeds extends Handler_Protected {
|
||||
|
||||
print "</p>";
|
||||
|
||||
print_warning(__("You can disable all articles shared by unique URLs here."));
|
||||
|
||||
print "<p>";
|
||||
|
||||
print "<button dojoType=\"dijit.form.Button\" onclick=\"return clearArticleAccessKeys()\">".
|
||||
__('Unshare all articles')."</button> ";
|
||||
|
||||
print "</p>";
|
||||
|
||||
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION,
|
||||
"hook_prefs_tab_section", "prefFeedsPublishedGenerated");
|
||||
|
||||
@@ -1602,8 +1579,6 @@ class Pref_Feeds extends Handler_Protected {
|
||||
# class needed for selectTableRows()
|
||||
print "<tr class=\"placeholder\" $this_row_id>";
|
||||
|
||||
$edit_title = htmlspecialchars($line["title"]);
|
||||
|
||||
# id needed for selectTableRows()
|
||||
print "<td width='5%' align='center'><input
|
||||
onclick='toggleSelectRow2(this);' dojoType=\"dijit.form.CheckBox\"
|
||||
@@ -1668,8 +1643,6 @@ class Pref_Feeds extends Handler_Protected {
|
||||
# class needed for selectTableRows()
|
||||
print "<tr class=\"placeholder\" $this_row_id>";
|
||||
|
||||
$edit_title = htmlspecialchars($line["title"]);
|
||||
|
||||
# id needed for selectTableRows()
|
||||
print "<td width='5%' align='center'><input
|
||||
onclick='toggleSelectRow2(this);' dojoType=\"dijit.form.CheckBox\"
|
||||
@@ -1920,7 +1893,7 @@ class Pref_Feeds extends Handler_Protected {
|
||||
AND owner_uid = " . $owner_uid);
|
||||
|
||||
if ($this->dbh->num_rows($result) == 1) {
|
||||
$key = $this->dbh->escape_string(sha1(uniqid(rand(), true)));
|
||||
$key = $this->dbh->escape_string(uniqid(base_convert(rand(), 10, 36)));
|
||||
|
||||
$this->dbh->query("UPDATE ttrss_access_keys SET access_key = '$key'
|
||||
WHERE feed_id = '$feed_id' AND is_cat = $sql_is_cat
|
||||
|
||||
@@ -88,7 +88,6 @@ class Pref_Filters extends Handler_Protected {
|
||||
|
||||
$result = $qfh_ret[0];
|
||||
|
||||
$articles = array();
|
||||
$found = 0;
|
||||
|
||||
print __("Articles matching this filter:");
|
||||
@@ -97,12 +96,13 @@ class Pref_Filters extends Handler_Protected {
|
||||
print "<table width=\"100%\" cellspacing=\"0\" id=\"prefErrorFeedList\">";
|
||||
|
||||
while ($line = $this->dbh->fetch_assoc($result)) {
|
||||
$line["content_preview"] = truncate_string(strip_tags($line["content"]), 100, '...');
|
||||
|
||||
$entry_timestamp = strtotime($line["updated"]);
|
||||
$entry_tags = get_article_tags($line["id"], $_SESSION["uid"]);
|
||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
|
||||
$line = $p->hook_query_headlines($line, 100);
|
||||
}
|
||||
|
||||
$content_preview = truncate_string(
|
||||
strip_tags($line["content_preview"]), 100, '...');
|
||||
$content_preview = $line["content_preview"];
|
||||
|
||||
if ($line["feed_title"])
|
||||
$feed_title = $line["feed_title"];
|
||||
@@ -147,6 +147,40 @@ class Pref_Filters extends Handler_Protected {
|
||||
|
||||
}
|
||||
|
||||
private function getfilterrules_concise($filter_id) {
|
||||
$result = $this->dbh->query("SELECT reg_exp,
|
||||
inverse,
|
||||
feed_id,
|
||||
cat_id,
|
||||
cat_filter,
|
||||
ttrss_filter_types.description AS field
|
||||
FROM
|
||||
ttrss_filters2_rules, ttrss_filter_types
|
||||
WHERE
|
||||
filter_id = '$filter_id' AND filter_type = ttrss_filter_types.id");
|
||||
|
||||
$rv = "";
|
||||
|
||||
while ($line = $this->dbh->fetch_assoc($result)) {
|
||||
|
||||
$where = sql_bool_to_bool($line["cat_filter"]) ?
|
||||
getCategoryTitle($line["cat_id"]) :
|
||||
($line["feed_id"] ?
|
||||
getFeedTitle($line["feed_id"]) : __("All feeds"));
|
||||
|
||||
# $where = $line["cat_id"] . "/" . $line["feed_id"];
|
||||
|
||||
$inverse = sql_bool_to_bool($line["inverse"]) ? "inverse" : "";
|
||||
|
||||
$rv .= "<span class='$inverse'>" . T_sprintf("%s on %s in %s %s",
|
||||
strip_tags($line["reg_exp"]),
|
||||
$line["field"],
|
||||
$where,
|
||||
sql_bool_to_bool($line["inverse"]) ? __("(inverse)") : "") . "</span>";
|
||||
}
|
||||
|
||||
return $rv;
|
||||
}
|
||||
|
||||
function getfiltertree() {
|
||||
$root = array();
|
||||
@@ -170,24 +204,11 @@ class Pref_Filters extends Handler_Protected {
|
||||
owner_uid = ".$_SESSION["uid"]." ORDER BY order_id, title");
|
||||
|
||||
|
||||
$action_id = -1;
|
||||
$folder = array();
|
||||
$folder['items'] = array();
|
||||
|
||||
while ($line = $this->dbh->fetch_assoc($result)) {
|
||||
|
||||
/* if ($action_id != $line["action_id"]) {
|
||||
if (count($folder['items']) > 0) {
|
||||
array_push($root['items'], $folder);
|
||||
}
|
||||
|
||||
$folder = array();
|
||||
$folder['id'] = $line["action_id"];
|
||||
$folder['name'] = __($line["action_name"]);
|
||||
$folder['items'] = array();
|
||||
$action_id = $line["action_id"];
|
||||
} */
|
||||
|
||||
$name = $this->getFilterName($line["id"]);
|
||||
|
||||
$match_ok = false;
|
||||
@@ -223,6 +244,7 @@ class Pref_Filters extends Handler_Protected {
|
||||
$filter['param'] = $name[1];
|
||||
$filter['checkbox'] = false;
|
||||
$filter['enabled'] = sql_bool_to_bool($line["enabled"]);
|
||||
$filter['rules'] = $this->getfilterrules_concise($line['id']);
|
||||
|
||||
if (!$filter_search || $match_ok) {
|
||||
array_push($folder['items'], $filter);
|
||||
@@ -429,8 +451,11 @@ class Pref_Filters extends Handler_Protected {
|
||||
WHERE id = ".(int)$rule["filter_type"]);
|
||||
$filter_type = $this->dbh->fetch_result($result, 0, "description");
|
||||
|
||||
return T_sprintf("%s on %s in %s %s", strip_tags($rule["reg_exp"]),
|
||||
$filter_type, $feed, isset($rule["inverse"]) ? __("(inverse)") : "");
|
||||
$inverse = isset($rule["inverse"]) ? "inverse" : "";
|
||||
|
||||
return "<span class='filterRule $inverse'>" .
|
||||
T_sprintf("%s on %s in %s %s", strip_tags($rule["reg_exp"]),
|
||||
$filter_type, $feed, isset($rule["inverse"]) ? __("(inverse)") : "") . "</span>";
|
||||
}
|
||||
|
||||
function printRuleName() {
|
||||
@@ -467,7 +492,7 @@ class Pref_Filters extends Handler_Protected {
|
||||
$inverse = checkbox_to_sql_bool($this->dbh->escape_string($_REQUEST["inverse"]));
|
||||
$title = $this->dbh->escape_string($_REQUEST["title"]);
|
||||
|
||||
$result = $this->dbh->query("UPDATE ttrss_filters2 SET enabled = $enabled,
|
||||
$this->dbh->query("UPDATE ttrss_filters2 SET enabled = $enabled,
|
||||
match_any_rule = $match_any_rule,
|
||||
inverse = $inverse,
|
||||
title = '$title'
|
||||
@@ -585,14 +610,15 @@ class Pref_Filters extends Handler_Protected {
|
||||
$enabled = checkbox_to_sql_bool($_REQUEST["enabled"]);
|
||||
$match_any_rule = checkbox_to_sql_bool($_REQUEST["match_any_rule"]);
|
||||
$title = $this->dbh->escape_string($_REQUEST["title"]);
|
||||
$inverse = checkbox_to_sql_bool($_REQUEST["inverse"]);
|
||||
|
||||
$this->dbh->query("BEGIN");
|
||||
|
||||
/* create base filter */
|
||||
|
||||
$result = $this->dbh->query("INSERT INTO ttrss_filters2
|
||||
(owner_uid, match_any_rule, enabled, title) VALUES
|
||||
(".$_SESSION["uid"].",$match_any_rule,$enabled, '$title')");
|
||||
(owner_uid, match_any_rule, enabled, title, inverse) VALUES
|
||||
(".$_SESSION["uid"].",$match_any_rule,$enabled, '$title', $inverse)");
|
||||
|
||||
$result = $this->dbh->query("SELECT MAX(id) AS id FROM ttrss_filters2
|
||||
WHERE owner_uid = ".$_SESSION["uid"]);
|
||||
@@ -870,6 +896,11 @@ class Pref_Filters extends Handler_Protected {
|
||||
|
||||
print "<div class=\"dlgButtons\">";
|
||||
|
||||
print "<div style=\"float : left\">
|
||||
<a class=\"visibleLink\" target=\"_blank\" href=\"http://tt-rss.org/wiki/ContentFilters\">".__("Wiki: Filters")."</a>
|
||||
</div>";
|
||||
|
||||
|
||||
print "<button dojoType=\"dijit.form.Button\" onclick=\"return dijit.byId('filterNewRuleDlg').execute()\">".
|
||||
($rule ? __("Save rule") : __('Add rule'))."</button> ";
|
||||
|
||||
|
||||
@@ -181,7 +181,8 @@ class Pref_Prefs extends Handler_Protected {
|
||||
global $access_level_names;
|
||||
|
||||
$prefs_blacklist = array("STRIP_UNSAFE_TAGS", "REVERSE_HEADLINES",
|
||||
"SORT_HEADLINES_BY_FEED_DATE", "DEFAULT_ARTICLE_LIMIT");
|
||||
"SORT_HEADLINES_BY_FEED_DATE", "DEFAULT_ARTICLE_LIMIT",
|
||||
"FEEDS_SORT_BY_UNREAD");
|
||||
|
||||
/* "FEEDS_SORT_BY_UNREAD", "HIDE_READ_FEEDS", "REVERSE_HEADLINES" */
|
||||
|
||||
@@ -765,7 +766,9 @@ class Pref_Prefs extends Handler_Protected {
|
||||
dojoType=\"dijit.form.CheckBox\" $checked
|
||||
type=\"checkbox\"></td>";
|
||||
|
||||
print "<td>$name</td>";
|
||||
$plugin_icon = $checked ? "plugin.png" : "plugin_disabled.png";
|
||||
|
||||
print "<td><label><img src='images/$plugin_icon' alt=''> $name</label></td>";
|
||||
print "<td>" . htmlspecialchars($about[1]);
|
||||
if (@$about[4]) {
|
||||
print " — <a target=\"_blank\" class=\"visibleLink\"
|
||||
@@ -818,11 +821,13 @@ class Pref_Prefs extends Handler_Protected {
|
||||
|
||||
print "<tr class='$rowclass'>";
|
||||
|
||||
$plugin_icon = $checked ? "plugin.png" : "plugin_disabled.png";
|
||||
|
||||
print "<td align='center'><input id='FPCHK-$name' name='plugins[]' value='$name' onclick='toggleSelectRow2(this);'
|
||||
dojoType=\"dijit.form.CheckBox\" $checked $disabled
|
||||
type=\"checkbox\"></td>";
|
||||
|
||||
print "<td><label for='FPCHK-$name'>$name</label></td>";
|
||||
print "<td><label for='FPCHK-$name'><img src='images/$plugin_icon' alt=''> $name</label></td>";
|
||||
print "<td><label for='FPCHK-$name'>" . htmlspecialchars($about[1]) . "</label>";
|
||||
if (@$about[4]) {
|
||||
print " — <a target=\"_blank\" class=\"visibleLink\"
|
||||
@@ -883,8 +888,9 @@ class Pref_Prefs extends Handler_Protected {
|
||||
|
||||
if (!$otp_enabled) {
|
||||
$secret = $base32->encode(sha1($this->dbh->fetch_result($result, 0, "salt")));
|
||||
$topt = new \OTPHP\TOTP($secret);
|
||||
print QRcode::png($topt->provisioning_uri($login));
|
||||
print QRcode::png("otpauth://totp/".urlencode($login).
|
||||
"?secret=$secret&issuer=".urlencode("Tiny Tiny RSS"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@ class Pref_Users extends Handler_Protected {
|
||||
|
||||
$pwd_hash = encrypt_password($tmp_user_pwd, $new_salt, true);
|
||||
|
||||
db_query("UPDATE ttrss_users SET pwd_hash = '$pwd_hash', salt = '$new_salt'
|
||||
db_query("UPDATE ttrss_users SET pwd_hash = '$pwd_hash', salt = '$new_salt', otp_enabled = false
|
||||
WHERE id = '$uid'");
|
||||
|
||||
if ($show_password) {
|
||||
@@ -418,7 +418,7 @@ class Pref_Users extends Handler_Protected {
|
||||
|
||||
$onclick = "onclick='editUser($uid, event)' title='".__('Click to edit')."'";
|
||||
|
||||
print "<td $onclick>" . $line["login"] . "</td>";
|
||||
print "<td $onclick><img src='images/user.png' class='markedPic' alt=''> " . $line["login"] . "</td>";
|
||||
|
||||
if (!$line["email"]) $line["email"] = " ";
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ class RPC extends Handler_Protected {
|
||||
WHERE orig_feed_id = '$id') = 0 AND
|
||||
id = '$id' AND owner_uid = ".$_SESSION["uid"]);
|
||||
|
||||
$rc = $this->dbh->affected_rows($result);
|
||||
$this->dbh->affected_rows($result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ class RPC extends Handler_Protected {
|
||||
$mark = "false";
|
||||
}
|
||||
|
||||
$result = $this->dbh->query("UPDATE ttrss_user_entries SET marked = $mark,
|
||||
$this->dbh->query("UPDATE ttrss_user_entries SET marked = $mark,
|
||||
last_marked = NOW()
|
||||
WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
|
||||
|
||||
@@ -148,8 +148,8 @@ class RPC extends Handler_Protected {
|
||||
function delete() {
|
||||
$ids = $this->dbh->escape_string($_REQUEST["ids"]);
|
||||
|
||||
$result = $this->dbh->query("DELETE FROM ttrss_user_entries
|
||||
WHERE ref_id IN ($ids) AND owner_uid = " . $_SESSION["uid"]);
|
||||
$this->dbh->query("DELETE FROM ttrss_user_entries
|
||||
WHERE ref_id IN ($ids) AND owner_uid = " . $_SESSION["uid"]);
|
||||
|
||||
purge_orphans();
|
||||
|
||||
@@ -258,7 +258,6 @@ class RPC extends Handler_Protected {
|
||||
function publ() {
|
||||
$pub = $_REQUEST["pub"];
|
||||
$id = $this->dbh->escape_string($_REQUEST["id"]);
|
||||
$note = trim(strip_tags($this->dbh->escape_string($_REQUEST["note"])));
|
||||
|
||||
if ($pub == "1") {
|
||||
$pub = "true";
|
||||
@@ -266,7 +265,7 @@ class RPC extends Handler_Protected {
|
||||
$pub = "false";
|
||||
}
|
||||
|
||||
$result = $this->dbh->query("UPDATE ttrss_user_entries SET
|
||||
$this->dbh->query("UPDATE ttrss_user_entries SET
|
||||
published = $pub, last_published = NOW()
|
||||
WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
|
||||
|
||||
@@ -467,14 +466,6 @@ class RPC extends Handler_Protected {
|
||||
print_feed_cat_select("cat_id", $id, '');
|
||||
}
|
||||
|
||||
// Silent
|
||||
function clearArticleKeys() {
|
||||
$this->dbh->query("UPDATE ttrss_user_entries SET uuid = '' WHERE
|
||||
owner_uid = " . $_SESSION["uid"]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
function setpanelmode() {
|
||||
$wide = (int) $_REQUEST["wide"];
|
||||
|
||||
@@ -484,7 +475,8 @@ class RPC extends Handler_Protected {
|
||||
print json_encode(array("wide" => $wide));
|
||||
}
|
||||
|
||||
function updaterandomfeed() {
|
||||
static function updaterandomfeed_real($dbh) {
|
||||
|
||||
// Test if the feed need a update (update interval exceded).
|
||||
if (DB_TYPE == "pgsql") {
|
||||
$update_limit_qpart = "AND ((
|
||||
@@ -515,16 +507,24 @@ class RPC extends Handler_Protected {
|
||||
|
||||
$random_qpart = sql_random_function();
|
||||
|
||||
// we could be invoked from public.php with no active session
|
||||
if ($_SESSION["uid"]) {
|
||||
$owner_check_qpart = "AND ttrss_feeds.owner_uid = '".$_SESSION["uid"]."'";
|
||||
} else {
|
||||
$owner_check_qpart = "";
|
||||
}
|
||||
|
||||
// We search for feed needing update.
|
||||
$result = $this->dbh->query("SELECT ttrss_feeds.feed_url,ttrss_feeds.id
|
||||
$result = $dbh->query("SELECT ttrss_feeds.feed_url,ttrss_feeds.id
|
||||
FROM
|
||||
ttrss_feeds, ttrss_users, ttrss_user_prefs
|
||||
WHERE
|
||||
ttrss_feeds.owner_uid = ttrss_users.id
|
||||
AND ttrss_users.id = ttrss_user_prefs.owner_uid
|
||||
AND ttrss_user_prefs.pref_name = 'DEFAULT_UPDATE_INTERVAL'
|
||||
AND ttrss_feeds.owner_uid = ".$_SESSION["uid"]."
|
||||
$update_limit_qpart $updstart_thresh_qpart
|
||||
$owner_check_qpart
|
||||
$update_limit_qpart
|
||||
$updstart_thresh_qpart
|
||||
ORDER BY $random_qpart LIMIT 30");
|
||||
|
||||
$feed_id = -1;
|
||||
@@ -535,7 +535,7 @@ class RPC extends Handler_Protected {
|
||||
|
||||
$tstart = time();
|
||||
|
||||
while ($line = $this->dbh->fetch_assoc($result)) {
|
||||
while ($line = $dbh->fetch_assoc($result)) {
|
||||
$feed_id = $line["id"];
|
||||
|
||||
if (time() - $tstart < ini_get("max_execution_time") * 0.7) {
|
||||
@@ -559,6 +559,10 @@ class RPC extends Handler_Protected {
|
||||
|
||||
}
|
||||
|
||||
function updaterandomfeed() {
|
||||
RPC::updaterandomfeed_real($this->dbh);
|
||||
}
|
||||
|
||||
private function markArticlesById($ids, $cmode) {
|
||||
|
||||
$tmp_ids = array();
|
||||
@@ -615,7 +619,7 @@ class RPC extends Handler_Protected {
|
||||
|
||||
$p = new Publisher(PUBSUBHUBBUB_HUB);
|
||||
|
||||
$pubsub_result = $p->publish_update($rss_link);
|
||||
/* $pubsub_result = */ $p->publish_update($rss_link);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
// *** Basic settings (important!) ***
|
||||
// ***********************************
|
||||
|
||||
define('SELF_URL_PATH', 'http://yourserver/tt-rss/');
|
||||
define('SELF_URL_PATH', 'http://example.org/tt-rss/');
|
||||
// Full URL of your tt-rss installation. This should be set to the
|
||||
// location of tt-rss directory, e.g. http://yourserver/tt-rss/
|
||||
// location of tt-rss directory, e.g. http://example.org/tt-rss/
|
||||
// You need to set this option correctly otherwise several features
|
||||
// including PUSH, bookmarklets and browser integration will not work properly.
|
||||
|
||||
@@ -50,10 +50,11 @@
|
||||
// *****************************
|
||||
|
||||
define('PHP_EXECUTABLE', '/usr/bin/php');
|
||||
// Path to PHP *COMMAND LINE* executable, used for various command-line tt-rss programs and
|
||||
// update daemon. Do not try to use CGI binary here, it won't work. If you see HTTP headers
|
||||
// being displayed while running tt-rss scripts, then most probably you are using the CGI
|
||||
// binary. If you are unsure what to put in here, ask your hosting provider.
|
||||
// Path to PHP *COMMAND LINE* executable, used for various command-line tt-rss
|
||||
// programs and update daemon. Do not try to use CGI binary here, it won't work.
|
||||
// If you see HTTP headers being displayed while running tt-rss scripts,
|
||||
// then most probably you are using the CGI binary. If you are unsure what to
|
||||
// put in here, ask your hosting provider.
|
||||
|
||||
define('LOCK_DIRECTORY', 'lock');
|
||||
// Directory for lockfiles, must be writable to the user you run
|
||||
@@ -103,13 +104,9 @@
|
||||
// Enable client PubSubHubbub support in tt-rss. When disabled, tt-rss
|
||||
// won't try to subscribe to PUSH feed updates.
|
||||
|
||||
// *********************
|
||||
// *** Sphinx search ***
|
||||
// *********************
|
||||
|
||||
define('SPHINX_ENABLED', false);
|
||||
// Enable fulltext search using Sphinx (http://www.sphinxsearch.com)
|
||||
// Please see http://tt-rss.org/wiki/SphinxSearch for more information.
|
||||
// ****************************
|
||||
// *** Sphinx search plugin ***
|
||||
// ****************************
|
||||
|
||||
define('SPHINX_SERVER', 'localhost:9312');
|
||||
// Hostname:port combination for the Sphinx server.
|
||||
@@ -173,7 +170,8 @@
|
||||
// outgoing mail. Only used with SMTP_SERVER.
|
||||
|
||||
define('SMTP_SECURE', '');
|
||||
// used to select a secure SMTP conneciton. can be tls, ssl or enpty
|
||||
// Used to select a secure SMTP connection. Allowed values: ssl, tls,
|
||||
// or empty.
|
||||
|
||||
// ***************************************
|
||||
// *** Other settings (less important) ***
|
||||
@@ -182,6 +180,12 @@
|
||||
define('CHECK_FOR_NEW_VERSION', true);
|
||||
// Check for new versions of tt-rss automatically.
|
||||
|
||||
define('DETECT_ARTICLE_LANGUAGE', false);
|
||||
// Detect article language when updating feeds, presently this is only
|
||||
// used for hyphenation. This may increase amount of CPU time used by
|
||||
// update processes, disable if necessary (i.e. you are being billed
|
||||
// for CPU time).
|
||||
|
||||
define('ENABLE_GZIP_OUTPUT', false);
|
||||
// Selectively gzip output to improve wire performance. This requires
|
||||
// PHP Zlib extension on the server.
|
||||
@@ -209,4 +213,3 @@
|
||||
// if necessary (after migrating all new options from this file).
|
||||
|
||||
// vim:ft=php
|
||||
?>
|
||||
|
||||
191
css/cdm.css
@@ -52,7 +52,8 @@ div.cdmHeader input {
|
||||
|
||||
div.cdmContentInner {
|
||||
margin : 10px;
|
||||
line-height : 20px;
|
||||
line-height : 1.5;
|
||||
font-size : 15px;
|
||||
}
|
||||
|
||||
div.cdmContentInner img {
|
||||
@@ -61,6 +62,16 @@ div.cdmContentInner img {
|
||||
height : auto;
|
||||
}
|
||||
|
||||
div.cdmContentInner h1 {
|
||||
font-size : 16px;
|
||||
}
|
||||
|
||||
div.cdmContentInner h2,
|
||||
div.cdmContentInner h3,
|
||||
div.cdmContentInner h4 {
|
||||
font-size : 15px;
|
||||
}
|
||||
|
||||
div.cdmFooter {
|
||||
padding : 5px;
|
||||
font-weight : normal;
|
||||
@@ -68,15 +79,25 @@ div.cdmFooter {
|
||||
clear : both;
|
||||
}
|
||||
|
||||
div.cdm {
|
||||
margin-right : 4px;
|
||||
}
|
||||
|
||||
div.cdm.expanded {
|
||||
margin-top : 4px;
|
||||
margin-bottom : 4px;
|
||||
}
|
||||
|
||||
div.cdm.expanded div.cdmFooter {
|
||||
border-style : solid;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-color : #ddd;
|
||||
}
|
||||
|
||||
div.cdm.expandable {
|
||||
background-color : #f0f0f0;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-color : #c0c0c0;
|
||||
border-color : #ddd;
|
||||
border-style : solid;
|
||||
}
|
||||
|
||||
@@ -98,8 +119,6 @@ div.cdm.expandable.Selected {
|
||||
}
|
||||
|
||||
div.cdm.expandable.active {
|
||||
box-shadow : inset 0px 0px 3px 0px rgba(0,0,0,0.1);
|
||||
border-color : #88b0f0;
|
||||
background : white ! important;
|
||||
}
|
||||
|
||||
@@ -110,9 +129,20 @@ div.cdm.expandable div.cdmHeader span.titleWrap {
|
||||
max-width : 500px;
|
||||
}
|
||||
|
||||
div.cdm.expandable.active div.cdmHeader span.titleWrap {
|
||||
white-space : normal;
|
||||
}
|
||||
|
||||
div.cdm.expandable div.cdmHeader a.title {
|
||||
font-weight : bold;
|
||||
font-weight : 600;
|
||||
color : #555;
|
||||
font-size : 14px;
|
||||
-webkit-transition : color 0.2s;
|
||||
transition : color 0.2s;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
div.cdm.expandable.Unread div.cdmHeader a.title {
|
||||
@@ -121,6 +151,12 @@ div.cdm.expandable.Unread div.cdmHeader a.title {
|
||||
|
||||
div.cdm.expandable.active div.cdmHeader a.title {
|
||||
color : #4684ff;
|
||||
font-size : 16px;
|
||||
font-weight : 600;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
div.cdm.expanded div.cdmHeader {
|
||||
@@ -128,9 +164,15 @@ div.cdm.expanded div.cdmHeader {
|
||||
}
|
||||
|
||||
div.cdm.expanded div.cdmHeader a.title {
|
||||
font-size : 14px;
|
||||
font-size : 16px;
|
||||
color : #999;
|
||||
font-weight : bold;
|
||||
font-weight : 600;
|
||||
-webkit-transition : color 0.2s;
|
||||
transition : color 0.2s;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
div.cdm.expanded.active {
|
||||
@@ -159,7 +201,7 @@ div.cdm.active div.cdmContent {
|
||||
|
||||
span.cdmExcerpt {
|
||||
font-size : 11px;
|
||||
color : #555;
|
||||
color : #999;
|
||||
font-weight : normal;
|
||||
cursor : pointer;
|
||||
}
|
||||
@@ -174,7 +216,7 @@ div.cdmFeedTitle {
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-style : solid;
|
||||
padding : 5px 3px 5px 5px;
|
||||
background : url("images/toolbar.png") bottom left;
|
||||
background : url("../images/toolbar.png") bottom left;
|
||||
background-repeat : repeat-x;
|
||||
}
|
||||
|
||||
@@ -214,6 +256,9 @@ div.cdm .hlFeed a {
|
||||
|
||||
div.cdmContentInner p {
|
||||
max-width : 650px;
|
||||
-webkit-hyphens: auto;
|
||||
-moz-hyphens: auto;
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
div.cdmContentInner iframe {
|
||||
@@ -230,38 +275,126 @@ div.cdmHeader span.author {
|
||||
div#floatingTitle {
|
||||
position : absolute;
|
||||
z-index : 5;
|
||||
top : 30px;
|
||||
right : 20px;
|
||||
border : 1px solid #ccc;
|
||||
top : 0px;
|
||||
right : 0px;
|
||||
left : 0px;
|
||||
border-color : #ddd;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-style : solid;
|
||||
background : white;
|
||||
border-radius : 3px;
|
||||
box-shadow : 0px 0px 3px 0px rgba(0,0,0,0.1);
|
||||
color : #555;
|
||||
font-size : 10px;
|
||||
padding : 3px;
|
||||
box-shadow : 0px 1px 1px -1px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
div#floatingTitle > * {
|
||||
display : table-cell;
|
||||
white-space : nowrap;
|
||||
vertical-align : middle;
|
||||
}
|
||||
|
||||
div#floatingTitle span.titleWrap {
|
||||
max-width : 200px;
|
||||
overflow : hidden;
|
||||
text-overflow : ellipsis;
|
||||
padding : 9px 5px;
|
||||
}
|
||||
|
||||
div#floatingTitle img {
|
||||
padding-right : 3px;
|
||||
margin-right : 4px;
|
||||
margin-left : 4px;
|
||||
}
|
||||
|
||||
div#floatingTitle .dijit,
|
||||
div#floatingTitle span.updated,
|
||||
div#floatingTitle div.scoreWrap,
|
||||
div#floatingTitle div.hlFeed,
|
||||
div#floatingTitle span.author,
|
||||
div#floatingTitle img.tinyFeedIcon {
|
||||
div#floatingTitle span.author {
|
||||
color : #555;
|
||||
font-size : 11px;
|
||||
font-weight : normal;
|
||||
}
|
||||
|
||||
div#floatingTitle a.title {
|
||||
font-size : 16px;
|
||||
color : #999;
|
||||
-webkit-transition : color 0.2s;
|
||||
transition : color 0.2s;
|
||||
font-weight : 600;
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", Ubuntu, "DejaVu Sans", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
div#floatingTitle.Unread a.title {
|
||||
color : black;
|
||||
}
|
||||
|
||||
div#floatingTitle img.anchor {
|
||||
margin-left : 0px;
|
||||
}
|
||||
|
||||
div#floatingTitle div.hlFeed {
|
||||
padding-right : 10px;
|
||||
color : #555;
|
||||
font-weight : normal;
|
||||
font-style : italic;
|
||||
font-size : 11px;
|
||||
white-space : nowrap;
|
||||
}
|
||||
|
||||
div#floatingTitle div.hlFeed a {
|
||||
border-radius : 4px;
|
||||
display : inline-block;
|
||||
padding : 1px 4px 1px 4px;
|
||||
}
|
||||
|
||||
div#floatingTitle span.updated {
|
||||
padding-right : 10px;
|
||||
white-space : nowrap;
|
||||
color : #555;
|
||||
font-size : 11px;
|
||||
}
|
||||
|
||||
div#floatingTitle div.hlFeed a {
|
||||
color : #555;
|
||||
}
|
||||
|
||||
div#floatingTitle span.titleWrap {
|
||||
width : 100%;
|
||||
white-space : normal;
|
||||
}
|
||||
|
||||
div#floatingTitle .dijit,
|
||||
div#floatingTitle img.hlScorePic {
|
||||
display : none;
|
||||
}
|
||||
|
||||
.cdm.high .cdmHeader a.title.high, .cdm.high .cdmHeader .cdmExcerpt,
|
||||
.cdm.high .cdmHeader span.author {
|
||||
color : #00aa00;
|
||||
}
|
||||
|
||||
.cdm.Unread.high .cdmHeader a.title.high, .cdm.Unread.high .cdmHeader .cdmExcerpt,
|
||||
.cdm.Unread.high .cdmHeader span.author {
|
||||
color : #00dd00;
|
||||
}
|
||||
|
||||
.cdm .cdmHeader a.title.low, .cdm.low .cdmHeader .cdmExcerpt,
|
||||
.cdm.Unread .cdmHeader a.title.low, .cdm.Unread.low .cdmHeader .cdmExcerpt,
|
||||
.cdm.low .cdmHeader span.author {
|
||||
color : #909090;
|
||||
text-decoration : line-through;
|
||||
}
|
||||
|
||||
div.cdmFeedTitle > * {
|
||||
display : table-cell;
|
||||
vertical-align : middle;
|
||||
}
|
||||
|
||||
div.cdmFeedTitle a.title {
|
||||
width : 100%;
|
||||
}
|
||||
|
||||
div.cdmFeedTitle a.catchup {
|
||||
text-align : right;
|
||||
color : #555;
|
||||
padding-right : 10px;
|
||||
font-size : 11px;
|
||||
white-space : nowrap;
|
||||
}
|
||||
|
||||
div.cdmFeedTitle a.catchup:hover {
|
||||
color : #4684ff;
|
||||
}
|
||||
|
||||
|
||||
409
css/dijit.css
Normal file
@@ -0,0 +1,409 @@
|
||||
/* Tree */
|
||||
|
||||
.claro .dijitTreeRow .dijitCheckBox {
|
||||
position : relative;
|
||||
top : -2px;
|
||||
}
|
||||
|
||||
.claro .dijitTreeLabel {
|
||||
outline : 0;
|
||||
}
|
||||
|
||||
.claro .dijitTree .feedParam {
|
||||
color : #555;
|
||||
float : right;
|
||||
margin-right : 1em;
|
||||
}
|
||||
|
||||
.claro .dijitTree .filterRules {
|
||||
display : block;
|
||||
color : #ccc;
|
||||
font-size : 10px;
|
||||
margin-left : 100px;
|
||||
}
|
||||
|
||||
.claro .dijitTree .filterRules span {
|
||||
display : block;
|
||||
color : green;
|
||||
}
|
||||
|
||||
#filterDlg_Matches span.filterRule {
|
||||
color : green;
|
||||
}
|
||||
|
||||
.claro .dijitTree .filterRules span.inverse,
|
||||
#filterDlg_Matches span.filterRule.inverse {
|
||||
color : red;
|
||||
}
|
||||
|
||||
|
||||
.claro .dijitTree .labelParam {
|
||||
float : right;
|
||||
margin-right : 1em;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeLabel.Disabled,
|
||||
.claro .dijitTree .labelParam.Disabled {
|
||||
color : #555;
|
||||
}
|
||||
|
||||
.claro .dijitTreeRow.Error {
|
||||
color : red;
|
||||
}
|
||||
|
||||
.claro .dijitTreeRow.Hidden {
|
||||
display : none;
|
||||
}
|
||||
|
||||
.claro .dijitTreeNode .loadingNode {
|
||||
margin-left : 3px;
|
||||
height : 9px;
|
||||
}
|
||||
|
||||
.claro .dijitFolderClosed,
|
||||
.claro .dijitFolderOpened {
|
||||
display : none;
|
||||
}
|
||||
|
||||
.claro .dijitTreeNode .dijitCheckBox {
|
||||
margin-left : 4px;
|
||||
}
|
||||
|
||||
.claro .dijitTreeIsRoot > .dijitTreeRow > .dijitTreeExpando {
|
||||
margin-left : 5px;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeExpando {
|
||||
margin-top : 0px;
|
||||
opacity : 0.6;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeNode {
|
||||
padding : 0px;
|
||||
border-width : 0px;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeRow {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeRowSelected {
|
||||
background : white;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeRowHover {
|
||||
background : #f0f0f0;
|
||||
border-color : #ddd;
|
||||
}
|
||||
|
||||
.claro .dijitTree .dijitTreeRowSelected {
|
||||
background : white;
|
||||
border-color : #ddd;
|
||||
}
|
||||
|
||||
.claro .dijitTreeRowSelected .dijitTreeLabel {
|
||||
text-shadow : 1px 1px 2px #fff;
|
||||
}
|
||||
|
||||
.claro .dijitTreeRow .dijitTreeExpando {
|
||||
background-image: url("../images/treeExpandImages.png");
|
||||
position : relative;
|
||||
top : -1px;
|
||||
}
|
||||
|
||||
.claro .dijitTreeRow .dijitTreeExpandoLeaf {
|
||||
background : none;
|
||||
}
|
||||
|
||||
/* Toolbar */
|
||||
|
||||
.claro .dijitToolbar {
|
||||
background : #f5f5f5;
|
||||
border-color : #ddd;
|
||||
/* text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif; */
|
||||
}
|
||||
|
||||
/* .claro .dijitToolbar {
|
||||
text-shadow : 1px 1px 2px #fff;
|
||||
} */
|
||||
|
||||
.claro .dijitDialog .dijitToolbar {
|
||||
border : 1px solid #ddd;
|
||||
}
|
||||
|
||||
/* Dialog */
|
||||
|
||||
.claro .dijitDialog h2 {
|
||||
margin-top : 0px;
|
||||
margin-bottom : 4px;
|
||||
border-width : 0px;
|
||||
}
|
||||
|
||||
.claro .dijitMenuItemLabel {
|
||||
font-size : 13px;
|
||||
}
|
||||
|
||||
/* Checkbox */
|
||||
|
||||
.claro .dijitCheckBox {
|
||||
background-image : url("../images/untick.png");
|
||||
background-color : transparent;
|
||||
width : 15px;
|
||||
height : 15px;
|
||||
margin : 1px;
|
||||
opacity : 0.7;
|
||||
background-position : center center;
|
||||
transition : opacity 0.25s;
|
||||
-webkit-transition : opacity 0.25s;
|
||||
/* border : 1px solid #b5bcc7; */
|
||||
padding : 1px;
|
||||
}
|
||||
|
||||
.claro .dijitCheckBox:hover {
|
||||
opacity : 1;
|
||||
}
|
||||
|
||||
.claro .dijitCheckBox.dijitCheckBoxDisabled:hover {
|
||||
opacity : 0.7;
|
||||
}
|
||||
|
||||
.claro .dijitCheckBox.dijitCheckBoxChecked {
|
||||
border-color : #69C671;
|
||||
background-image : url("../images/tick.png");
|
||||
opacity : 1;
|
||||
}
|
||||
|
||||
/* Various buttons */
|
||||
|
||||
.claro .dijitButton .dijitButtonNode,
|
||||
.claro .dijitComboButton .dijitButtonNode,
|
||||
.claro .dijitToolbar .dijitDropDownButton .dijitButtonNode,
|
||||
.claro .dijitToolbar .dijitComboButton,
|
||||
.claro .dijitToolbar .dijitComboButton .dijitButtonNode {
|
||||
background : none;
|
||||
border-color : transparent;
|
||||
box-shadow : none;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type="submit"] {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size : 14px;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type="submit"],
|
||||
.claro .dijitButton,
|
||||
.claro .dijitComboButton {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
margin-bottom: 0;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
background-color: #f5f5f5;
|
||||
background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
|
||||
background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
|
||||
background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
|
||||
background-repeat: repeat-x;
|
||||
border: 1px solid #cccccc;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
border-bottom-color: #b3b3b3;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
button:hover,
|
||||
button:focus,
|
||||
button:active,
|
||||
input[type="submit"]:hover,
|
||||
input[type="submit"]:focus,
|
||||
input[type="submit"]:active,
|
||||
.claro .dijitButton:hover,
|
||||
.claro .dijitButton:focus,
|
||||
.claro .dijitButton:active,
|
||||
.claro .dijitComboButton:hover,
|
||||
.claro .dijitComboButton:focus,
|
||||
.claro .dijitComboButton:active,
|
||||
.claro .dijitButton.dijitButtonDisabled {
|
||||
color: #333333;
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
|
||||
button:active,
|
||||
input[type="submit"]:active,
|
||||
.claro .dijitButton:active,
|
||||
.claro .dijitComboButton:active {
|
||||
background-color: #cccccc \9;
|
||||
}
|
||||
|
||||
.claro .dijitToolbar .dijitButton,
|
||||
.claro .dijitToolbar .dijitButton.dijitHover,
|
||||
.claro .dijitToolbar .dijitComboButton,
|
||||
.claro .dijitToolbar .dijitComboButton.dijitHover {
|
||||
background : none;
|
||||
border-color : transparent;
|
||||
box-shadow : none;
|
||||
padding : 0px;
|
||||
margin : 0px;
|
||||
line-height : auto;
|
||||
text-shadow : none;
|
||||
}
|
||||
|
||||
.claro .dijitToolbar .dijitDropDownButton .dijitButtonText,
|
||||
.claro .dijitToolbar .dijitComboButton .dijitButtonText {
|
||||
padding : 0px;
|
||||
}
|
||||
|
||||
.claro .dijitToolbar .dijitDropDownButton .dijitButtonNode {
|
||||
border-radius : 4px;
|
||||
}
|
||||
|
||||
.claro .dijitToolbar .dijitButton.dijitHover,
|
||||
.claro .dijitToolbar .dijitDropDownButton.dijitHover .dijitButtonNode,
|
||||
.claro .dijitToolbar .dijitComboButton.dijitHover {
|
||||
border-color : #ccc;
|
||||
}
|
||||
|
||||
.claro .dijitToolbar .dijitButton.dijitHover .dijitButtonNode,
|
||||
.claro .dijitToolbar .dijitButton.dijitButtonActive .dijitButtonNode {
|
||||
background : none;
|
||||
}
|
||||
|
||||
.claro .dijitToolbar .dijitButton .dijitButtonContents,
|
||||
.claro .dijitToolbar .dijitDropDownButton .dijitButtonContents,
|
||||
.claro .dijitToolbar .dijitComboButton .dijitButtonContents {
|
||||
font-size : 13px;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
button:focus,
|
||||
input[type="submit"]:hover,
|
||||
input[type="submit"]:focus,
|
||||
.claro .dijitButton:hover,
|
||||
.claro .dijitToolbar .dijitButton:hover .dijitButtonNode,
|
||||
.claro .dijitToolbar .dijitButton.dijitHover .dijitButtonNode,
|
||||
.claro .dijitButton:focus,
|
||||
.claro .dijitComboButton:hover,
|
||||
.claro .dijitComboButton:focus {
|
||||
color: #333333;
|
||||
text-decoration: none;
|
||||
background-position: 0 -15px;
|
||||
-webkit-transition: background-position 0.1s linear;
|
||||
transition: background-position 0.1s linear;
|
||||
}
|
||||
|
||||
button:focus,
|
||||
input[type="submit"]:focus,
|
||||
.claro .dijitButton:focus,
|
||||
.claro .dijitComboButton:focus {
|
||||
outline: thin dotted #333;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
button:active,
|
||||
input[type="submit"]:active,
|
||||
.claro .dijitButton:active,
|
||||
.claro .dijitComboButton:active,
|
||||
.claro .dijitToolbar .dijitDropDownButton.dijitOpened,
|
||||
.claro .dijitToolbar .dijitComboButton.dijitOpened,
|
||||
.claro .dijitToolbar .dijitButton.dijitButtonActive .dijitButtonNode {
|
||||
background-image: none;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
input[type="submit"][disabled],
|
||||
button[disabled],
|
||||
.claro .dijitButton[disabled],
|
||||
.claro .dijitButton.dijitButtonDisabled,
|
||||
.claro .dijitComboButton.dijitButtonDisabled {
|
||||
cursor: default;
|
||||
background-image: none;
|
||||
opacity: 0.65;
|
||||
filter: alpha(opacity=65);
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.claro .dijitButton .dijitButtonContents,
|
||||
.claro .dijitComboButton .dijitButtonContents {
|
||||
font-size : 14px;
|
||||
font-weight : normal;
|
||||
line-height : 20px;
|
||||
}
|
||||
|
||||
.claro .dijitButton.small .dijitButtonText {
|
||||
font-size : 11px;
|
||||
}
|
||||
|
||||
.claro .dijitMenu {
|
||||
border-color : #ccc;
|
||||
}
|
||||
|
||||
.claro .dijitMenu .dijitMenuItem.dijitHover,
|
||||
.claro .dijitMenu .dijitMenuItem.dijitFocused,
|
||||
.claro .dijitMenuTable .dijitMenuItem.dijitHover .dijitMenuItemLabel,
|
||||
.claro .dijitMenuTable .dijitMenuItem.dijitFocused .dijitMenuItemLabel {
|
||||
background : #eee;
|
||||
border-color : transparent;
|
||||
}
|
||||
|
||||
.claro .dijitButton .dijitButtonNode,
|
||||
.claro .dijitComboButton .dijitButtonNode {
|
||||
padding : 0px;
|
||||
}
|
||||
|
||||
/* Other stuff */
|
||||
|
||||
/* .claro .dijitAccordionTitleFocus {
|
||||
text-shadow : 1px 1px 2px #fff;
|
||||
}
|
||||
|
||||
.claro .dijitAccordionTitle {
|
||||
text-rendering: optimizelegibility;
|
||||
font-family : "Segoe WP Semibold", "Segoe UI Semibold",
|
||||
"Segoe UI Web Semibold", "Segoe UI", "Helvetica Neue",
|
||||
Helvetica, Arial, sans-serif;
|
||||
} */
|
||||
|
||||
.claro .dijitAccordionInnerContainer.dijitAccordionInnerContainerSelected {
|
||||
border-color : #ccc;
|
||||
}
|
||||
|
||||
.claro .dijitAccordionContainer .dijitAccordionChildWrapper {
|
||||
border-color : #ddd;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
|
||||
.claro .dijitTabContent {
|
||||
background : #eee;
|
||||
}
|
||||
|
||||
.claro .dijitTabContent.dijitTabChecked,
|
||||
.claro .dijitTabContent.dijitTabHover,
|
||||
.claro .dijitTabContent.dijitFocused {
|
||||
background : white;
|
||||
}
|
||||
|
||||
.claro .dijitTabPaneWrapper,
|
||||
.claro .dijitTabContainerTop-tabs,
|
||||
.claro .dijitTab,
|
||||
.claro .dijitAccordionInnerContainer {
|
||||
border-color : #ddd;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
body#ttrssPrefs {
|
||||
background-color : #f5f5f5;
|
||||
}
|
||||
|
||||
body#ttrssPrefs #footer, body#ttrssPrefs #header {
|
||||
background-color : #f5f5f5;
|
||||
padding-left : 8px;
|
||||
padding-right : 8px;
|
||||
}
|
||||
|
||||
|
||||
#header a:hover {
|
||||
color : black;
|
||||
}
|
||||
@@ -13,12 +24,12 @@ div#pref-tabs .dijitContentPane {
|
||||
}
|
||||
|
||||
div#pref-tabs {
|
||||
box-shadow : 0px 1px 1px -1px rgba(0,0,0,0.1);
|
||||
margin : 0px 5px 0px 5px;
|
||||
}
|
||||
|
||||
div#pref-tabs .dijitContentPane h3 {
|
||||
font-size : 14px;
|
||||
font-weight : bold;
|
||||
}
|
||||
|
||||
#pref-filter-wrap, #pref-filter-header, #pref-filter-content,
|
||||
@@ -52,11 +63,10 @@ div.prefProfileHolder, div.prefFeedOPMLHolder, div.inactiveFeedHolder {
|
||||
height : 300px;
|
||||
overflow : auto;
|
||||
border-width : 0px 1px 1px 1px;
|
||||
border-color : #c0c0c0;
|
||||
border-color : #ddd;
|
||||
border-style : solid;
|
||||
margin : 0px 0px 5px 0px;
|
||||
background-color : #ecf4ff;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
background-color : white;
|
||||
}
|
||||
div.filterTestHolder, div.prefFeedOPMLHolder {
|
||||
border-width : 1px;
|
||||
@@ -66,12 +76,10 @@ ul.selfUpdateList, ul.userFeedList {
|
||||
height : 200px;
|
||||
overflow : auto;
|
||||
list-style-type : none;
|
||||
border : 1px solid #c0c0c0;
|
||||
background-color : #ecf4ff;
|
||||
border : 1px solid #ddd;
|
||||
background-color : #f5f5f5;
|
||||
margin : 0px 0px 5px 0px;
|
||||
padding : 5px;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
border-radius : 4px;
|
||||
}
|
||||
|
||||
div#feedlistLoading, div#filterlistLoading, div#labellistLoading {
|
||||
@@ -90,7 +98,8 @@ div#feedlistLoading img, div#filterlistLoading img, div#labellistLoading {
|
||||
|
||||
a.bookmarklet {
|
||||
color : #4684ff;
|
||||
border : 1px solid #ecf4ff;
|
||||
border : 1px solid #ddd;
|
||||
background : #f5f5f5;
|
||||
padding : 2px;
|
||||
}
|
||||
|
||||
@@ -98,6 +107,14 @@ table.prefPluginsList td label, table.prefUserList td {
|
||||
cursor : pointer;
|
||||
}
|
||||
|
||||
table.prefPluginsList label {
|
||||
white-space : nowrap;
|
||||
}
|
||||
|
||||
table.prefPluginsList label img {
|
||||
vertical-align : middle;
|
||||
}
|
||||
|
||||
table.prefErrorLog tr.errrow td {
|
||||
font-size : 10px;
|
||||
}
|
||||
@@ -112,7 +129,9 @@ table.prefErrorLog td.filename, table.prefErrorLog td.login, table.prefErrorLog
|
||||
color : #555;
|
||||
}
|
||||
|
||||
.dijitAccordionContainer-child {
|
||||
box-shadow : inset 0px 0px 3px rgba(0,0,0,0.2);
|
||||
body#ttrssPrefs hr {
|
||||
border-color : #ecf4ff;
|
||||
max-width : 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
621
css/tt-rss.css
@@ -1,5 +1,5 @@
|
||||
body {
|
||||
background : #f9fbff;
|
||||
background : #f5f5f5;
|
||||
color : black;
|
||||
padding : 0px;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
@@ -15,11 +15,11 @@ form {
|
||||
}
|
||||
|
||||
div.content {
|
||||
overflow : hidden;
|
||||
background : white;
|
||||
border : 1px solid #ccc;
|
||||
border : 1px solid #ddd;
|
||||
padding : 10px;
|
||||
border-radius : 4px;
|
||||
box-shadow : inset 0 0 3px rgba(0,0,0,0.1);
|
||||
box-shadow : 0px 1px 1px -1px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
p.warning {
|
||||
@@ -40,9 +40,7 @@ div.insensitive-small {
|
||||
}
|
||||
|
||||
.floatingLogo {
|
||||
float : right;
|
||||
position : relative;
|
||||
top : -10px;
|
||||
display : none;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -61,7 +59,6 @@ div.notice, div.warning, div.error {
|
||||
font-size : 12px;
|
||||
border-style : solid;
|
||||
border-color : #ccc;
|
||||
border-radius : 4px;
|
||||
border-width : 1px;
|
||||
box-shadow : inset 0px 0px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
@@ -86,7 +83,7 @@ div.error {
|
||||
}
|
||||
|
||||
div.warning img, div.notice img, div.error img {
|
||||
margin-right : 4px;
|
||||
margin : 4px;
|
||||
vertical-align : middle;
|
||||
}
|
||||
|
||||
@@ -120,7 +117,6 @@ div.rss h1 {
|
||||
border-color : gray;
|
||||
border-style : dotted;
|
||||
color : gray;
|
||||
margin-right : 90px;
|
||||
}
|
||||
|
||||
div.rss h2 {
|
||||
@@ -160,7 +156,7 @@ div.rss hr {
|
||||
|
||||
body#sharepopup {
|
||||
background-color : white;
|
||||
background-image : url("images/toolbar.png");
|
||||
background-image : url("../images/toolbar.png");
|
||||
background-repeat : repeat-x;
|
||||
background-position : bottom;
|
||||
margin : 10px;
|
||||
|
||||
105
css/zoom.css
Normal file
@@ -0,0 +1,105 @@
|
||||
body#ttrssZoom {
|
||||
margin-left : auto;
|
||||
margin-right : auto;
|
||||
padding : 20px;
|
||||
max-width : 670px;
|
||||
background : #f5f5f5;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader div.postFeedTitle {
|
||||
float : left;
|
||||
text-align : right;
|
||||
padding-left : 0px;
|
||||
font-size : 11px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader a.postComments {
|
||||
text-align : right;
|
||||
padding-left : 0px;
|
||||
font-size : 11px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader div.postDate {
|
||||
float : none;
|
||||
text-align : right;
|
||||
padding-left : 0px;
|
||||
color : #777;
|
||||
font-size : 11px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader div.postTags {
|
||||
color : #777;
|
||||
font-size : 11px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader div.postTitle {
|
||||
white-space : normal;
|
||||
font-size : 16px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent {
|
||||
font-size : 15px;
|
||||
line-height : 1.5;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent p {
|
||||
max-width : 650px;
|
||||
-webkit-hyphens: auto;
|
||||
-moz-hyphens: auto;
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postHeader {
|
||||
margin : 10px;
|
||||
border-width : 0px 0px 1px 0px;
|
||||
border-style : solid;
|
||||
border-color : #eee;
|
||||
background : white;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postReply {
|
||||
border : 1px solid #ddd;
|
||||
background : white;
|
||||
box-shadow : 0px 1px 1px -1px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
body#ttrssZoom div.footer {
|
||||
margin-top : 1em;
|
||||
text-align : center;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent img {
|
||||
max-width : 630px;
|
||||
height : auto;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent blockquote {
|
||||
margin : 5px 0px 5px 0px;
|
||||
color : #555;
|
||||
padding-left : 10px;
|
||||
border-width : 0px 0px 0px 4px;
|
||||
border-color : #ccc;
|
||||
border-style : solid;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent code {
|
||||
color : #009900;
|
||||
font-family : monospace;
|
||||
font-size : 12px;
|
||||
}
|
||||
|
||||
body#ttrssZoom div.postContent pre {
|
||||
margin : 5px 0px 5px 0px;
|
||||
padding : 10px;
|
||||
color : #555;
|
||||
font-family : monospace;
|
||||
font-size : 12px;
|
||||
border-width : 0px;
|
||||
border-color : #ccc;
|
||||
border-style : solid;
|
||||
background : #f5f5f5;
|
||||
display : block;
|
||||
max-width : 98%;
|
||||
overflow : auto;
|
||||
}
|
||||
|
||||
BIN
images/alert.png
|
Before Width: | Height: | Size: 340 B After Width: | Height: | Size: 701 B |
@@ -1,87 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16px"
|
||||
height="16px"
|
||||
id="svg2985"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
inkscape:export-filename="Y:\public_html\testbox\tt-irc\images\alert.png"
|
||||
inkscape:export-xdpi="102.17"
|
||||
inkscape:export-ydpi="102.17"
|
||||
sodipodi:docname="alert.svg">
|
||||
<defs
|
||||
id="defs2987" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="22.197802"
|
||||
inkscape:cx="0.97227717"
|
||||
inkscape:cy="13.508447"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="1137"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="opacity:1;fill:#d40000;fill-opacity:1"
|
||||
id="path2993"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="4.7752476"
|
||||
sodipodi:cy="2.3499999"
|
||||
sodipodi:r1="8.1370182"
|
||||
sodipodi:r2="4.0685091"
|
||||
sodipodi:arg1="0.52359878"
|
||||
sodipodi:arg2="1.5707963"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 11.822112,6.418509 -7.0468643,0 -7.0468646,0 3.5234322,-6.10276355 3.5234323,-6.10276375 3.5234322,6.10276356 z"
|
||||
inkscape:transform-center-y="-2.0342545"
|
||||
transform="translate(3.2247524,7.6842546)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:11px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Times New Roman;-inkscape-font-specification:Sans Bold"
|
||||
x="6.1657715"
|
||||
y="12.508285"
|
||||
id="text3767"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3769"
|
||||
x="6.1657715"
|
||||
y="12.508285">!</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 213 B After Width: | Height: | Size: 555 B |
@@ -1,76 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16px"
|
||||
height="16px"
|
||||
id="svg2985"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="close_notify.svg">
|
||||
<defs
|
||||
id="defs2987" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#88b0f0"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="22.197802"
|
||||
inkscape:cx="0.97227717"
|
||||
inkscape:cy="8"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1138"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#454545;stroke-width:0.73948608000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path2997"
|
||||
sodipodi:cx="6.6673269"
|
||||
sodipodi:cy="7.1702971"
|
||||
sodipodi:rx="5.270792"
|
||||
sodipodi:ry="5.270792"
|
||||
d="m 11.938119,7.1702971 a 5.270792,5.270792 0 1 1 -10.5415841,0 5.270792,5.270792 0 1 1 10.5415841,0 z"
|
||||
transform="matrix(1.3522905,0,0,1.3522905,-1.0161629,-1.6963247)" />
|
||||
<path
|
||||
style="fill:none;stroke:#454545;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;opacity:1"
|
||||
d="M 4.4322613,4.4322611 11.567739,11.567739"
|
||||
id="path3771"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#454545;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;opacity:1"
|
||||
d="M 11.567739,4.432261 4.432261,11.567739"
|
||||
id="path3771-1"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 186 B After Width: | Height: | Size: 317 B |
BIN
images/cross.png
Normal file
|
After Width: | Height: | Size: 655 B |
BIN
images/error.png
Normal file
|
After Width: | Height: | Size: 666 B |
BIN
images/feed.png
Normal file
|
After Width: | Height: | Size: 691 B |
BIN
images/filter.png
Normal file
|
After Width: | Height: | Size: 586 B |
BIN
images/folder.png
Normal file
|
After Width: | Height: | Size: 537 B |
|
Before Width: | Height: | Size: 415 B |
BIN
images/fresh.png
|
Before Width: | Height: | Size: 251 B After Width: | Height: | Size: 633 B |
BIN
images/information.png
Normal file
|
After Width: | Height: | Size: 778 B |
BIN
images/label.png
|
Before Width: | Height: | Size: 387 B After Width: | Height: | Size: 586 B |
BIN
images/mark_set.png
Normal file
|
After Width: | Height: | Size: 670 B |
@@ -1,73 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16.000000px"
|
||||
height="16.000000px"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.42"
|
||||
sodipodi:docbase="/home/fox/public_html/testbox/tt-rss/images"
|
||||
sodipodi:docname="mark_set.svg"
|
||||
inkscape:export-filename="/home/fox/public_html/testbox/tt-rss/images/mark_set.png"
|
||||
inkscape:export-xdpi="90.000000"
|
||||
inkscape:export-ydpi="90.000000">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0000000"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="31.678384"
|
||||
inkscape:cx="6.9004349"
|
||||
inkscape:cy="7.4155540"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="1131"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="25"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="opacity:1.0000000;fill:#a8cdfd;fill-opacity:1.0000000;stroke:#4f9dfd;stroke-width:0.99999938;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-opacity:1.0000000"
|
||||
id="path1306"
|
||||
sodipodi:sides="5"
|
||||
sodipodi:cx="7.3551731"
|
||||
sodipodi:cy="1.6684607"
|
||||
sodipodi:r1="6.3745561"
|
||||
sodipodi:r2="3.1872780"
|
||||
sodipodi:arg1="0.78539816"
|
||||
sodipodi:arg2="1.4137167"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0.0000000"
|
||||
inkscape:randomized="0.0000000"
|
||||
d="M 11.862665,6.1759525 L 7.8537732,4.8164981 L 4.4611852,7.3482318 L 4.5152876,3.1154547 L 1.0590984,0.67126048 L 5.1014272,-0.58528520 L 6.3579728,-4.6276140 L 8.8021671,-1.1714248 L 13.034944,-1.2255272 L 10.503210,2.1670609 L 11.862665,6.1759525 z "
|
||||
transform="matrix(-0.707107,-0.707107,0.707107,-0.707107,12.02111,14.98939)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB |
BIN
images/mark_unset.png
Normal file
|
After Width: | Height: | Size: 623 B |
@@ -1,76 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16.000000px"
|
||||
height="16.000000px"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.48.0 r9654"
|
||||
sodipodi:docname="mark_unset.svg"
|
||||
inkscape:export-filename="/home/fox/public_html/testbox/tt-rss/images/mark_unset.png"
|
||||
inkscape:export-xdpi="90.000000"
|
||||
inkscape:export-ydpi="90.000000"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0000000"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="7.919596"
|
||||
inkscape:cx="-13.509597"
|
||||
inkscape:cy="-5.9527534"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="1131"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="25"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
showgrid="false"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#88b0f0;stroke-width:0.99999938000000022;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path1306"
|
||||
sodipodi:sides="5"
|
||||
sodipodi:cx="7.3551731"
|
||||
sodipodi:cy="1.6684607"
|
||||
sodipodi:r1="6.3745561"
|
||||
sodipodi:r2="3.1872780"
|
||||
sodipodi:arg1="0.78539816"
|
||||
sodipodi:arg2="1.4137167"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0.0000000"
|
||||
inkscape:randomized="0.0000000"
|
||||
d="M 11.862665,6.1759525 L 7.8537732,4.8164981 L 4.4611852,7.3482318 L 4.5152876,3.1154547 L 1.0590984,0.67126048 L 5.1014272,-0.58528520 L 6.3579728,-4.6276140 L 8.8021671,-1.1714248 L 13.034944,-1.2255272 L 10.503210,2.1670609 L 11.862665,6.1759525 z "
|
||||
transform="matrix(-0.707107,-0.707107,0.707107,-0.707107,12.02111,14.98939)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 141 B After Width: | Height: | Size: 372 B |
BIN
images/page_white_go.png
Normal file
|
After Width: | Height: | Size: 612 B |
BIN
images/plugin.png
Normal file
|
After Width: | Height: | Size: 591 B |
BIN
images/plugin_disabled.png
Normal file
|
After Width: | Height: | Size: 347 B |
BIN
images/pub_set.png
Normal file
|
After Width: | Height: | Size: 691 B |
@@ -1,184 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="16"
|
||||
height="16"
|
||||
id="RSSicon"
|
||||
viewBox="0 0 32 32"
|
||||
inkscape:version="0.48.0 r9654"
|
||||
sodipodi:docname="mark_set.svg">
|
||||
<metadata
|
||||
id="metadata34">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="1137"
|
||||
id="namedview32"
|
||||
showgrid="false"
|
||||
inkscape:zoom="23.953242"
|
||||
inkscape:cx="6.5252922"
|
||||
inkscape:cy="10.694533"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="RSSicon" />
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
x1="30.059999"
|
||||
y1="30.059999"
|
||||
x2="225.94"
|
||||
y2="225.94"
|
||||
id="RSSg"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(0,-224)">
|
||||
<stop
|
||||
offset="0.0"
|
||||
stop-color="#E3702D"
|
||||
id="stop6" />
|
||||
<stop
|
||||
offset="0.1071"
|
||||
stop-color="#EA7D31"
|
||||
id="stop8" />
|
||||
<stop
|
||||
offset="0.3503"
|
||||
stop-color="#F69537"
|
||||
id="stop10" />
|
||||
<stop
|
||||
offset="0.5"
|
||||
stop-color="#FB9E3A"
|
||||
id="stop12" />
|
||||
<stop
|
||||
offset="0.7016"
|
||||
stop-color="#EA7C31"
|
||||
id="stop14" />
|
||||
<stop
|
||||
offset="0.8866"
|
||||
stop-color="#DE642B"
|
||||
id="stop16" />
|
||||
<stop
|
||||
offset="1.0"
|
||||
stop-color="#D95B29"
|
||||
id="stop18" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#RSSg"
|
||||
id="linearGradient3029"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(0,-224)"
|
||||
x1="30.059999"
|
||||
y1="30.059999"
|
||||
x2="225.94"
|
||||
y2="225.94" />
|
||||
<filter
|
||||
id="filter3031"
|
||||
inkscape:label="Desaturate"
|
||||
x="0"
|
||||
y="0"
|
||||
width="1"
|
||||
height="1"
|
||||
inkscape:menu="Color"
|
||||
inkscape:menu-tooltip="Render in shades of gray by reducing saturation to zero"
|
||||
color-interpolation-filters="sRGB">
|
||||
<feColorMatrix
|
||||
id="feColorMatrix3033"
|
||||
type="saturate"
|
||||
values="0" />
|
||||
</filter>
|
||||
<filter
|
||||
id="filter3035"
|
||||
inkscape:label="Desaturate"
|
||||
x="0"
|
||||
y="0"
|
||||
width="1"
|
||||
height="1"
|
||||
inkscape:menu="Color"
|
||||
inkscape:menu-tooltip="Render in shades of gray by reducing saturation to zero"
|
||||
color-interpolation-filters="sRGB">
|
||||
<feColorMatrix
|
||||
id="feColorMatrix3037"
|
||||
type="saturate"
|
||||
values="0" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
id="g3021"
|
||||
transform="matrix(0.10305878,0,0,0.10305878,2.808475,25.893644)"
|
||||
style="opacity:1">
|
||||
<rect
|
||||
style="fill:#cc5d15;"
|
||||
id="rect20"
|
||||
y="-224"
|
||||
x="0"
|
||||
ry="55"
|
||||
rx="55"
|
||||
height="256"
|
||||
width="256" />
|
||||
<rect
|
||||
style="fill:#f49c52;"
|
||||
id="rect22"
|
||||
y="-219"
|
||||
x="5"
|
||||
ry="50"
|
||||
rx="50"
|
||||
height="246"
|
||||
width="246" />
|
||||
<rect
|
||||
style="fill:url(#linearGradient3029);"
|
||||
id="rect24"
|
||||
y="-214"
|
||||
x="10"
|
||||
ry="47"
|
||||
rx="47"
|
||||
height="236"
|
||||
width="236" />
|
||||
<circle
|
||||
transform="translate(0,-224)"
|
||||
style="fill:#ffffff;"
|
||||
sodipodi:ry="24"
|
||||
sodipodi:rx="24"
|
||||
sodipodi:cy="189"
|
||||
sodipodi:cx="68"
|
||||
id="circle26"
|
||||
r="24"
|
||||
cy="189"
|
||||
cx="68"
|
||||
d="m 92,189 c 0,13.25483 -10.745166,24 -24,24 -13.254834,0 -24,-10.74517 -24,-24 0,-13.25483 10.745166,-24 24,-24 13.254834,0 24,10.74517 24,24 z" />
|
||||
<path
|
||||
style="fill:#ffffff;"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path28"
|
||||
d="M 160,-11 H 126 A 82,82 0 0 0 44,-93 v -34 a 116,116 0 0 1 116,116 z" />
|
||||
<path
|
||||
style="fill:#ffffff;"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path30"
|
||||
d="M 184,-11 A 140,140 0 0 0 44,-151 v -35 a 175,175 0 0 1 175,175 z" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.7 KiB |
BIN
images/pub_unset.png
Normal file
|
After Width: | Height: | Size: 717 B |
@@ -1,149 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="16"
|
||||
height="16"
|
||||
id="RSSicon"
|
||||
viewBox="0 0 32 32"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="pub_unset.svg">
|
||||
<metadata
|
||||
id="metadata34">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="1137"
|
||||
id="namedview32"
|
||||
showgrid="false"
|
||||
inkscape:zoom="23.953242"
|
||||
inkscape:cx="6.0451902"
|
||||
inkscape:cy="5.8935127"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="RSSicon" />
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
x1="30.059999"
|
||||
y1="30.059999"
|
||||
x2="225.94"
|
||||
y2="225.94"
|
||||
id="RSSg"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(0,-224)">
|
||||
<stop
|
||||
offset="0.0"
|
||||
stop-color="#E3702D"
|
||||
id="stop6" />
|
||||
<stop
|
||||
offset="0.1071"
|
||||
stop-color="#EA7D31"
|
||||
id="stop8" />
|
||||
<stop
|
||||
offset="0.3503"
|
||||
stop-color="#F69537"
|
||||
id="stop10" />
|
||||
<stop
|
||||
offset="0.5"
|
||||
stop-color="#FB9E3A"
|
||||
id="stop12" />
|
||||
<stop
|
||||
offset="0.7016"
|
||||
stop-color="#EA7C31"
|
||||
id="stop14" />
|
||||
<stop
|
||||
offset="0.8866"
|
||||
stop-color="#DE642B"
|
||||
id="stop16" />
|
||||
<stop
|
||||
offset="1.0"
|
||||
stop-color="#D95B29"
|
||||
id="stop18" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#RSSg"
|
||||
id="linearGradient3029"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(0,-224)"
|
||||
x1="30.059999"
|
||||
y1="30.059999"
|
||||
x2="225.94"
|
||||
y2="225.94" />
|
||||
</defs>
|
||||
<rect
|
||||
width="27.385"
|
||||
height="27.385"
|
||||
rx="5.8834963"
|
||||
ry="5.8834963"
|
||||
x="2.3074989"
|
||||
y="2.3075001"
|
||||
id="rect20"
|
||||
style="fill:#909090;fill-opacity:1" />
|
||||
<rect
|
||||
width="26.315275"
|
||||
height="26.315275"
|
||||
rx="5.3486328"
|
||||
ry="5.3486328"
|
||||
x="2.8423624"
|
||||
y="2.8423634"
|
||||
id="rect22"
|
||||
style="fill:#a0a0a0;fill-opacity:0.94117647" />
|
||||
<rect
|
||||
width="25.245548"
|
||||
height="25.245548"
|
||||
rx="5.0277152"
|
||||
ry="5.0277152"
|
||||
x="3.3772256"
|
||||
y="3.3772268"
|
||||
id="rect24"
|
||||
style="fill:#c0c0c0;fill-opacity:1" />
|
||||
<circle
|
||||
d="m 92,189 c 0,13.25483 -10.745166,24 -24,24 -13.254834,0 -24,-10.74517 -24,-24 0,-13.25483 10.745166,-24 24,-24 13.254834,0 24,10.74517 24,24 z"
|
||||
cx="68"
|
||||
cy="189"
|
||||
r="24"
|
||||
id="circle26"
|
||||
sodipodi:cx="68"
|
||||
sodipodi:cy="189"
|
||||
sodipodi:rx="24"
|
||||
sodipodi:ry="24"
|
||||
style="fill:#ffffff"
|
||||
transform="matrix(0.10697266,0,0,0.10697266,2.307499,2.3075002)" />
|
||||
<path
|
||||
d="M 19.423125,25.092677 H 15.786054 A 8.7717581,8.7717581 0 0 0 7.014296,16.320919 v -3.637071 a 12.408829,12.408829 0 0 1 12.408829,12.408829 z"
|
||||
id="path28"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" />
|
||||
<path
|
||||
d="M 21.990468,25.092677 A 14.976172,14.976172 0 0 0 7.014296,10.116504 V 6.3724612 A 18.720216,18.720216 0 0 1 25.734512,25.092677 z"
|
||||
id="path30"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 205 B After Width: | Height: | Size: 332 B |
|
Before Width: | Height: | Size: 181 B After Width: | Height: | Size: 295 B |
|
Before Width: | Height: | Size: 190 B After Width: | Height: | Size: 295 B |
|
Before Width: | Height: | Size: 168 B After Width: | Height: | Size: 211 B |
|
Before Width: | Height: | Size: 172 B After Width: | Height: | Size: 201 B |
@@ -1,80 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="32px"
|
||||
height="32px"
|
||||
id="svg7311"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.0 r9654"
|
||||
sodipodi:docname="sign_excl.svg">
|
||||
<defs
|
||||
id="defs7313" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.197802"
|
||||
inkscape:cx="-11.862611"
|
||||
inkscape:cy="16"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="1137"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7316">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#eb6363;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path6540-7"
|
||||
sodipodi:cx="3.409934"
|
||||
sodipodi:cy="4.3416462"
|
||||
sodipodi:rx="14.271205"
|
||||
sodipodi:ry="14.271205"
|
||||
d="m 17.681139,4.3416462 a 14.271205,14.271205 0 1 1 -28.54241,0 14.271205,14.271205 0 1 1 28.54241,0 z"
|
||||
transform="translate(12.590066,11.658354)"
|
||||
inkscape:export-xdpi="73.07"
|
||||
inkscape:export-ydpi="73.07" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Times New Roman;-inkscape-font-specification:Times New Roman"
|
||||
x="11.482422"
|
||||
y="24.308594"
|
||||
id="text6542-9"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6544-5"
|
||||
x="11.482422"
|
||||
y="24.308594"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#ffffff;fill-opacity:1;font-family:Georgia;-inkscape-font-specification:Georgia Bold">!</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.8 KiB |
@@ -1,83 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="32px"
|
||||
height="32px"
|
||||
id="svg2985"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.0 r9654"
|
||||
sodipodi:docname="sign_info.svg"
|
||||
inkscape:export-filename="Y:\public_html\testbox\tt-rss\images\sign_info.png"
|
||||
inkscape:export-xdpi="67.5"
|
||||
inkscape:export-ydpi="67.5">
|
||||
<defs
|
||||
id="defs2987" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.7994505"
|
||||
inkscape:cx="6.8311272"
|
||||
inkscape:cy="-22.339561"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="1137"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#88b0f0;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path6540"
|
||||
sodipodi:cx="3.409934"
|
||||
sodipodi:cy="4.3416462"
|
||||
sodipodi:rx="14.271205"
|
||||
sodipodi:ry="14.271205"
|
||||
d="m 17.681139,4.3416462 a 14.271205,14.271205 0 1 1 -28.54241,0 14.271205,14.271205 0 1 1 28.54241,0 z"
|
||||
transform="translate(12.590066,11.658354)"
|
||||
inkscape:export-xdpi="73.07"
|
||||
inkscape:export-ydpi="73.07" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Times New Roman;-inkscape-font-specification:Times New Roman"
|
||||
x="11.763672"
|
||||
y="25.070313"
|
||||
id="text6542"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6544"
|
||||
x="11.763672"
|
||||
y="25.070313"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#ffffff;fill-opacity:1;font-family:Georgia;-inkscape-font-specification:Georgia Bold">i</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.0 KiB |
BIN
images/star.png
Normal file
|
After Width: | Height: | Size: 670 B |
BIN
images/tag.png
|
Before Width: | Height: | Size: 372 B After Width: | Height: | Size: 594 B |
BIN
images/tick.png
Normal file
|
After Width: | Height: | Size: 537 B |
BIN
images/time.png
Normal file
|
After Width: | Height: | Size: 793 B |
BIN
images/treeExpandImages.png
Normal file
|
After Width: | Height: | Size: 288 B |
BIN
images/untick.png
Normal file
|
After Width: | Height: | Size: 518 B |
BIN
images/user.png
Normal file
|
After Width: | Height: | Size: 741 B |
@@ -92,7 +92,7 @@
|
||||
}
|
||||
|
||||
function ccache_update($feed_id, $owner_uid, $is_cat = false,
|
||||
$update_pcat = true) {
|
||||
$update_pcat = true, $pcat_fast = false) {
|
||||
|
||||
if (!is_numeric($feed_id)) return;
|
||||
|
||||
@@ -127,11 +127,13 @@
|
||||
|
||||
/* Recalculate counters for child feeds */
|
||||
|
||||
$result = db_query("SELECT id FROM ttrss_feeds
|
||||
if (!$pcat_fast) {
|
||||
$result = db_query("SELECT id FROM ttrss_feeds
|
||||
WHERE owner_uid = '$owner_uid' AND $cat_qpart");
|
||||
|
||||
while ($line = db_fetch_assoc($result)) {
|
||||
ccache_update($line["id"], $owner_uid, false, false);
|
||||
while ($line = db_fetch_assoc($result)) {
|
||||
ccache_update($line["id"], $owner_uid, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
$result = db_query("SELECT SUM(value) AS sv
|
||||
@@ -177,7 +179,7 @@
|
||||
|
||||
$cat_id = (int) db_fetch_result($result, 0, "cat_id");
|
||||
|
||||
ccache_update($cat_id, $owner_uid, true);
|
||||
ccache_update($cat_id, $owner_uid, true, true, true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,17 +288,24 @@ function hsl2rgb($arr) {
|
||||
|
||||
$size = @getimagesize($imageFile);
|
||||
|
||||
if (strtolower($size['mime']) == 'image/vnd.microsoft.icon' && class_exists("floIcon")) {
|
||||
// to enable .ico support place floIcon.php into lib/
|
||||
if (strtolower($size['mime']) == 'image/vnd.microsoft.icon') {
|
||||
|
||||
$ico = new floIcon();
|
||||
@$ico->readICO($imageFile);
|
||||
if (class_exists("floIcon")) {
|
||||
|
||||
if(count($ico->images)==0)
|
||||
return null;
|
||||
else
|
||||
$img = @$ico->images[count($ico->images)-1]->getImageResource();
|
||||
$ico = new floIcon();
|
||||
@$ico->readICO($imageFile);
|
||||
|
||||
} else {
|
||||
if(count($ico->images)==0)
|
||||
return false;
|
||||
else
|
||||
$img = @$ico->images[count($ico->images)-1]->getImageResource();
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if ($size[0] > 0 && $size[1] > 0) {
|
||||
$img = @imagecreatefromstring(file_get_contents($imageFile));
|
||||
}
|
||||
|
||||
|
||||
@@ -127,8 +127,6 @@
|
||||
ORDER BY ttrss_feed_categories.title, ttrss_feeds.title, score DESC, date_updated DESC
|
||||
LIMIT $limit");
|
||||
|
||||
$cur_feed_title = "";
|
||||
|
||||
$headlines_count = db_num_rows($result);
|
||||
|
||||
$headlines = array();
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
htmlspecialchars($line["title"])."</span></a>";
|
||||
|
||||
$feed_url = "<a target=\"_blank\" class=\"fb_feedUrl\"
|
||||
href=\"$feed_url\"><img src='images/pub_set.svg'
|
||||
href=\"$feed_url\"><img src='images/pub_set.png'
|
||||
style='vertical-align : middle'></a>";
|
||||
|
||||
$rv .= "<li>$check_box $feed_url $site_url".
|
||||
@@ -72,7 +72,6 @@
|
||||
} else if ($mode == 2) {
|
||||
$feed_url = htmlspecialchars($line["feed_url"]);
|
||||
$site_url = htmlspecialchars($line["site_url"]);
|
||||
$title = htmlspecialchars($line["title"]);
|
||||
|
||||
$check_box = "<input onclick='toggleSelectListRow2(this)' dojoType=\"dijit.form.CheckBox\"
|
||||
type=\"checkbox\">";
|
||||
@@ -80,7 +79,7 @@
|
||||
$class = ($feedctr % 2) ? "even" : "odd";
|
||||
|
||||
if ($line['articles_archived'] > 0) {
|
||||
$archived = sprintf(ngettext("%d archived article", "%d archived articles", $line['articles_archived']), $line['articles_archived']);
|
||||
$archived = sprintf(_ngettext("%d archived article", "%d archived articles", $line['articles_archived']), $line['articles_archived']);
|
||||
$archived = " <span class='subscribers'>($archived)</span>";
|
||||
} else {
|
||||
$archived = '';
|
||||
@@ -92,7 +91,7 @@
|
||||
htmlspecialchars($line["title"])."</span></a>";
|
||||
|
||||
$feed_url = "<a target=\"_blank\" class=\"fb_feedUrl\"
|
||||
href=\"$feed_url\"><img src='images/pub_set.svg'
|
||||
href=\"$feed_url\"><img src='images/pub_set.png'
|
||||
style='vertical-align : middle'></a>";
|
||||
|
||||
|
||||
|
||||
2403
include/functions2.php
Normal file
@@ -42,7 +42,8 @@
|
||||
ORDER BY caption");
|
||||
|
||||
while ($line = db_fetch_assoc($result)) {
|
||||
$rk = array($line["label_id"], $line["caption"], $line["fg_color"],
|
||||
$rk = array(label_to_feed_id($line["label_id"]),
|
||||
$line["caption"], $line["fg_color"],
|
||||
$line["bg_color"]);
|
||||
array_push($rv, $rk);
|
||||
}
|
||||
@@ -108,7 +109,7 @@
|
||||
|
||||
if (!$label_id) return;
|
||||
|
||||
$result = db_query(
|
||||
db_query(
|
||||
"DELETE FROM ttrss_user_labels2
|
||||
WHERE
|
||||
label_id = '$label_id' AND
|
||||
|
||||
@@ -2,15 +2,22 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Tiny Tiny RSS : Login</title>
|
||||
<link rel="stylesheet" type="text/css" href="lib/dijit/themes/claro/claro.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="css/tt-rss.css">
|
||||
<?php echo stylesheet_tag("lib/dijit/themes/claro/claro.css") ?>
|
||||
<?php echo stylesheet_tag("css/tt-rss.css") ?>
|
||||
<?php echo stylesheet_tag("css/dijit.css") ?>
|
||||
<link rel="shortcut icon" type="image/png" href="images/favicon.png">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script type="text/javascript" src="lib/dojo/dojo.js"></script>
|
||||
<script type="text/javascript" src="lib/dojo/tt-rss-layer.js"></script>
|
||||
<script type="text/javascript" src="lib/prototype.js"></script>
|
||||
<script type="text/javascript" src="js/functions.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="errors.php?mode=js"></script>
|
||||
<?php
|
||||
foreach (array("lib/prototype.js",
|
||||
"lib/dojo/dojo.js",
|
||||
"lib/dojo/tt-rss-layer.js",
|
||||
"js/functions.js",
|
||||
"errors.php?mode=js") as $jsfile) {
|
||||
|
||||
echo javascript_tag($jsfile);
|
||||
|
||||
} ?>
|
||||
|
||||
<script type="text/javascript">
|
||||
require({cache:{}});
|
||||
Event.observe(window, 'load', function() {
|
||||
@@ -246,9 +253,6 @@ function bwLimitChange(elem) {
|
||||
|
||||
<div class='footer'>
|
||||
<a href="http://tt-rss.org/">Tiny Tiny RSS</a>
|
||||
<?php if (!defined('HIDE_VERSION')) { ?>
|
||||
v<?php echo VERSION ?>
|
||||
<?php } ?>
|
||||
© 2005–<?php echo date('Y') ?> <a href="http://fakecake.org/">Andrew Dolgov</a>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,6 +2,19 @@
|
||||
define_default('DAEMON_UPDATE_LOGIN_LIMIT', 30);
|
||||
define_default('DAEMON_FEED_LIMIT', 500);
|
||||
define_default('DAEMON_SLEEP_INTERVAL', 120);
|
||||
define_default('_MIN_CACHE_IMAGE_SIZE', 1024);
|
||||
|
||||
function calculate_article_hash($article, $pluginhost) {
|
||||
$tmp = "";
|
||||
|
||||
foreach ($article as $k => $v) {
|
||||
if ($k != "feed" && isset($v)) {
|
||||
$tmp .= sha1("$k:" . (is_array($v) ? implode(",", $v) : $v));
|
||||
}
|
||||
}
|
||||
|
||||
return sha1(implode(",", $pluginhost->get_plugin_names()) . $tmp);
|
||||
}
|
||||
|
||||
function update_feedbrowser_cache() {
|
||||
|
||||
@@ -79,7 +92,7 @@
|
||||
$login_thresh_qpart = "";
|
||||
}
|
||||
|
||||
// Test if the feed need a update (update interval exceded).
|
||||
// Test if the feed need a update (update interval exceeded).
|
||||
if (DB_TYPE == "pgsql") {
|
||||
$update_limit_qpart = "AND ((
|
||||
ttrss_feeds.update_interval = 0
|
||||
@@ -88,8 +101,10 @@
|
||||
) OR (
|
||||
ttrss_feeds.update_interval > 0
|
||||
AND ttrss_feeds.last_updated < NOW() - CAST((ttrss_feeds.update_interval || ' minutes') AS INTERVAL)
|
||||
) OR ttrss_feeds.last_updated IS NULL
|
||||
OR last_updated = '1970-01-01 00:00:00')";
|
||||
) OR (ttrss_feeds.last_updated IS NULL
|
||||
AND ttrss_user_prefs.value != '-1')
|
||||
OR (last_updated = '1970-01-01 00:00:00'
|
||||
AND ttrss_user_prefs.value != '-1'))";
|
||||
} else {
|
||||
$update_limit_qpart = "AND ((
|
||||
ttrss_feeds.update_interval = 0
|
||||
@@ -98,8 +113,10 @@
|
||||
) OR (
|
||||
ttrss_feeds.update_interval > 0
|
||||
AND ttrss_feeds.last_updated < DATE_SUB(NOW(), INTERVAL ttrss_feeds.update_interval MINUTE)
|
||||
) OR ttrss_feeds.last_updated IS NULL
|
||||
OR last_updated = '1970-01-01 00:00:00')";
|
||||
) OR (ttrss_feeds.last_updated IS NULL
|
||||
AND ttrss_user_prefs.value != '-1')
|
||||
OR (last_updated = '1970-01-01 00:00:00'
|
||||
AND ttrss_user_prefs.value != '-1'))";
|
||||
}
|
||||
|
||||
// Test if feed is currently being updated by another process.
|
||||
@@ -118,6 +135,7 @@
|
||||
ttrss_feeds, ttrss_users, ttrss_user_prefs
|
||||
WHERE
|
||||
ttrss_feeds.owner_uid = ttrss_users.id
|
||||
AND ttrss_user_prefs.profile IS NULL
|
||||
AND ttrss_users.id = ttrss_user_prefs.owner_uid
|
||||
AND ttrss_user_prefs.pref_name = 'DEFAULT_UPDATE_INTERVAL'
|
||||
$login_thresh_qpart $update_limit_qpart
|
||||
@@ -151,6 +169,7 @@
|
||||
}
|
||||
|
||||
$nf = 0;
|
||||
$bstarted = microtime(true);
|
||||
|
||||
// For each feed, we call the feed update function.
|
||||
foreach ($feeds_to_update as $feed) {
|
||||
@@ -165,6 +184,7 @@
|
||||
ttrss_user_prefs.owner_uid = ttrss_feeds.owner_uid AND
|
||||
ttrss_users.id = ttrss_user_prefs.owner_uid AND
|
||||
ttrss_user_prefs.pref_name = 'DEFAULT_UPDATE_INTERVAL' AND
|
||||
ttrss_user_prefs.profile IS NULL AND
|
||||
feed_url = '".db_escape_string($feed)."' AND
|
||||
(ttrss_feeds.update_interval > 0 OR
|
||||
ttrss_user_prefs.value != '-1')
|
||||
@@ -172,14 +192,27 @@
|
||||
ORDER BY ttrss_feeds.id $query_limit");
|
||||
|
||||
if (db_num_rows($tmp_result) > 0) {
|
||||
$rss = false;
|
||||
|
||||
while ($tline = db_fetch_assoc($tmp_result)) {
|
||||
if($debug) _debug(" => " . $tline["last_updated"] . ", " . $tline["id"] . " " . $tline["owner_uid"]);
|
||||
update_rss_feed($tline["id"], true);
|
||||
|
||||
$fstarted = microtime(true);
|
||||
$rss = update_rss_feed($tline["id"], true, false);
|
||||
_debug_suppress(false);
|
||||
|
||||
_debug(sprintf(" %.4f (sec)", microtime(true) - $fstarted));
|
||||
|
||||
++$nf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($nf > 0) {
|
||||
_debug(sprintf("Processed %d feeds in %.4f (sec), %.4f (sec/feed avg)", $nf,
|
||||
microtime(true) - $bstarted, (microtime(true) - $bstarted) / $nf));
|
||||
}
|
||||
|
||||
require_once "digest.php";
|
||||
|
||||
// Send feed digests by email if needed.
|
||||
@@ -190,14 +223,15 @@
|
||||
} // function update_daemon_common
|
||||
|
||||
// ignore_daemon is not used
|
||||
function update_rss_feed($feed, $ignore_daemon = false, $no_cache = false) {
|
||||
function update_rss_feed($feed, $ignore_daemon = false, $no_cache = false, $rss = false) {
|
||||
|
||||
$debug_enabled = defined('DAEMON_EXTENDED_DEBUG') || $_REQUEST['xdebug'];
|
||||
|
||||
_debug_suppress(!$debug_enabled);
|
||||
_debug("start", $debug_enabled);
|
||||
|
||||
$result = db_query("SELECT id,update_interval,auth_login,
|
||||
feed_url,auth_pass,cache_images,last_updated,
|
||||
feed_url,auth_pass,cache_images,
|
||||
mark_unread_on_update, owner_uid,
|
||||
pubsub_state, auth_pass_encrypted,
|
||||
(SELECT max(date_entered) FROM
|
||||
@@ -209,7 +243,6 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
$last_updated = db_fetch_result($result, 0, "last_updated");
|
||||
$last_article_timestamp = @strtotime(db_fetch_result($result, 0, "last_article_timestamp"));
|
||||
|
||||
if (defined('_DISABLE_HTTP_304'))
|
||||
@@ -250,34 +283,37 @@
|
||||
$pluginhost->load($user_plugins, PluginHost::KIND_USER, $owner_uid);
|
||||
$pluginhost->load_data();
|
||||
|
||||
$rss = false;
|
||||
$rss_hash = false;
|
||||
|
||||
$force_refetch = isset($_REQUEST["force_refetch"]);
|
||||
|
||||
if (file_exists($cache_filename) &&
|
||||
is_readable($cache_filename) &&
|
||||
!$auth_login && !$auth_pass &&
|
||||
filemtime($cache_filename) > time() - 30) {
|
||||
|
||||
_debug("using local cache.", $debug_enabled);
|
||||
|
||||
@$feed_data = file_get_contents($cache_filename);
|
||||
|
||||
if ($feed_data) {
|
||||
$rss_hash = sha1($feed_data);
|
||||
}
|
||||
|
||||
if ($rss && is_object($rss) && get_class($rss) == "FeedParser") {
|
||||
_debug("using previously initialized parser object");
|
||||
} else {
|
||||
_debug("local cache will not be used for this feed", $debug_enabled);
|
||||
}
|
||||
$rss_hash = false;
|
||||
|
||||
if (!$rss) {
|
||||
$force_refetch = isset($_REQUEST["force_refetch"]);
|
||||
|
||||
foreach ($pluginhost->get_hooks(PluginHost::HOOK_FETCH_FEED) as $plugin) {
|
||||
$feed_data = $plugin->hook_fetch_feed($feed_data, $fetch_url, $owner_uid, $feed);
|
||||
$feed_data = $plugin->hook_fetch_feed($feed_data, $fetch_url, $owner_uid, $feed, $last_article_timestamp, $auth_login, $auth_pass);
|
||||
}
|
||||
|
||||
// try cache
|
||||
if (!$feed_data &&
|
||||
file_exists($cache_filename) &&
|
||||
is_readable($cache_filename) &&
|
||||
!$auth_login && !$auth_pass &&
|
||||
filemtime($cache_filename) > time() - 30) {
|
||||
|
||||
_debug("using local cache [$cache_filename].", $debug_enabled);
|
||||
|
||||
@$feed_data = file_get_contents($cache_filename);
|
||||
|
||||
if ($feed_data) {
|
||||
$rss_hash = sha1($feed_data);
|
||||
}
|
||||
|
||||
} else {
|
||||
_debug("local cache will not be used for this feed", $debug_enabled);
|
||||
}
|
||||
|
||||
// fetch feed from source
|
||||
if (!$feed_data) {
|
||||
_debug("fetching [$fetch_url]...", $debug_enabled);
|
||||
_debug("If-Modified-Since: ".gmdate('D, d M Y H:i:s \G\M\T', $last_article_timestamp), $debug_enabled);
|
||||
@@ -316,6 +352,16 @@
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
// cache vanilla feed data for re-use
|
||||
if ($feed_data && !$auth_pass && !$auth_login && is_writable(CACHE_DIR . "/simplepie")) {
|
||||
$new_rss_hash = sha1($feed_data);
|
||||
|
||||
if ($new_rss_hash != $rss_hash) {
|
||||
_debug("saving $cache_filename", $debug_enabled);
|
||||
@file_put_contents($cache_filename, $feed_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$feed_data) {
|
||||
@@ -354,22 +400,19 @@
|
||||
$rss->init();
|
||||
}
|
||||
|
||||
if (DETECT_ARTICLE_LANGUAGE) {
|
||||
require_once "lib/languagedetect/LanguageDetect.php";
|
||||
|
||||
$lang = new Text_LanguageDetect();
|
||||
$lang->setNameMode(2);
|
||||
}
|
||||
|
||||
// print_r($rss);
|
||||
|
||||
$feed = db_escape_string($feed);
|
||||
|
||||
if (!$rss->error()) {
|
||||
|
||||
// cache data for later
|
||||
if (!$auth_pass && !$auth_login && is_writable(CACHE_DIR . "/simplepie")) {
|
||||
$new_rss_hash = sha1($rss_data);
|
||||
|
||||
if ($new_rss_hash != $rss_hash && count($rss->get_items()) > 0 ) {
|
||||
_debug("saving $cache_filename", $debug_enabled);
|
||||
@file_put_contents($cache_filename, $feed_data);
|
||||
}
|
||||
}
|
||||
|
||||
// We use local pluginhost here because we need to load different per-user feed plugins
|
||||
$pluginhost->run_hooks(PluginHost::HOOK_FEED_PARSED, "hook_feed_parsed", $rss);
|
||||
|
||||
@@ -438,7 +481,7 @@
|
||||
|
||||
if (!$registered_title || $registered_title == "[Unknown]") {
|
||||
|
||||
$feed_title = db_escape_string($rss->get_title());
|
||||
$feed_title = db_escape_string(mb_substr($rss->get_title(), 0, 199));
|
||||
|
||||
if ($feed_title) {
|
||||
_debug("registering title: $feed_title", $debug_enabled);
|
||||
@@ -488,7 +531,20 @@
|
||||
|
||||
_debug("feed hub url: $feed_hub_url", $debug_enabled);
|
||||
|
||||
if ($feed_hub_url && function_exists('curl_init') &&
|
||||
$feed_self_url = $fetch_url;
|
||||
|
||||
$links = $rss->get_links('self');
|
||||
|
||||
if ($links && is_array($links)) {
|
||||
foreach ($links as $l) {
|
||||
$feed_self_url = $l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_debug("feed self url = $feed_self_url");
|
||||
|
||||
if ($feed_hub_url && $feed_self_url && function_exists('curl_init') &&
|
||||
!ini_get("open_basedir")) {
|
||||
|
||||
require_once 'lib/pubsubhubbub/subscriber.php';
|
||||
@@ -498,9 +554,9 @@
|
||||
|
||||
$s = new Subscriber($feed_hub_url, $callback_url);
|
||||
|
||||
$rc = $s->subscribe($fetch_url);
|
||||
$rc = $s->subscribe($feed_self_url);
|
||||
|
||||
_debug("feed hub url found, subscribe request sent.", $debug_enabled);
|
||||
_debug("feed hub url found, subscribe request sent. [rc=$rc]", $debug_enabled);
|
||||
|
||||
db_query("UPDATE ttrss_feeds SET pubsub_state = 1
|
||||
WHERE id = '$feed'");
|
||||
@@ -517,9 +573,6 @@
|
||||
$entry_guid = $item->get_id();
|
||||
if (!$entry_guid) $entry_guid = $item->get_link();
|
||||
if (!$entry_guid) $entry_guid = make_guid_from_title($item->get_title());
|
||||
|
||||
_debug("f_guid $entry_guid", $debug_enabled);
|
||||
|
||||
if (!$entry_guid) continue;
|
||||
|
||||
$entry_guid = "$owner_uid,$entry_guid";
|
||||
@@ -536,9 +589,6 @@
|
||||
|
||||
if ($entry_timestamp == -1 || !$entry_timestamp || $entry_timestamp > time()) {
|
||||
$entry_timestamp = time();
|
||||
$no_orig_date = 'true';
|
||||
} else {
|
||||
$no_orig_date = 'false';
|
||||
}
|
||||
|
||||
$entry_timestamp_fmt = strftime("%Y/%m/%d %H:%M:%S", $entry_timestamp);
|
||||
@@ -565,6 +615,21 @@
|
||||
print "\n";
|
||||
}
|
||||
|
||||
$entry_language = "";
|
||||
|
||||
if (DETECT_ARTICLE_LANGUAGE) {
|
||||
$entry_language = $lang->detect($entry_title . " " . $entry_content, 1);
|
||||
|
||||
if (count($entry_language) > 0) {
|
||||
$possible = array_keys($entry_language);
|
||||
$entry_language = $possible[0];
|
||||
|
||||
_debug("detected language: $entry_language", $debug_enabled);
|
||||
} else {
|
||||
$entry_language = "";
|
||||
}
|
||||
}
|
||||
|
||||
$entry_comments = $item->get_comments_url();
|
||||
$entry_author = $item->get_author();
|
||||
|
||||
@@ -600,24 +665,15 @@
|
||||
|
||||
_debug("done collecting data.", $debug_enabled);
|
||||
|
||||
// TODO: less memory-hungry implementation
|
||||
|
||||
_debug("applying plugin filters..", $debug_enabled);
|
||||
|
||||
// FIXME not sure if owner_uid is a good idea here, we may have a base entry without user entry (?)
|
||||
$result = db_query("SELECT plugin_data,title,content,link,tag_cache,author FROM ttrss_entries, ttrss_user_entries
|
||||
WHERE ref_id = id AND (guid = '".db_escape_string($entry_guid)."' OR guid = '$entry_guid_hashed') AND owner_uid = $owner_uid");
|
||||
$result = db_query("SELECT id, content_hash FROM ttrss_entries
|
||||
WHERE guid = '".db_escape_string($entry_guid)."' OR guid = '$entry_guid_hashed'");
|
||||
|
||||
if (db_num_rows($result) != 0) {
|
||||
$entry_plugin_data = db_fetch_result($result, 0, "plugin_data");
|
||||
$stored_article = array("title" => db_fetch_result($result, 0, "title"),
|
||||
"content" => db_fetch_result($result, 0, "content"),
|
||||
"link" => db_fetch_result($result, 0, "link"),
|
||||
"tags" => explode(",", db_fetch_result($result, 0, "tag_cache")),
|
||||
"author" => db_fetch_result($result, 0, "author"));
|
||||
$base_entry_id = db_fetch_result($result, 0, "id");
|
||||
$entry_stored_hash = db_fetch_result($result, 0, "content_hash");
|
||||
} else {
|
||||
$entry_plugin_data = "";
|
||||
$stored_article = array();
|
||||
$base_entry_id = false;
|
||||
$entry_stored_hash = "";
|
||||
}
|
||||
|
||||
$article = array("owner_uid" => $owner_uid, // read only
|
||||
@@ -626,32 +682,67 @@
|
||||
"content" => $entry_content,
|
||||
"link" => $entry_link,
|
||||
"tags" => $entry_tags,
|
||||
"plugin_data" => $entry_plugin_data,
|
||||
"author" => $entry_author,
|
||||
"stored" => $stored_article);
|
||||
"language" => $entry_language, // read only
|
||||
"feed" => array("id" => $feed,
|
||||
"fetch_url" => $fetch_url,
|
||||
"site_url" => $site_url)
|
||||
);
|
||||
|
||||
$entry_plugin_data = "";
|
||||
$entry_current_hash = calculate_article_hash($article, $pluginhost);
|
||||
|
||||
_debug("article hash: $entry_current_hash [stored=$entry_stored_hash]", $debug_enabled);
|
||||
|
||||
if ($entry_current_hash == $entry_stored_hash && !isset($_REQUEST["force_rehash"])) {
|
||||
_debug("stored article seems up to date [IID: $base_entry_id], updating timestamp only", $debug_enabled);
|
||||
|
||||
// we keep encountering the entry in feeds, so we need to
|
||||
// update date_updated column so that we don't get horrible
|
||||
// dupes when the entry gets purged and reinserted again e.g.
|
||||
// in the case of SLOW SLOW OMG SLOW updating feeds
|
||||
|
||||
$base_entry_id = db_fetch_result($result, 0, "id");
|
||||
|
||||
db_query("UPDATE ttrss_entries SET date_updated = NOW()
|
||||
WHERE id = '$base_entry_id'");
|
||||
|
||||
// if we allow duplicate posts, we have to continue to
|
||||
// create the user entries for this feed
|
||||
if (!get_pref("ALLOW_DUPLICATE_POSTS", $owner_uid, false)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_debug("hash differs, applying plugin filters:", $debug_enabled);
|
||||
|
||||
foreach ($pluginhost->get_hooks(PluginHost::HOOK_ARTICLE_FILTER) as $plugin) {
|
||||
_debug("... " . get_class($plugin), $debug_enabled);
|
||||
|
||||
$start = microtime(true);
|
||||
$article = $plugin->hook_article_filter($article);
|
||||
|
||||
_debug("=== " . sprintf("%.4f (sec)", microtime(true) - $start), $debug_enabled);
|
||||
|
||||
$entry_plugin_data .= mb_strtolower(get_class($plugin)) . ",";
|
||||
}
|
||||
|
||||
$entry_plugin_data = db_escape_string($entry_plugin_data);
|
||||
|
||||
_debug("plugin data: $entry_plugin_data", $debug_enabled);
|
||||
|
||||
$entry_tags = $article["tags"];
|
||||
$entry_guid = db_escape_string($entry_guid);
|
||||
$entry_title = db_escape_string($article["title"]);
|
||||
$entry_author = db_escape_string($article["author"]);
|
||||
$entry_link = db_escape_string($article["link"]);
|
||||
$entry_plugin_data = db_escape_string($article["plugin_data"]);
|
||||
$entry_content = $article["content"]; // escaped below
|
||||
|
||||
|
||||
_debug("plugin data: $entry_plugin_data", $debug_enabled);
|
||||
|
||||
if ($cache_images && is_writable(CACHE_DIR . '/images'))
|
||||
cache_images($entry_content, $site_url, $debug_enabled);
|
||||
|
||||
$entry_content = db_escape_string($entry_content, false);
|
||||
|
||||
$content_hash = "SHA1:" . sha1($entry_content);
|
||||
|
||||
db_query("BEGIN");
|
||||
|
||||
$result = db_query("SELECT id FROM ttrss_entries
|
||||
@@ -671,13 +762,13 @@
|
||||
updated,
|
||||
content,
|
||||
content_hash,
|
||||
cached_content,
|
||||
no_orig_date,
|
||||
date_updated,
|
||||
date_entered,
|
||||
comments,
|
||||
num_comments,
|
||||
plugin_data,
|
||||
lang,
|
||||
author)
|
||||
VALUES
|
||||
('$entry_title',
|
||||
@@ -685,41 +776,27 @@
|
||||
'$entry_link',
|
||||
'$entry_timestamp_fmt',
|
||||
'$entry_content',
|
||||
'$content_hash',
|
||||
'',
|
||||
$no_orig_date,
|
||||
'$entry_current_hash',
|
||||
false,
|
||||
NOW(),
|
||||
'$date_feed_processed',
|
||||
'$entry_comments',
|
||||
'$num_comments',
|
||||
'$entry_plugin_data',
|
||||
'$entry_language',
|
||||
'$entry_author')");
|
||||
|
||||
$article_labels = array();
|
||||
|
||||
} else {
|
||||
// we keep encountering the entry in feeds, so we need to
|
||||
// update date_updated column so that we don't get horrible
|
||||
// dupes when the entry gets purged and reinserted again e.g.
|
||||
// in the case of SLOW SLOW OMG SLOW updating feeds
|
||||
|
||||
$base_entry_id = db_fetch_result($result, 0, "id");
|
||||
|
||||
db_query("UPDATE ttrss_entries SET date_updated = NOW()
|
||||
WHERE id = '$base_entry_id'");
|
||||
|
||||
$article_labels = get_article_labels($base_entry_id, $owner_uid);
|
||||
}
|
||||
|
||||
// now it should exist, if not - bad luck then
|
||||
|
||||
$result = db_query("SELECT
|
||||
id,content_hash,no_orig_date,title,plugin_data,guid,
|
||||
".SUBSTRING_FOR_DATE."(date_updated,1,19) as date_updated,
|
||||
".SUBSTRING_FOR_DATE."(updated,1,19) as updated,
|
||||
num_comments
|
||||
FROM
|
||||
ttrss_entries
|
||||
$result = db_query("SELECT id FROM ttrss_entries
|
||||
WHERE guid = '$entry_guid' OR guid = '$entry_guid_hashed'");
|
||||
|
||||
$entry_ref_id = 0;
|
||||
@@ -729,14 +806,6 @@
|
||||
|
||||
_debug("base guid found, checking for user record", $debug_enabled);
|
||||
|
||||
// this will be used below in update handler
|
||||
$orig_content_hash = db_fetch_result($result, 0, "content_hash");
|
||||
$orig_title = db_fetch_result($result, 0, "title");
|
||||
$orig_num_comments = db_fetch_result($result, 0, "num_comments");
|
||||
$orig_date_updated = strtotime(db_fetch_result($result,
|
||||
0, "date_updated"));
|
||||
$orig_plugin_data = db_fetch_result($result, 0, "plugin_data");
|
||||
|
||||
$ref_id = db_fetch_result($result, 0, "id");
|
||||
$entry_ref_id = $ref_id;
|
||||
|
||||
@@ -850,7 +919,7 @@
|
||||
|
||||
$p = new Publisher(PUBSUBHUBBUB_HUB);
|
||||
|
||||
$pubsub_result = $p->publish_update($rss_link);
|
||||
/* $pubsub_result = */ $p->publish_update($rss_link);
|
||||
}
|
||||
|
||||
$result = db_query(
|
||||
@@ -870,53 +939,20 @@
|
||||
|
||||
_debug("RID: $entry_ref_id, IID: $entry_int_id", $debug_enabled);
|
||||
|
||||
$post_needs_update = false;
|
||||
$update_insignificant = false;
|
||||
db_query("UPDATE ttrss_entries
|
||||
SET title = '$entry_title',
|
||||
content = '$entry_content',
|
||||
content_hash = '$entry_current_hash',
|
||||
updated = '$entry_timestamp_fmt',
|
||||
num_comments = '$num_comments',
|
||||
plugin_data = '$entry_plugin_data',
|
||||
author = '$entry_author',
|
||||
lang = '$entry_language'
|
||||
WHERE id = '$ref_id'");
|
||||
|
||||
if ($orig_num_comments != $num_comments) {
|
||||
$post_needs_update = true;
|
||||
$update_insignificant = true;
|
||||
}
|
||||
|
||||
if ($entry_plugin_data != $orig_plugin_data) {
|
||||
$post_needs_update = true;
|
||||
$update_insignificant = true;
|
||||
}
|
||||
|
||||
if ($content_hash != $orig_content_hash) {
|
||||
$post_needs_update = true;
|
||||
$update_insignificant = false;
|
||||
}
|
||||
|
||||
if (db_escape_string($orig_title) != $entry_title) {
|
||||
$post_needs_update = true;
|
||||
$update_insignificant = false;
|
||||
}
|
||||
|
||||
// if post needs update, update it and mark all user entries
|
||||
// linking to this post as updated
|
||||
if ($post_needs_update) {
|
||||
|
||||
if (defined('DAEMON_EXTENDED_DEBUG')) {
|
||||
_debug("post $entry_guid_hashed needs update...", $debug_enabled);
|
||||
}
|
||||
|
||||
// print "<!-- post $orig_title needs update : $post_needs_update -->";
|
||||
|
||||
db_query("UPDATE ttrss_entries
|
||||
SET title = '$entry_title', content = '$entry_content',
|
||||
content_hash = '$content_hash',
|
||||
updated = '$entry_timestamp_fmt',
|
||||
num_comments = '$num_comments',
|
||||
plugin_data = '$entry_plugin_data'
|
||||
WHERE id = '$ref_id'");
|
||||
|
||||
if (!$update_insignificant) {
|
||||
if ($mark_unread_on_update) {
|
||||
db_query("UPDATE ttrss_user_entries
|
||||
SET last_read = null, unread = true WHERE ref_id = '$ref_id'");
|
||||
}
|
||||
}
|
||||
if ($mark_unread_on_update) {
|
||||
db_query("UPDATE ttrss_user_entries
|
||||
SET last_read = null, unread = true WHERE ref_id = '$ref_id'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,7 +974,7 @@
|
||||
if (is_array($encs)) {
|
||||
foreach ($encs as $e) {
|
||||
$e_item = array(
|
||||
$e->link, $e->type, $e->length);
|
||||
$e->link, $e->type, $e->length, $e->title, $e->width, $e->height);
|
||||
array_push($enclosures, $e_item);
|
||||
}
|
||||
}
|
||||
@@ -950,18 +986,24 @@
|
||||
|
||||
db_query("BEGIN");
|
||||
|
||||
// debugging
|
||||
// db_query("DELETE FROM ttrss_enclosures WHERE post_id = '$entry_ref_id'");
|
||||
|
||||
foreach ($enclosures as $enc) {
|
||||
$enc_url = db_escape_string($enc[0]);
|
||||
$enc_type = db_escape_string($enc[1]);
|
||||
$enc_dur = db_escape_string($enc[2]);
|
||||
$enc_title = db_escape_string($enc[3]);
|
||||
$enc_width = intval($enc[4]);
|
||||
$enc_height = intval($enc[5]);
|
||||
|
||||
$result = db_query("SELECT id FROM ttrss_enclosures
|
||||
WHERE content_url = '$enc_url' AND post_id = '$entry_ref_id'");
|
||||
|
||||
if (db_num_rows($result) == 0) {
|
||||
db_query("INSERT INTO ttrss_enclosures
|
||||
(content_url, content_type, title, duration, post_id) VALUES
|
||||
('$enc_url', '$enc_type', '', '$enc_dur', '$entry_ref_id')");
|
||||
(content_url, content_type, title, duration, post_id, width, height) VALUES
|
||||
('$enc_url', '$enc_type', '$enc_title', '$enc_dur', '$entry_ref_id', $enc_width, $enc_height)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1062,11 +1104,6 @@
|
||||
_debug("article processed", $debug_enabled);
|
||||
}
|
||||
|
||||
if (!$last_updated) {
|
||||
_debug("new feed, catching it up...", $debug_enabled);
|
||||
catchup_feed($feed, false, $owner_uid);
|
||||
}
|
||||
|
||||
_debug("purging feed...", $debug_enabled);
|
||||
|
||||
purge_feed($feed, 0, $debug_enabled);
|
||||
@@ -1080,21 +1117,27 @@
|
||||
|
||||
$error_msg = db_escape_string(mb_substr($rss->error(), 0, 245));
|
||||
|
||||
_debug("error fetching feed: $error_msg", $debug_enabled);
|
||||
_debug("fetch error: $error_msg", $debug_enabled);
|
||||
|
||||
if (count($rss->errors()) > 1) {
|
||||
foreach ($rss->errors() as $error) {
|
||||
_debug("+ $error");
|
||||
}
|
||||
}
|
||||
|
||||
db_query(
|
||||
"UPDATE ttrss_feeds SET last_error = '$error_msg',
|
||||
last_updated = NOW() WHERE id = '$feed'");
|
||||
last_updated = NOW() WHERE id = '$feed'");
|
||||
|
||||
unset($rss);
|
||||
}
|
||||
|
||||
unset($rss);
|
||||
|
||||
_debug("done", $debug_enabled);
|
||||
|
||||
return $rss;
|
||||
}
|
||||
|
||||
function cache_images($html, $site_url, $debug) {
|
||||
$cache_dir = CACHE_DIR . "/images";
|
||||
|
||||
libxml_use_internal_errors(true);
|
||||
|
||||
$charset_hack = '<head>
|
||||
@@ -1118,21 +1161,20 @@
|
||||
if (!file_exists($local_filename)) {
|
||||
$file_content = fetch_file_contents($src);
|
||||
|
||||
if ($file_content && strlen($file_content) > 1024) {
|
||||
if ($file_content && strlen($file_content) > _MIN_CACHE_IMAGE_SIZE) {
|
||||
file_put_contents($local_filename, $file_content);
|
||||
}
|
||||
}
|
||||
|
||||
if (file_exists($local_filename)) {
|
||||
/* if (file_exists($local_filename)) {
|
||||
$entry->setAttribute('src', SELF_URL_PATH . '/image.php?url=' .
|
||||
base64_encode($src));
|
||||
}
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
$node = $doc->getElementsByTagName('body')->item(0);
|
||||
|
||||
return $doc->saveXML($node);
|
||||
//$node = $doc->getElementsByTagName('body')->item(0);
|
||||
//return $doc->saveXML($node);
|
||||
}
|
||||
|
||||
function expire_error_log($debug) {
|
||||
@@ -1370,5 +1412,8 @@
|
||||
$rc = cleanup_tags( 14, 50000);
|
||||
|
||||
_debug("Cleaned $rc cached tags.");
|
||||
|
||||
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_HOUSE_KEEPING, "hook_house_keeping", "");
|
||||
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (SELF_URL_PATH == "http://yourserver/tt-rss/") {
|
||||
if (SELF_URL_PATH == "http://example.org/tt-rss/") {
|
||||
$urlpath = preg_replace("/\w+\.php$/", "", make_self_url_path());
|
||||
|
||||
array_push($errors,
|
||||
@@ -138,10 +138,6 @@
|
||||
array_push($errors, "PHP support for ctype functions are required by HTMLPurifier.");
|
||||
}
|
||||
|
||||
if (!function_exists("iconv")) {
|
||||
array_push($errors, "PHP support for iconv is required to handle multiple charsets.");
|
||||
}
|
||||
|
||||
/* if (ini_get("safe_mode")) {
|
||||
array_push($errors, "PHP safe mode setting is not supported.");
|
||||
} */
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<?php # This file has been generated at: Thu May 30 08:39:20 MSK 2013
|
||||
<?php # This file has been generated at: Fri Sep 27 13:42:37 MSK 2013
|
||||
define('GENERATED_CONFIG_CHECK', 26);
|
||||
$requred_defines = array( 'DB_TYPE', 'DB_HOST', 'DB_USER', 'DB_NAME', 'DB_PASS', 'MYSQL_CHARSET', 'SELF_URL_PATH', 'FEED_CRYPT_KEY', 'SINGLE_USER_MODE', 'SIMPLE_UPDATE_MODE', 'PHP_EXECUTABLE', 'LOCK_DIRECTORY', 'CACHE_DIR', 'ICONS_DIR', 'ICONS_URL', 'AUTH_AUTO_CREATE', 'AUTH_AUTO_LOGIN', 'FORCE_ARTICLE_PURGE', 'PUBSUBHUBBUB_HUB', 'PUBSUBHUBBUB_ENABLED', 'SPHINX_ENABLED', 'SPHINX_SERVER', 'SPHINX_INDEX', 'ENABLE_REGISTRATION', 'REG_NOTIFY_ADDRESS', 'REG_MAX_USERS', 'SESSION_COOKIE_LIFETIME', 'SESSION_CHECK_ADDRESS', 'SMTP_FROM_NAME', 'SMTP_FROM_ADDRESS', 'DIGEST_SUBJECT', 'SMTP_SERVER', 'SMTP_LOGIN', 'SMTP_PASSWORD', 'SMTP_SECURE', 'CHECK_FOR_NEW_VERSION', 'ENABLE_GZIP_OUTPUT', 'PLUGINS', 'LOG_DESTINATION', 'CONFIG_VERSION'); ?>
|
||||
$requred_defines = array( 'DB_TYPE', 'DB_HOST', 'DB_USER', 'DB_NAME', 'DB_PASS', 'MYSQL_CHARSET', 'SELF_URL_PATH', 'FEED_CRYPT_KEY', 'SINGLE_USER_MODE', 'SIMPLE_UPDATE_MODE', 'PHP_EXECUTABLE', 'LOCK_DIRECTORY', 'CACHE_DIR', 'ICONS_DIR', 'ICONS_URL', 'AUTH_AUTO_CREATE', 'AUTH_AUTO_LOGIN', 'FORCE_ARTICLE_PURGE', 'PUBSUBHUBBUB_HUB', 'PUBSUBHUBBUB_ENABLED', 'ENABLE_REGISTRATION', 'REG_NOTIFY_ADDRESS', 'REG_MAX_USERS', 'SESSION_COOKIE_LIFETIME', 'SESSION_CHECK_ADDRESS', 'SMTP_FROM_NAME', 'SMTP_FROM_ADDRESS', 'DIGEST_SUBJECT', 'SMTP_SERVER', 'SMTP_LOGIN', 'SMTP_PASSWORD', 'SMTP_SECURE', 'CHECK_FOR_NEW_VERSION', 'DETECT_ARTICLE_LANGUAGE', 'ENABLE_GZIP_OUTPUT', 'PLUGINS', 'LOG_DESTINATION', 'CONFIG_VERSION'); ?>
|
||||
|
||||
@@ -62,11 +62,17 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($_SESSION["ref_schema_version"] != session_get_schema_version(true))
|
||||
if ($_SESSION["ref_schema_version"] != session_get_schema_version(true)) {
|
||||
$_SESSION["login_error_msg"] =
|
||||
__("Session failed to validate (schema version changed)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sha1($_SERVER['HTTP_USER_AGENT']) != $_SESSION["user_agent"])
|
||||
if (sha1($_SERVER['HTTP_USER_AGENT']) != $_SESSION["user_agent"]) {
|
||||
$_SESSION["login_error_msg"] =
|
||||
__("Session failed to validate (user agent changed)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($_SESSION["uid"]) {
|
||||
$result = Db::get()->query(
|
||||
@@ -74,11 +80,19 @@
|
||||
|
||||
// user not found
|
||||
if (Db::get()->num_rows($result) == 0) {
|
||||
|
||||
$_SESSION["login_error_msg"] =
|
||||
__("Session failed to validate (user not found)");
|
||||
|
||||
return false;
|
||||
} else {
|
||||
$pwd_hash = Db::get()->fetch_result($result, 0, "pwd_hash");
|
||||
|
||||
if ($pwd_hash != $_SESSION["pwd_hash"]) {
|
||||
|
||||
$_SESSION["login_error_msg"] =
|
||||
__("Session failed to validate (password changed)");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?php
|
||||
define('VERSION_STATIC', '1.8');
|
||||
define('VERSION_STATIC', '1.14');
|
||||
|
||||
function get_version() {
|
||||
date_default_timezone_set('UTC');
|
||||
$root_dir = dirname(dirname(__FILE__));
|
||||
|
||||
if (is_dir("$root_dir/.git") && file_exists("$root_dir/.git/ORIG_HEAD")) {
|
||||
if (is_dir("$root_dir/.git") && file_exists("$root_dir/.git/refs/heads/master")) {
|
||||
|
||||
$suffix = substr(trim(file_get_contents("$root_dir/.git/ORIG_HEAD")), 0, 7);
|
||||
$suffix = substr(trim(file_get_contents("$root_dir/.git/refs/heads/master")), 0, 7);
|
||||
|
||||
return VERSION_STATIC . ".$suffix";
|
||||
} else {
|
||||
|
||||
31
index.php
@@ -56,15 +56,19 @@
|
||||
<head>
|
||||
<title>Tiny Tiny RSS</title>
|
||||
|
||||
<?php stylesheet_tag("lib/dijit/themes/claro/claro.css"); ?>
|
||||
<?php stylesheet_tag("css/layout.css"); ?>
|
||||
<script type="text/javascript">
|
||||
var __ttrss_version = "<?php echo VERSION ?>"
|
||||
</script>
|
||||
|
||||
<?php echo stylesheet_tag("lib/dijit/themes/claro/claro.css"); ?>
|
||||
<?php echo stylesheet_tag("css/layout.css"); ?>
|
||||
|
||||
<?php if ($_SESSION["uid"]) {
|
||||
$theme = get_pref( "USER_CSS_THEME", $_SESSION["uid"], false);
|
||||
if ($theme && file_exists("themes/$theme")) {
|
||||
stylesheet_tag("themes/$theme");
|
||||
echo stylesheet_tag("themes/$theme");
|
||||
} else {
|
||||
stylesheet_tag("themes/default.css");
|
||||
echo stylesheet_tag("themes/default.css");
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -86,19 +90,19 @@
|
||||
|
||||
<?php
|
||||
foreach (array("lib/prototype.js",
|
||||
"lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls",
|
||||
"lib/scriptaculous/scriptaculous.js?load=effects,controls",
|
||||
"lib/dojo/dojo.js",
|
||||
"lib/dojo/tt-rss-layer.js",
|
||||
"errors.php?mode=js") as $jsfile) {
|
||||
|
||||
javascript_tag($jsfile);
|
||||
echo javascript_tag($jsfile);
|
||||
|
||||
} ?>
|
||||
|
||||
<script type="text/javascript">
|
||||
require({cache:{}});
|
||||
<?php
|
||||
require 'lib/jshrink/Minifier.php';
|
||||
require_once 'lib/jshrink/Minifier.php';
|
||||
|
||||
print get_minified_js(array("tt-rss",
|
||||
"functions", "feedlist", "viewfeed", "FeedTree", "PluginHost"));
|
||||
@@ -134,7 +138,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="notify" class="notify" style="display : none"></div>
|
||||
<div id="notify" class="notify"></div>
|
||||
<div id="cmdline" style="display : none"></div>
|
||||
<div id="headlines-tmp" style="display : none"></div>
|
||||
|
||||
@@ -153,11 +157,15 @@
|
||||
<div id="toolbar" dojoType="dijit.layout.ContentPane" region="top">
|
||||
<div id="main-toolbar" dojoType="dijit.Toolbar">
|
||||
|
||||
<form id="headlines-toolbar" action="" onsubmit='return false'>
|
||||
|
||||
</form>
|
||||
|
||||
<form id="main_toolbar_form" action="" onsubmit='return false'>
|
||||
|
||||
<button dojoType="dijit.form.Button" id="collapse_feeds_btn"
|
||||
onclick="collapse_feedlist()"
|
||||
title="<?php echo __('Collapse feedlist') ?>" style="display : inline">
|
||||
title="<?php echo __('Collapse feedlist') ?>" style="display : none">
|
||||
<<</button>
|
||||
|
||||
<select name="view_mode" title="<?php echo __('Show articles') ?>"
|
||||
@@ -210,7 +218,7 @@
|
||||
<button id="net-alert" dojoType="dijit.form.Button" style="display : none" disabled="true"
|
||||
title="<?php echo __("Communication problem with server.") ?>">
|
||||
<img
|
||||
src="images/alert.png" />
|
||||
src="images/error.png" />
|
||||
</button>
|
||||
|
||||
<button id="newVersionIcon" dojoType="dijit.form.Button" style="display : none">
|
||||
@@ -257,9 +265,6 @@
|
||||
|
||||
<div id="headlines-wrap-inner" dojoType="dijit.layout.BorderContainer" region="center">
|
||||
|
||||
<div id="headlines-toolbar" dojoType="dijit.layout.ContentPane" region="top">
|
||||
</div>
|
||||
|
||||
<div id="floatingTitle" style="display : none"></div>
|
||||
|
||||
<div id="headlines-frame" dojoType="dijit.layout.ContentPane"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<title>Tiny Tiny RSS - Installer</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="../css/utility.css">
|
||||
<link rel="stylesheet" type="text/css" href="../css/dijit.css">
|
||||
<style type="text/css">
|
||||
textarea { font-size : 12px; }
|
||||
</style>
|
||||
@@ -10,6 +11,12 @@
|
||||
<body>
|
||||
|
||||
<?php
|
||||
|
||||
// could be needed because of existing config.php
|
||||
function define_default($param, $value) {
|
||||
//
|
||||
}
|
||||
|
||||
function make_password($length = 8) {
|
||||
|
||||
$password = "";
|
||||
@@ -80,13 +87,13 @@
|
||||
}
|
||||
|
||||
function print_error($msg) {
|
||||
print "<div class='error'><span><img src='../images/sign_excl.svg'></span>
|
||||
print "<div class='error'><span><img src='../images/alert.png'></span>
|
||||
<span>$msg</span></div>";
|
||||
}
|
||||
|
||||
function print_notice($msg) {
|
||||
print "<div class=\"notice\">
|
||||
<span><img src=\"../images/sign_info.svg\"></span><span>$msg</span></div>";
|
||||
<span><img src=\"../images/information.png\"></span><span>$msg</span></div>";
|
||||
}
|
||||
|
||||
function db_connect($host, $user, $pass, $db, $type, $port = false) {
|
||||
@@ -199,7 +206,7 @@
|
||||
}
|
||||
|
||||
function make_self_url_path() {
|
||||
$url_path = ($_SERVER['HTTPS'] != "on" ? 'http://' : 'https://') . $_SERVER["HTTP_HOST"] . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
|
||||
$url_path = ((!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") ? 'http://' : 'https://') . $_SERVER["HTTP_HOST"] . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
|
||||
|
||||
return $url_path;
|
||||
}
|
||||
@@ -263,7 +270,7 @@
|
||||
|
||||
<fieldset>
|
||||
<label>Password</label>
|
||||
<input required name="DB_PASS" size="20" type="password" value="<?php echo $DB_PASS ?>"/>
|
||||
<input name="DB_PASS" size="20" type="password" value="<?php echo $DB_PASS ?>"/>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
|
||||
@@ -58,12 +58,12 @@ dojo.declare("fox.FeedStoreModel", dijit.tree.ForestStoreModel, {
|
||||
|
||||
if (is_cat) {
|
||||
treeItem = this.store._itemsByIdentity['CAT:' + feed];
|
||||
items = this.store._arrayOfTopLevelItems;
|
||||
} else {
|
||||
treeItem = this.store._itemsByIdentity['FEED:' + feed];
|
||||
items = this.store._arrayOfAllItems;
|
||||
}
|
||||
|
||||
items = this.store._arrayOfAllItems;
|
||||
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i] == treeItem) {
|
||||
|
||||
@@ -71,14 +71,18 @@ dojo.declare("fox.FeedStoreModel", dijit.tree.ForestStoreModel, {
|
||||
var unread = this.store.getValue(items[j], 'unread');
|
||||
var id = this.store.getValue(items[j], 'id');
|
||||
|
||||
if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
|
||||
if (unread > 0 && ((is_cat && id.match("CAT:")) || (!is_cat && id.match("FEED:")))) {
|
||||
if( !is_cat || ! (this.store.hasAttribute(items[j], 'parent_id') && this.store.getValue(items[j], 'parent_id') == feed) ) return items[j];
|
||||
}
|
||||
}
|
||||
|
||||
for (var j = 0; j < i; j++) {
|
||||
var unread = this.store.getValue(items[j], 'unread');
|
||||
var id = this.store.getValue(items[j], 'id');
|
||||
|
||||
if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
|
||||
if (unread > 0 && ((is_cat && id.match("CAT:")) || (!is_cat && id.match("FEED:")))) {
|
||||
if( !is_cat || ! (this.store.hasAttribute(items[j], 'parent_id') && this.store.getValue(items[j], 'parent_id') == feed) ) return items[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -539,7 +543,7 @@ dojo.declare("fox.FeedTree", dijit.Tree, {
|
||||
}
|
||||
|
||||
items = this.model.store._arrayOfAllItems;
|
||||
var item = items[0];
|
||||
var item = items[0] == treeItem ? items[items.length-1] : items[0];
|
||||
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i] == treeItem) {
|
||||
|
||||
@@ -10,6 +10,7 @@ var PluginHost = {
|
||||
HOOK_ARTICLE_COLLAPSED: 7,
|
||||
HOOK_PARAMS_LOADED: 8,
|
||||
HOOK_RUNTIME_INFO_LOADED: 9,
|
||||
HOOK_FLOATING_TITLE: 10,
|
||||
hooks: [],
|
||||
register: function (name, callback) {
|
||||
if (typeof(this.hooks[name]) == 'undefined')
|
||||
|
||||
@@ -24,6 +24,7 @@ dojo.declare("fox.PrefFilterTree", lib.CheckBoxTree, {
|
||||
|
||||
var enabled = this.model.store.getValue(args.item, 'enabled');
|
||||
var param = this.model.store.getValue(args.item, 'param');
|
||||
var rules = this.model.store.getValue(args.item, 'rules');
|
||||
|
||||
if (param) {
|
||||
param = dojo.doc.createElement('span');
|
||||
@@ -32,6 +33,21 @@ dojo.declare("fox.PrefFilterTree", lib.CheckBoxTree, {
|
||||
dojo.place(param, tnode.rowNode, 'first');
|
||||
}
|
||||
|
||||
if (rules) {
|
||||
param = dojo.doc.createElement('span');
|
||||
param.className = 'filterRules';
|
||||
param.innerHTML = rules;
|
||||
dojo.place(param, tnode.rowNode, 'next');
|
||||
}
|
||||
|
||||
if (this.model.store.getValue(args.item, 'id') != 'root') {
|
||||
var img = dojo.doc.createElement('img');
|
||||
img.src ='images/filter.png';
|
||||
img.className = 'markedPic';
|
||||
tnode._filterIconNode = img;
|
||||
dojo.place(tnode._filterIconNode, tnode.labelNode, 'before');
|
||||
}
|
||||
|
||||
return tnode;
|
||||
},
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ dojo.declare("fox.PrefLabelTree", lib.CheckBoxTree, {
|
||||
if (type == 'label') {
|
||||
var span = dojo.doc.createElement('span');
|
||||
span.innerHTML = 'α';
|
||||
span.className = 'labelColorIndicator2';
|
||||
span.className = 'labelColorIndicator';
|
||||
span.id = 'LICID-' + bare_id;
|
||||
|
||||
span.setStyle({
|
||||
@@ -38,6 +38,6 @@ dojo.declare("fox.PrefLabelTree", lib.CheckBoxTree, {
|
||||
},
|
||||
getIconClass: function (item, opened) {
|
||||
return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible";
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ var _infscroll_disable = 0;
|
||||
var _infscroll_request_sent = 0;
|
||||
var _search_query = false;
|
||||
var _viewfeed_last = 0;
|
||||
var _viewfeed_timeout = false;
|
||||
|
||||
var counters_last_request = 0;
|
||||
|
||||
@@ -34,10 +35,7 @@ function loadMoreHeadlines() {
|
||||
} else if (_search_query) {
|
||||
offset = num_all;
|
||||
} else if (view_mode == "adaptive") {
|
||||
if (num_unread > 0)
|
||||
offset = unread_in_buffer;
|
||||
else
|
||||
offset = num_all;
|
||||
offset = num_unread > 0 ? unread_in_buffer : num_all;
|
||||
} else {
|
||||
offset = num_all;
|
||||
}
|
||||
@@ -52,7 +50,7 @@ function loadMoreHeadlines() {
|
||||
}
|
||||
|
||||
|
||||
function viewfeed(feed, method, is_cat, offset, background, infscroll_req) {
|
||||
function viewfeed(feed, method, is_cat, offset, background, infscroll_req, can_wait) {
|
||||
try {
|
||||
if (is_cat == undefined)
|
||||
is_cat = false;
|
||||
@@ -94,7 +92,7 @@ function viewfeed(feed, method, is_cat, offset, background, infscroll_req) {
|
||||
|
||||
var toolbar_query = Form.serialize("main_toolbar_form");
|
||||
|
||||
var query = "?op=feeds&method=view&feed=" + feed + "&" +
|
||||
var query = "?op=feeds&method=view&feed=" + param_escape(feed) + "&" +
|
||||
toolbar_query;
|
||||
|
||||
if (method) {
|
||||
@@ -132,15 +130,24 @@ function viewfeed(feed, method, is_cat, offset, background, infscroll_req) {
|
||||
|
||||
console.log(query);
|
||||
|
||||
if (can_wait && _viewfeed_timeout) {
|
||||
setFeedExpandoIcon(getActiveFeedId(), activeFeedIsCat(), 'images/blank_icon.gif');
|
||||
clearTimeout(_viewfeed_timeout);
|
||||
}
|
||||
|
||||
setActiveFeedId(feed, is_cat);
|
||||
|
||||
new Ajax.Request("backend.php", {
|
||||
parameters: query,
|
||||
onComplete: function(transport) {
|
||||
setFeedExpandoIcon(feed, is_cat, 'images/blank_icon.gif');
|
||||
headlines_callback2(transport, offset, background, infscroll_req);
|
||||
PluginHost.run(PluginHost.HOOK_FEED_LOADED, [feed, is_cat]);
|
||||
} });
|
||||
timeout_ms = can_wait ? 250 : 0;
|
||||
_viewfeed_timeout = setTimeout(function() {
|
||||
|
||||
new Ajax.Request("backend.php", {
|
||||
parameters: query,
|
||||
onComplete: function(transport) {
|
||||
setFeedExpandoIcon(feed, is_cat, 'images/blank_icon.gif');
|
||||
headlines_callback2(transport, offset, background, infscroll_req);
|
||||
PluginHost.run(PluginHost.HOOK_FEED_LOADED, [feed, is_cat]);
|
||||
} });
|
||||
}, timeout_ms); // Wait 250ms
|
||||
|
||||
} catch (e) {
|
||||
exception_error("viewfeed", e);
|
||||
|
||||
128
js/functions.js
@@ -44,11 +44,8 @@ function exception_error(location, e, ext_info) {
|
||||
|
||||
try {
|
||||
|
||||
if (ext_info) {
|
||||
if (ext_info.responseText) {
|
||||
ext_info = ext_info.responseText;
|
||||
}
|
||||
}
|
||||
if (ext_info)
|
||||
ext_info = JSON.stringify(ext_info);
|
||||
|
||||
try {
|
||||
new Ajax.Request("backend.php", {
|
||||
@@ -104,13 +101,15 @@ function exception_error(location, e, ext_info) {
|
||||
title: "Unhandled exception",
|
||||
style: "width: 600px",
|
||||
report: function() {
|
||||
if (confirm(__("Are you sure to report this exception to tt-rss.org? The report will include your browser information. Your IP would be saved in the database."))) {
|
||||
if (confirm(__("Are you sure to report this exception to tt-rss.org? The report will include information about your web browser and tt-rss configuration. Your IP will be saved in the database."))) {
|
||||
|
||||
document.forms['exceptionForm'].params.value = $H({
|
||||
browserName: navigator.appName,
|
||||
browserVersion: navigator.appVersion,
|
||||
browserPlatform: navigator.platform,
|
||||
browserCookies: navigator.cookieEnabled,
|
||||
ttrssVersion: __ttrss_version,
|
||||
initParams: JSON.stringify(init_params),
|
||||
}).toQueryString();
|
||||
|
||||
document.forms['exceptionForm'].submit();
|
||||
@@ -183,11 +182,6 @@ function param_unescape(arg) {
|
||||
return unescape(arg);
|
||||
}
|
||||
|
||||
|
||||
function hide_notify() {
|
||||
Element.hide('notify');
|
||||
}
|
||||
|
||||
function notify_real(msg, no_hide, n_type) {
|
||||
|
||||
var n = $("notify");
|
||||
@@ -199,12 +193,11 @@ function notify_real(msg, no_hide, n_type) {
|
||||
}
|
||||
|
||||
if (msg == "") {
|
||||
if (Element.visible(n)) {
|
||||
notify_hide_timerid = window.setTimeout("hide_notify()", 0);
|
||||
if (n.hasClassName("visible")) {
|
||||
notify_hide_timerid = window.setTimeout(function() {
|
||||
n.removeClassName("visible") }, 0);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
Element.show(n);
|
||||
}
|
||||
|
||||
/* types:
|
||||
@@ -218,21 +211,21 @@ function notify_real(msg, no_hide, n_type) {
|
||||
|
||||
msg = "<span class=\"msg\"> " + __(msg) + "</span>";
|
||||
|
||||
if (n_type == 1) {
|
||||
n.className = "notify";
|
||||
} else if (n_type == 2) {
|
||||
n.className = "notify progress";
|
||||
if (n_type == 2) {
|
||||
n.className = "notify notify_progress visible";
|
||||
msg = "<span><img src='images/indicator_white.gif'></span>" + msg;
|
||||
no_hide = true;
|
||||
} else if (n_type == 3) {
|
||||
n.className = "notify error";
|
||||
msg = "<span><img src='images/sign_excl.svg'></span>" + msg;
|
||||
n.className = "notify notify_error visible";
|
||||
msg = "<span><img src='images/alert.png'></span>" + msg;
|
||||
} else if (n_type == 4) {
|
||||
n.className = "notify info";
|
||||
msg = "<span><img src='images/sign_info.svg'></span>" + msg;
|
||||
n.className = "notify notify_info visible";
|
||||
msg = "<span><img src='images/information.png'></span>" + msg;
|
||||
} else {
|
||||
n.className = "notify visible";
|
||||
}
|
||||
|
||||
msg += " <span><img src=\"images/close_notify.svg\" class=\"close\" title=\"" +
|
||||
msg += " <span><img src=\"images/cross.png\" class=\"close\" title=\"" +
|
||||
__("Click to close") + "\" onclick=\"notify('')\"></span>";
|
||||
|
||||
// msg = "<img src='images/live_com_loading.gif'> " + msg;
|
||||
@@ -240,7 +233,8 @@ function notify_real(msg, no_hide, n_type) {
|
||||
n.innerHTML = msg;
|
||||
|
||||
if (!no_hide) {
|
||||
notify_hide_timerid = window.setTimeout("hide_notify()", 5*1000);
|
||||
notify_hide_timerid = window.setTimeout(function() {
|
||||
n.removeClassName("visible") }, 5*1000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -829,7 +823,14 @@ function quickAddFeed() {
|
||||
onComplete: function(transport) {
|
||||
try {
|
||||
|
||||
var reply = JSON.parse(transport.responseText);
|
||||
try {
|
||||
var reply = JSON.parse(transport.responseText);
|
||||
} catch (e) {
|
||||
Element.hide("feed_add_spinner");
|
||||
alert(__("Failed to parse output. This can indicate server timeout and/or network issues. Backend output was logged to browser console."));
|
||||
console.log('quickAddFeed, backend returned:' + transport.responseText);
|
||||
return;
|
||||
}
|
||||
|
||||
var rc = reply['result'];
|
||||
|
||||
@@ -854,6 +855,8 @@ function quickAddFeed() {
|
||||
case 4:
|
||||
feeds = rc['feeds'];
|
||||
|
||||
Element.show("fadd_multiple_notify");
|
||||
|
||||
var select = dijit.byId("feedDlg_feedContainerSelect");
|
||||
|
||||
while (select.getOptions().length > 0)
|
||||
@@ -1148,33 +1151,48 @@ function quickAddFilter() {
|
||||
href: query});
|
||||
|
||||
if (!inPreferences()) {
|
||||
var selectedText = getSelectionText();
|
||||
|
||||
var lh = dojo.connect(dialog, "onLoad", function(){
|
||||
dojo.disconnect(lh);
|
||||
|
||||
var query = "op=rpc&method=getlinktitlebyid&id=" + getActiveArticleId();
|
||||
if (selectedText != "") {
|
||||
|
||||
new Ajax.Request("backend.php", {
|
||||
parameters: query,
|
||||
onComplete: function(transport) {
|
||||
var reply = JSON.parse(transport.responseText);
|
||||
var feed_id = activeFeedIsCat() ? 'CAT:' + parseInt(getActiveFeedId()) :
|
||||
getActiveFeedId();
|
||||
|
||||
var title = false;
|
||||
var rule = { reg_exp: selectedText, feed_id: feed_id, filter_type: 1 };
|
||||
|
||||
if (reply && reply) title = reply.title;
|
||||
addFilterRule(null, dojo.toJson(rule));
|
||||
|
||||
if (title || getActiveFeedId() || activeFeedIsCat()) {
|
||||
} else {
|
||||
|
||||
console.log(title + " " + getActiveFeedId());
|
||||
var query = "op=rpc&method=getlinktitlebyid&id=" + getActiveArticleId();
|
||||
|
||||
var feed_id = activeFeedIsCat() ? 'CAT:' + parseInt(getActiveFeedId()) :
|
||||
getActiveFeedId();
|
||||
new Ajax.Request("backend.php", {
|
||||
parameters: query,
|
||||
onComplete: function(transport) {
|
||||
var reply = JSON.parse(transport.responseText);
|
||||
|
||||
var rule = { reg_exp: title, feed_id: feed_id, filter_type: 1 };
|
||||
var title = false;
|
||||
|
||||
addFilterRule(null, dojo.toJson(rule));
|
||||
}
|
||||
if (reply && reply) title = reply.title;
|
||||
|
||||
} });
|
||||
if (title || getActiveFeedId() || activeFeedIsCat()) {
|
||||
|
||||
console.log(title + " " + getActiveFeedId());
|
||||
|
||||
var feed_id = activeFeedIsCat() ? 'CAT:' + parseInt(getActiveFeedId()) :
|
||||
getActiveFeedId();
|
||||
|
||||
var rule = { reg_exp: title, feed_id: feed_id, filter_type: 1 };
|
||||
|
||||
addFilterRule(null, dojo.toJson(rule));
|
||||
}
|
||||
|
||||
} });
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
@@ -1270,10 +1288,8 @@ function backend_sanity_check_callback(transport) {
|
||||
console.log('reading init-params...');
|
||||
|
||||
for (k in params) {
|
||||
var v = params[k];
|
||||
console.log("IP: " + k + " => " + v);
|
||||
|
||||
if (k == "label_base_index") _label_base_index = parseInt(v);
|
||||
console.log("IP: " + k + " => " + JSON.stringify(params[k]));
|
||||
if (k == "label_base_index") _label_base_index = parseInt(params[k]);
|
||||
}
|
||||
|
||||
init_params = params;
|
||||
@@ -1934,3 +1950,25 @@ function feed_to_label_id(feed) {
|
||||
return _label_base_index - 1 + Math.abs(feed);
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/6251937/how-to-get-selecteduser-highlighted-text-in-contenteditable-element-and-replac
|
||||
|
||||
function getSelectionText() {
|
||||
var text = "";
|
||||
|
||||
if (typeof window.getSelection != "undefined") {
|
||||
var sel = window.getSelection();
|
||||
if (sel.rangeCount) {
|
||||
var container = document.createElement("div");
|
||||
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
|
||||
container.appendChild(sel.getRangeAt(i).cloneContents());
|
||||
}
|
||||
text = container.innerHTML;
|
||||
}
|
||||
} else if (typeof document.selection != "undefined") {
|
||||
if (document.selection.type == "Text") {
|
||||
text = document.selection.createRange().textText;
|
||||
}
|
||||
}
|
||||
|
||||
return text.stripTags();
|
||||
}
|
||||
|
||||
19
js/prefs.js
@@ -1529,25 +1529,6 @@ function clearFeedAccessKeys() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function clearArticleAccessKeys() {
|
||||
|
||||
var ok = confirm(__("This will invalidate all previously shared article URLs. Continue?"));
|
||||
|
||||
if (ok) {
|
||||
notify_progress("Clearing URLs...");
|
||||
|
||||
var query = "?op=rpc&method=clearArticleKeys";
|
||||
|
||||
new Ajax.Request("backend.php", {
|
||||
parameters: query,
|
||||
onComplete: function(transport) {
|
||||
notify_info("Shared URLs cleared.");
|
||||
} });
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function resetFilterOrder() {
|
||||
try {
|
||||
notify_progress("Loading, please wait...");
|
||||
|
||||
113
js/tt-rss.js
@@ -231,6 +231,7 @@ function init() {
|
||||
dojo.require("dijit.form.Select");
|
||||
dojo.require("dijit.form.SimpleTextarea");
|
||||
dojo.require("dijit.form.TextBox");
|
||||
dojo.require("dijit.form.ComboBox");
|
||||
dojo.require("dijit.form.ValidationTextBox");
|
||||
dojo.require("dijit.InlineEditBox");
|
||||
dojo.require("dijit.layout.AccordionContainer");
|
||||
@@ -272,13 +273,13 @@ function init() {
|
||||
var rv = dijit.byId("feedTree").getNextFeed(
|
||||
getActiveFeedId(), activeFeedIsCat());
|
||||
|
||||
if (rv) viewfeed(rv[0], '', rv[1]);
|
||||
if (rv) viewfeed(rv[0], '', rv[1], null, null, null, true);
|
||||
};
|
||||
hotkey_actions["prev_feed"] = function() {
|
||||
var rv = dijit.byId("feedTree").getPreviousFeed(
|
||||
getActiveFeedId(), activeFeedIsCat());
|
||||
|
||||
if (rv) viewfeed(rv[0], '', rv[1]);
|
||||
if (rv) viewfeed(rv[0], '', rv[1], null, null, null, true);
|
||||
};
|
||||
hotkey_actions["next_article"] = function() {
|
||||
moveToPost('next');
|
||||
@@ -301,21 +302,27 @@ function init() {
|
||||
hotkey_actions["collapse_article"] = function() {
|
||||
var id = getActiveArticleId();
|
||||
var elem = $("CICD-"+id);
|
||||
if(elem.visible()) {
|
||||
cdmCollapseArticle(null, id);
|
||||
}
|
||||
else {
|
||||
cdmExpandArticle(id);
|
||||
|
||||
if (elem) {
|
||||
if (elem.visible()) {
|
||||
cdmCollapseArticle(null, id);
|
||||
}
|
||||
else {
|
||||
cdmExpandArticle(id);
|
||||
}
|
||||
}
|
||||
};
|
||||
hotkey_actions["toggle_expand"] = function() {
|
||||
var id = getActiveArticleId();
|
||||
var elem = $("CICD-"+id);
|
||||
if(elem.visible()) {
|
||||
cdmCollapseArticle(null, id, false);
|
||||
}
|
||||
else {
|
||||
cdmExpandArticle(id);
|
||||
|
||||
if (elem) {
|
||||
if (elem.visible()) {
|
||||
cdmCollapseArticle(null, id, false);
|
||||
}
|
||||
else {
|
||||
cdmExpandArticle(id);
|
||||
}
|
||||
}
|
||||
};
|
||||
hotkey_actions["search_dialog"] = function() {
|
||||
@@ -339,6 +346,9 @@ function init() {
|
||||
hotkey_actions["dismiss_selected"] = function() {
|
||||
dismissSelectedArticles();
|
||||
};
|
||||
hotkey_actions["dismiss_read"] = function() {
|
||||
dismissReadArticles();
|
||||
};
|
||||
hotkey_actions["open_in_new_window"] = function() {
|
||||
if (getActiveArticleId()) {
|
||||
openArticleInNewWindow(getActiveArticleId());
|
||||
@@ -497,6 +507,10 @@ function init() {
|
||||
if (!isCdmMode()) {
|
||||
_widescreen_mode = !_widescreen_mode;
|
||||
|
||||
// reset stored sizes because geometry changed
|
||||
setCookie("ttrss_ci_width", 0);
|
||||
setCookie("ttrss_ci_height", 0);
|
||||
|
||||
switchPanelMode(_widescreen_mode);
|
||||
}
|
||||
};
|
||||
@@ -547,36 +561,26 @@ function init_second_stage() {
|
||||
updateFeedList();
|
||||
closeArticlePanel();
|
||||
|
||||
_widescreen_mode = getInitParam("widescreen");
|
||||
switchPanelMode(_widescreen_mode);
|
||||
|
||||
if (parseInt(getCookie("ttrss_fh_width")) > 0) {
|
||||
dijit.byId("feeds-holder").domNode.setStyle(
|
||||
{width: getCookie("ttrss_fh_width") + "px" });
|
||||
}
|
||||
|
||||
if (parseInt(getCookie("ttrss_ci_width")) > 0) {
|
||||
if (_widescreen_mode) {
|
||||
dijit.byId("content-insert").domNode.setStyle(
|
||||
{width: getCookie("ttrss_ci_width") + "px" });
|
||||
|
||||
} else {
|
||||
dijit.byId("content-insert").domNode.setStyle(
|
||||
{height: getCookie("ttrss_ci_height") + "px" });
|
||||
}
|
||||
}
|
||||
|
||||
dijit.byId("main").resize();
|
||||
|
||||
var tmph = dojo.connect(dijit.byId('feeds-holder'), 'resize',
|
||||
function (args) {
|
||||
setCookie("ttrss_fh_width", args.w, getInitParam("cookie_lifetime"));
|
||||
if (args && args.w >= 0) {
|
||||
setCookie("ttrss_fh_width", args.w, getInitParam("cookie_lifetime"));
|
||||
}
|
||||
});
|
||||
|
||||
var tmph = dojo.connect(dijit.byId('content-insert'), 'resize',
|
||||
function (args) {
|
||||
setCookie("ttrss_ci_width", args.w, getInitParam("cookie_lifetime"));
|
||||
setCookie("ttrss_ci_height", args.h, getInitParam("cookie_lifetime"));
|
||||
if (args && args.w >= 0 && args.h >= 0) {
|
||||
setCookie("ttrss_ci_width", args.w, getInitParam("cookie_lifetime"));
|
||||
setCookie("ttrss_ci_height", args.h, getInitParam("cookie_lifetime"));
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -617,6 +621,9 @@ function init_second_stage() {
|
||||
hotkeys[1] = tmp;
|
||||
setInitParam("hotkeys", hotkeys);
|
||||
|
||||
_widescreen_mode = getInitParam("widescreen");
|
||||
switchPanelMode(_widescreen_mode);
|
||||
|
||||
console.log("second stage ok");
|
||||
|
||||
if (getInitParam("simple_update")) {
|
||||
@@ -699,6 +706,10 @@ function quickMenuGo(opid) {
|
||||
if (!isCdmMode()) {
|
||||
_widescreen_mode = !_widescreen_mode;
|
||||
|
||||
// reset stored sizes because geometry changed
|
||||
setCookie("ttrss_ci_width", 0);
|
||||
setCookie("ttrss_ci_height", 0);
|
||||
|
||||
switchPanelMode(_widescreen_mode);
|
||||
}
|
||||
break;
|
||||
@@ -844,11 +855,16 @@ function hotkey_handler(e) {
|
||||
|
||||
var keycode = false;
|
||||
var shift_key = false;
|
||||
var ctrl_key = false;
|
||||
var alt_key = false;
|
||||
var meta_key = false;
|
||||
|
||||
var cmdline = $('cmdline');
|
||||
|
||||
shift_key = e.shiftKey;
|
||||
ctrl_key = e.ctrlKey;
|
||||
alt_key = e.altKey;
|
||||
meta_key = e.metaKey;
|
||||
|
||||
if (window.event) {
|
||||
keycode = window.event.keyCode;
|
||||
@@ -890,6 +906,8 @@ function hotkey_handler(e) {
|
||||
// ensure ^*char notation
|
||||
if (shift_key) hotkey = "*" + hotkey;
|
||||
if (ctrl_key) hotkey = "^" + hotkey;
|
||||
if (alt_key) hotkey = "+" + hotkey;
|
||||
if (meta_key) hotkey = "%" + hotkey;
|
||||
|
||||
hotkey = hotkey_prefix ? hotkey_prefix + " " + hotkey : hotkey;
|
||||
hotkey_prefix = false;
|
||||
@@ -975,6 +993,12 @@ function handle_rpc_json(transport, scheduled_call) {
|
||||
try {
|
||||
var reply = JSON.parse(transport.responseText);
|
||||
|
||||
var netalert_dijit = dijit.byId("net-alert");
|
||||
var netalert = false;
|
||||
|
||||
if (netalert_dijit)
|
||||
netalert = netalert_dijit.domNode;
|
||||
|
||||
if (reply) {
|
||||
|
||||
var error = reply['error'];
|
||||
@@ -1021,16 +1045,21 @@ function handle_rpc_json(transport, scheduled_call) {
|
||||
if (runtime_info)
|
||||
parse_runtime_info(runtime_info);
|
||||
|
||||
Element.hide(dijit.byId("net-alert").domNode);
|
||||
if (netalert) Element.hide(netalert);
|
||||
|
||||
} else {
|
||||
//notify_error("Error communicating with server.");
|
||||
Element.show(dijit.byId("net-alert").domNode);
|
||||
if (netalert)
|
||||
Element.show(netalert);
|
||||
else
|
||||
notify_error("Communication problem with server.");
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
Element.show(dijit.byId("net-alert").domNode);
|
||||
//notify_error("Error communicating with server.");
|
||||
if (netalert)
|
||||
Element.show(netalert);
|
||||
else
|
||||
notify_error("Communication problem with server.");
|
||||
|
||||
console.log(e);
|
||||
//exception_error("handle_rpc_json", e, transport);
|
||||
}
|
||||
@@ -1050,11 +1079,13 @@ function switchPanelMode(wide) {
|
||||
|
||||
dijit.byId("content-insert").domNode.setStyle({width: '50%',
|
||||
height: 'auto',
|
||||
borderLeftWidth: '1px',
|
||||
borderLeftColor: '#c0c0c0',
|
||||
borderTopWidth: '0px' });
|
||||
|
||||
$("headlines-toolbar").setStyle({ borderBottomWidth: '0px' });
|
||||
if (parseInt(getCookie("ttrss_ci_width")) > 0) {
|
||||
dijit.byId("content-insert").domNode.setStyle(
|
||||
{width: getCookie("ttrss_ci_width") + "px" });
|
||||
}
|
||||
|
||||
$("headlines-frame").setStyle({ borderBottomWidth: '0px' });
|
||||
$("headlines-frame").addClassName("wide");
|
||||
|
||||
@@ -1064,10 +1095,12 @@ function switchPanelMode(wide) {
|
||||
|
||||
dijit.byId("content-insert").domNode.setStyle({width: 'auto',
|
||||
height: '50%',
|
||||
borderLeftWidth: '0px',
|
||||
borderTopWidth: '1px'});
|
||||
borderTopWidth: '0px'});
|
||||
|
||||
$("headlines-toolbar").setStyle({ borderBottomWidth: '1px' });
|
||||
if (parseInt(getCookie("ttrss_ci_height")) > 0) {
|
||||
dijit.byId("content-insert").domNode.setStyle(
|
||||
{height: getCookie("ttrss_ci_height") + "px" });
|
||||
}
|
||||
|
||||
$("headlines-frame").setStyle({ borderBottomWidth: '1px' });
|
||||
$("headlines-frame").removeClassName("wide");
|
||||
|
||||
481
js/viewfeed.js
@@ -87,8 +87,12 @@ function headlines_callback2(transport, offset, background, infscroll_req) {
|
||||
dijit.byId("headlines-frame").attr('content',
|
||||
reply['headlines']['content']);
|
||||
|
||||
dijit.byId("headlines-toolbar").attr('content',
|
||||
reply['headlines']['toolbar']);
|
||||
//dijit.byId("headlines-toolbar").attr('content',
|
||||
// reply['headlines']['toolbar']);
|
||||
|
||||
dojo.html.set($("headlines-toolbar"),
|
||||
reply['headlines']['toolbar'],
|
||||
{parseContent: true});
|
||||
|
||||
$$("#headlines-frame > div[id*=RROW]").each(function(row) {
|
||||
if (loaded_article_ids.indexOf(row.id) != -1) {
|
||||
@@ -104,6 +108,10 @@ function headlines_callback2(transport, offset, background, infscroll_req) {
|
||||
|
||||
initHeadlinesMenu();
|
||||
|
||||
if (_infscroll_disable)
|
||||
hsp.innerHTML = "<a href='#' onclick='openNextUnreadFeed()'>" +
|
||||
__("Click to open next unread feed.") + "</a>";
|
||||
|
||||
if (_search_query) {
|
||||
$("feed_title").innerHTML += "<span id='cancel_search'>" +
|
||||
" (<a href='#' onclick='cancelSearch()'>" + __("Cancel search") + "</a>)" +
|
||||
@@ -143,9 +151,9 @@ function headlines_callback2(transport, offset, background, infscroll_req) {
|
||||
|
||||
if (!hsp) hsp = new Element("DIV", {"id": "headlines-spacer"});
|
||||
|
||||
if (getInitParam("cdm_auto_catchup") == 1) {
|
||||
// if (getInitParam("cdm_auto_catchup") == 1) {
|
||||
c.domNode.appendChild(hsp);
|
||||
}
|
||||
// }
|
||||
|
||||
console.log("added " + new_elems.size() + " headlines");
|
||||
|
||||
@@ -172,7 +180,8 @@ function headlines_callback2(transport, offset, background, infscroll_req) {
|
||||
|
||||
var hsp = $("headlines-spacer");
|
||||
|
||||
if (hsp) hsp.innerHTML = "";
|
||||
if (hsp) hsp.innerHTML = "<a href='#' onclick='openNextUnreadFeed()'>" +
|
||||
__("Click to open next unread feed.") + "</a>";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,14 +199,11 @@ function headlines_callback2(transport, offset, background, infscroll_req) {
|
||||
else
|
||||
request_counters(true);
|
||||
|
||||
} else if (transport.responseText) {
|
||||
} else {
|
||||
console.error("Invalid object received: " + transport.responseText);
|
||||
dijit.byId("headlines-frame").attr('content', "<div class='whiteBox'>" +
|
||||
__('Could not update headlines (invalid object received - see error console for details)') +
|
||||
"</div>");
|
||||
} else {
|
||||
//notify_error("Error communicating with server.");
|
||||
Element.show(dijit.byId("net-alert").domNode);
|
||||
}
|
||||
|
||||
_infscroll_request_sent = 0;
|
||||
@@ -314,13 +320,11 @@ function article_callback2(transport, id) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
} else if (transport.responseText) {
|
||||
} else {
|
||||
console.error("Invalid object received: " + transport.responseText);
|
||||
|
||||
render_article("<div class='whiteBox'>" +
|
||||
__('Could not display article (invalid object received - see error console for details)') + "</div>");
|
||||
} else {
|
||||
Element.show(dijit.byId("net-alert").domNode);
|
||||
}
|
||||
|
||||
var unread_in_buffer = $$("#headlines-frame > div[id*=RROW][class*=Unread]").length
|
||||
@@ -835,6 +839,8 @@ function selectionToggleUnread(set_state, callback, no_error, ids) {
|
||||
}
|
||||
}
|
||||
|
||||
updateFloatingTitle(true);
|
||||
|
||||
if (rows.length > 0) {
|
||||
|
||||
var cmode = "";
|
||||
@@ -959,10 +965,12 @@ function getLoadedArticleIds() {
|
||||
}
|
||||
|
||||
// mode = all,none,unread,invert,marked,published
|
||||
function selectArticles(mode) {
|
||||
function selectArticles(mode, query) {
|
||||
try {
|
||||
|
||||
var children = $$("#headlines-frame > div[id*=RROW]");
|
||||
if (!query) query = "#headlines-frame > div[id*=RROW]";
|
||||
|
||||
var children = $$(query);
|
||||
|
||||
children.each(function(child) {
|
||||
var id = child.id.replace("RROW-", "");
|
||||
@@ -1241,7 +1249,7 @@ function postMouseOut(id) {
|
||||
|
||||
function unpackVisibleHeadlines() {
|
||||
try {
|
||||
if (!isCdmMode()) return;
|
||||
if (!isCdmMode() || !getInitParam("cdm_expanded")) return;
|
||||
|
||||
$$("#headlines-frame > div[id*=RROW]").each(
|
||||
function(child) {
|
||||
@@ -1273,15 +1281,17 @@ function headlines_scroll_handler(e) {
|
||||
unpackVisibleHeadlines();
|
||||
|
||||
// set topmost child in the buffer as active
|
||||
if (getInitParam("cdm_auto_catchup") == 1 &&
|
||||
(!isCdmMode() || getInitParam("cdm_expanded"))) {
|
||||
if (isCdmMode() && getInitParam("cdm_auto_catchup") == 1 &&
|
||||
getSelectedArticleIds2().length <= 1 &&
|
||||
getInitParam("cdm_expanded")) {
|
||||
var rows = $$("#headlines-frame > div[id*=RROW]");
|
||||
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var child = rows[i];
|
||||
|
||||
if ($("headlines-frame").scrollTop < child.offsetTop &&
|
||||
child.offsetTop - $("headlines-frame").scrollTop < 100) {
|
||||
if ($("headlines-frame").scrollTop <= child.offsetTop &&
|
||||
child.offsetTop - $("headlines-frame").scrollTop < 100 &&
|
||||
child.id.replace("RROW-", "") != _active_article_id) {
|
||||
|
||||
if (_active_article_id) {
|
||||
var row = $("RROW-" + _active_article_id);
|
||||
@@ -1302,18 +1312,23 @@ function headlines_scroll_handler(e) {
|
||||
((e.scrollTop + e.offsetHeight) / e.scrollHeight >= 0.7))) {
|
||||
|
||||
if (hsp)
|
||||
hsp.innerHTML = "<img src='images/indicator_tiny.gif'> " +
|
||||
__("Loading, please wait...");
|
||||
hsp.innerHTML = "<span class='loading'><img src='images/indicator_tiny.gif'> " +
|
||||
__("Loading, please wait...") + "</span>";
|
||||
|
||||
loadMoreHeadlines();
|
||||
return;
|
||||
|
||||
}
|
||||
} else {
|
||||
if (hsp) hsp.innerHTML = "";
|
||||
if (hsp)
|
||||
if (_infscroll_disable)
|
||||
hsp.innerHTML = "<a href='#' onclick='openNextUnreadFeed()'>" +
|
||||
__("Click to open next unread feed.") + "</a>";
|
||||
else
|
||||
hsp.innerHTML = "";
|
||||
}
|
||||
|
||||
if (getInitParam("cdm_expanded") && isCdmMode()) {
|
||||
if (isCdmMode()) {
|
||||
updateFloatingTitle();
|
||||
}
|
||||
|
||||
@@ -1346,6 +1361,20 @@ function headlines_scroll_handler(e) {
|
||||
500);
|
||||
}
|
||||
}
|
||||
|
||||
if (_infscroll_disable) {
|
||||
var child = $$("#headlines-frame div[id*=RROW]").last();
|
||||
|
||||
if (child && $("headlines-frame").scrollTop >
|
||||
(child.offsetTop + child.offsetHeight - 50)) {
|
||||
|
||||
console.log("we seem to be at an end");
|
||||
|
||||
if (getInitParam("on_catchup_show_next_feed") == "1") {
|
||||
openNextUnreadFeed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
@@ -1353,6 +1382,16 @@ function headlines_scroll_handler(e) {
|
||||
}
|
||||
}
|
||||
|
||||
function openNextUnreadFeed() {
|
||||
try {
|
||||
var is_cat = activeFeedIsCat();
|
||||
var nuf = getNextUnreadFeed(getActiveFeedId(), is_cat);
|
||||
if (nuf) viewfeed(nuf, '', is_cat);
|
||||
} catch (e) {
|
||||
exception_error("openNextUnreadFeed", e);
|
||||
}
|
||||
}
|
||||
|
||||
function catchupBatchedArticles() {
|
||||
try {
|
||||
if (catchup_id_batch.length > 0 && !_infscroll_request_sent) {
|
||||
@@ -1379,6 +1418,8 @@ function catchupBatchedArticles() {
|
||||
catchup_id_batch.remove(id);
|
||||
});
|
||||
|
||||
updateFloatingTitle(true);
|
||||
|
||||
} });
|
||||
}
|
||||
|
||||
@@ -1487,6 +1528,12 @@ function cdmCollapseArticle(event, id, unmark) {
|
||||
if (event) Event.stop(event);
|
||||
|
||||
PluginHost.run(PluginHost.HOOK_ARTICLE_COLLAPSED, id);
|
||||
|
||||
if (row.offsetTop < $("headlines-frame").scrollTop)
|
||||
scrollToRowId(row.id);
|
||||
|
||||
Element.hide("floatingTitle");
|
||||
$("floatingTitle").setAttribute("rowid", false);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
@@ -1591,9 +1638,9 @@ function show_labels_in_headlines(transport) {
|
||||
|
||||
if (data) {
|
||||
data['info-for-headlines'].each(function(elem) {
|
||||
var ctr = $("HLLCTR-" + elem.id);
|
||||
|
||||
if (ctr) ctr.innerHTML = elem.labels;
|
||||
$$(".HLLCTR-" + elem.id).each(function(ctr) {
|
||||
ctr.innerHTML = elem.labels;
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -1611,6 +1658,12 @@ function dismissArticle(id) {
|
||||
|
||||
new Effect.Fade(elem, {duration : 0.5});
|
||||
|
||||
// Remove the content, too
|
||||
var elem_content = $("CICD-" + id);
|
||||
if (elem_content) {
|
||||
Element.remove(elem_content);
|
||||
}
|
||||
|
||||
if (id == getActiveArticleId()) {
|
||||
setActiveArticleId(0);
|
||||
}
|
||||
@@ -1634,6 +1687,12 @@ function dismissSelectedArticles() {
|
||||
ids[i] != getActiveArticleId()) {
|
||||
new Effect.Fade(elem, {duration : 0.5});
|
||||
sel.push(ids[i]);
|
||||
|
||||
// Remove the content, too
|
||||
var elem_content = $("CICD-" + ids[i]);
|
||||
if (elem_content) {
|
||||
Element.remove(elem_content);
|
||||
}
|
||||
} else {
|
||||
tmp.push(ids[i]);
|
||||
}
|
||||
@@ -1661,13 +1720,19 @@ function dismissReadArticles() {
|
||||
!elem.hasClassName("Selected")) {
|
||||
|
||||
new Effect.Fade(elem, {duration : 0.5});
|
||||
|
||||
// Remove the content, too
|
||||
var elem_content = $("CICD-" + ids[i]);
|
||||
if (elem_content) {
|
||||
Element.remove(elem_content);
|
||||
}
|
||||
} else {
|
||||
tmp.push(ids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
exception_error("dismissSelectedArticles", e);
|
||||
exception_error("dismissReadArticles", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1716,6 +1781,7 @@ function cdmClicked(event, id) {
|
||||
|
||||
if (article_is_unread) {
|
||||
decrementFeedCounter(getActiveFeedId(), activeFeedIsCat());
|
||||
updateFloatingTitle(true);
|
||||
}
|
||||
|
||||
var query = "?op=rpc&method=catchupSelected" +
|
||||
@@ -1730,7 +1796,8 @@ function cdmClicked(event, id) {
|
||||
return !event.shiftKey;
|
||||
}
|
||||
|
||||
} else {
|
||||
} else if (event.target.parents(".cdmHeader").length > 0) {
|
||||
|
||||
toggleSelected(id, true);
|
||||
|
||||
var elem = $("RROW-" + id);
|
||||
@@ -1890,6 +1957,153 @@ function closeArticlePanel() {
|
||||
dijit.byId("content-insert"));
|
||||
}
|
||||
|
||||
function initFloatingMenu() {
|
||||
try {
|
||||
if (dijit.byId("floatingMenu"))
|
||||
dijit.byId("floatingMenu").destroyRecursive();
|
||||
|
||||
var menu = new dijit.Menu({
|
||||
id: "floatingMenu",
|
||||
targetNodeIds: ["floatingTitle"]
|
||||
});
|
||||
|
||||
var id = $("floatingTitle").getAttribute("rowid").replace("RROW-", "");
|
||||
|
||||
headlinesMenuCommon(menu, id);
|
||||
|
||||
menu.startup();
|
||||
} catch (e) {
|
||||
exception_error("initFloatingMenu", e);
|
||||
}
|
||||
}
|
||||
|
||||
function headlinesMenuCommon(menu, base_id) {
|
||||
try {
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Open original article"),
|
||||
onClick: function(event) {
|
||||
openArticleInNewWindow(base_id ? base_id : this.getParent().callerRowId);
|
||||
}}));
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Display article URL"),
|
||||
onClick: function(event) {
|
||||
displayArticleUrl(base_id ? base_id : this.getParent().callerRowId);
|
||||
}}));
|
||||
|
||||
menu.addChild(new dijit.MenuSeparator());
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Toggle unread"),
|
||||
onClick: function(event) {
|
||||
var ids = getSelectedArticleIds2();
|
||||
// cast to string
|
||||
var id = (base_id ? base_id : this.getParent().callerRowId) + "";
|
||||
ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
|
||||
|
||||
selectionToggleUnread(undefined, false, true, ids);
|
||||
}}));
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Toggle starred"),
|
||||
onClick: function(event) {
|
||||
var ids = getSelectedArticleIds2();
|
||||
// cast to string
|
||||
var id = (base_id ? base_id : this.getParent().callerRowId) + "";
|
||||
ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
|
||||
|
||||
selectionToggleMarked(undefined, false, true, ids);
|
||||
}}));
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Toggle published"),
|
||||
onClick: function(event) {
|
||||
var ids = getSelectedArticleIds2();
|
||||
// cast to string
|
||||
var id = (base_id ? base_id : this.getParent().callerRowId) + "";
|
||||
ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
|
||||
|
||||
selectionTogglePublished(undefined, false, true, ids);
|
||||
}}));
|
||||
|
||||
menu.addChild(new dijit.MenuSeparator());
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Mark above as read"),
|
||||
onClick: function(event) {
|
||||
catchupRelativeToArticle(0, base_id ? base_id : this.getParent().callerRowId);
|
||||
}}));
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Mark below as read"),
|
||||
onClick: function(event) {
|
||||
catchupRelativeToArticle(1, base_id ? base_id : this.getParent().callerRowId);
|
||||
}}));
|
||||
|
||||
|
||||
var labels = dijit.byId("feedTree").model.getItemsInCategory(-2);
|
||||
|
||||
if (labels) {
|
||||
|
||||
menu.addChild(new dijit.MenuSeparator());
|
||||
|
||||
var labelAddMenu = new dijit.Menu({ownerMenu: menu});
|
||||
var labelDelMenu = new dijit.Menu({ownerMenu: menu});
|
||||
|
||||
labels.each(function(label) {
|
||||
var id = label.id[0];
|
||||
var bare_id = id.substr(id.indexOf(":")+1);
|
||||
var name = label.name[0];
|
||||
|
||||
bare_id = feed_to_label_id(bare_id);
|
||||
|
||||
labelAddMenu.addChild(new dijit.MenuItem({
|
||||
label: name,
|
||||
labelId: bare_id,
|
||||
onClick: function(event) {
|
||||
var ids = getSelectedArticleIds2();
|
||||
// cast to string
|
||||
var id = (base_id ? base_id : this.getParent().ownerMenu.callerRowId) + "";
|
||||
|
||||
ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
|
||||
|
||||
selectionAssignLabel(this.labelId, ids);
|
||||
}}));
|
||||
|
||||
labelDelMenu.addChild(new dijit.MenuItem({
|
||||
label: name,
|
||||
labelId: bare_id,
|
||||
onClick: function(event) {
|
||||
var ids = getSelectedArticleIds2();
|
||||
// cast to string
|
||||
var id = (base_id ? base_id : this.getParent().ownerMenu.callerRowId) + "";
|
||||
|
||||
ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
|
||||
|
||||
selectionRemoveLabel(this.labelId, ids);
|
||||
}}));
|
||||
|
||||
});
|
||||
|
||||
menu.addChild(new dijit.PopupMenuItem({
|
||||
label: __("Assign label"),
|
||||
popup: labelAddMenu,
|
||||
}));
|
||||
|
||||
menu.addChild(new dijit.PopupMenuItem({
|
||||
label: __("Remove label"),
|
||||
popup: labelDelMenu,
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
|
||||
} catch (e) {
|
||||
exception_error("headlinesMenuCommon", e);
|
||||
}
|
||||
}
|
||||
|
||||
function initHeadlinesMenu() {
|
||||
try {
|
||||
if (dijit.byId("headlinesMenu"))
|
||||
@@ -1925,133 +2139,76 @@ function initHeadlinesMenu() {
|
||||
|
||||
});
|
||||
|
||||
/* if (!isCdmMode())
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("View article"),
|
||||
onClick: function(event) {
|
||||
view(this.getParent().callerRowId);
|
||||
}})); */
|
||||
headlinesMenuCommon(menu, false);
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Open original article"),
|
||||
onClick: function(event) {
|
||||
openArticleInNewWindow(this.getParent().callerRowId);
|
||||
}}));
|
||||
menu.startup();
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Display article URL"),
|
||||
onClick: function(event) {
|
||||
displayArticleUrl(this.getParent().callerRowId);
|
||||
}}));
|
||||
/* vgroup feed title menu */
|
||||
|
||||
menu.addChild(new dijit.MenuSeparator());
|
||||
var nodes = $$("#headlines-frame > div[class='cdmFeedTitle']");
|
||||
var ids = [];
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Toggle unread"),
|
||||
onClick: function(event) {
|
||||
var ids = getSelectedArticleIds2();
|
||||
// cast to string
|
||||
var id = this.getParent().callerRowId + "";
|
||||
ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
|
||||
nodes.each(function(node) {
|
||||
ids.push(node.id);
|
||||
});
|
||||
|
||||
selectionToggleUnread(undefined, false, true, ids);
|
||||
}}));
|
||||
if (ids.length > 0) {
|
||||
if (dijit.byId("headlinesFeedTitleMenu"))
|
||||
dijit.byId("headlinesFeedTitleMenu").destroyRecursive();
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Toggle starred"),
|
||||
onClick: function(event) {
|
||||
var ids = getSelectedArticleIds2();
|
||||
// cast to string
|
||||
var id = this.getParent().callerRowId + "";
|
||||
ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
|
||||
var menu = new dijit.Menu({
|
||||
id: "headlinesFeedTitleMenu",
|
||||
targetNodeIds: ids,
|
||||
});
|
||||
|
||||
selectionToggleMarked(undefined, false, true, ids);
|
||||
}}));
|
||||
var tmph = dojo.connect(menu, '_openMyself', function (event) {
|
||||
var callerNode = event.target, match = null, tries = 0;
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Toggle published"),
|
||||
onClick: function(event) {
|
||||
var ids = getSelectedArticleIds2();
|
||||
// cast to string
|
||||
var id = this.getParent().callerRowId + "";
|
||||
ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
|
||||
while (match == null && callerNode && tries <= 3) {
|
||||
console.log(callerNode.id);
|
||||
|
||||
selectionTogglePublished(undefined, false, true, ids);
|
||||
}}));
|
||||
match = callerNode.id.match("^[A-Z]+[-]([0-9]+)$");
|
||||
callerNode = callerNode.parentNode;
|
||||
++tries;
|
||||
|
||||
menu.addChild(new dijit.MenuSeparator());
|
||||
console.log(match[1]);
|
||||
}
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Mark above as read"),
|
||||
onClick: function(event) {
|
||||
catchupRelativeToArticle(0, this.getParent().callerRowId);
|
||||
}}));
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Mark below as read"),
|
||||
onClick: function(event) {
|
||||
catchupRelativeToArticle(1, this.getParent().callerRowId);
|
||||
}}));
|
||||
|
||||
|
||||
var labels = dijit.byId("feedTree").model.getItemsInCategory(-2);
|
||||
|
||||
if (labels) {
|
||||
|
||||
menu.addChild(new dijit.MenuSeparator());
|
||||
|
||||
var labelAddMenu = new dijit.Menu({ownerMenu: menu});
|
||||
var labelDelMenu = new dijit.Menu({ownerMenu: menu});
|
||||
|
||||
labels.each(function(label) {
|
||||
var id = label.id[0];
|
||||
var bare_id = id.substr(id.indexOf(":")+1);
|
||||
var name = label.name[0];
|
||||
|
||||
bare_id = feed_to_label_id(bare_id);
|
||||
|
||||
labelAddMenu.addChild(new dijit.MenuItem({
|
||||
label: name,
|
||||
labelId: bare_id,
|
||||
onClick: function(event) {
|
||||
var ids = getSelectedArticleIds2();
|
||||
// cast to string
|
||||
var id = this.getParent().ownerMenu.callerRowId + "";
|
||||
|
||||
ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
|
||||
|
||||
selectionAssignLabel(this.labelId, ids);
|
||||
}}));
|
||||
|
||||
labelDelMenu.addChild(new dijit.MenuItem({
|
||||
label: name,
|
||||
labelId: bare_id,
|
||||
onClick: function(event) {
|
||||
var ids = getSelectedArticleIds2();
|
||||
// cast to string
|
||||
var id = this.getParent().ownerMenu.callerRowId + "";
|
||||
|
||||
ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id];
|
||||
|
||||
selectionRemoveLabel(this.labelId, ids);
|
||||
}}));
|
||||
if (match) this.callerRowId = parseInt(match[1]);
|
||||
|
||||
});
|
||||
|
||||
menu.addChild(new dijit.PopupMenuItem({
|
||||
label: __("Assign label"),
|
||||
popup: labelAddMenu,
|
||||
}));
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Select articles in group"),
|
||||
onClick: function(event) {
|
||||
selectArticles("all",
|
||||
"#headlines-frame > div[id*=RROW]"+
|
||||
"[orig-feed-id='"+menu.callerRowId+"']");
|
||||
|
||||
menu.addChild(new dijit.PopupMenuItem({
|
||||
label: __("Remove label"),
|
||||
popup: labelDelMenu,
|
||||
}));
|
||||
}}));
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Mark group as read"),
|
||||
onClick: function(event) {
|
||||
selectArticles("none");
|
||||
selectArticles("all",
|
||||
"#headlines-frame > div[id*=RROW]"+
|
||||
"[orig-feed-id='"+menu.callerRowId+"']");
|
||||
|
||||
catchupSelection();
|
||||
}}));
|
||||
|
||||
|
||||
menu.addChild(new dijit.MenuItem({
|
||||
label: __("Mark feed as read"),
|
||||
onClick: function(event) {
|
||||
catchupFeedInGroup(menu.callerRowId);
|
||||
}}));
|
||||
|
||||
menu.startup();
|
||||
|
||||
}
|
||||
|
||||
menu.startup();
|
||||
|
||||
} catch (e) {
|
||||
exception_error("initHeadlinesMenu", e);
|
||||
}
|
||||
@@ -2195,33 +2352,67 @@ function openSelectedAttachment(elem) {
|
||||
}
|
||||
}
|
||||
|
||||
function updateFloatingTitle() {
|
||||
function scrollToRowId(id) {
|
||||
try {
|
||||
var row = $(id);
|
||||
|
||||
if (row)
|
||||
$("headlines-frame").scrollTop = row.offsetTop;
|
||||
|
||||
} catch (e) {
|
||||
exception_error("scrollToRowId", e);
|
||||
}
|
||||
}
|
||||
|
||||
function updateFloatingTitle(unread_only) {
|
||||
try {
|
||||
if (!isCdmMode()) return;
|
||||
|
||||
var hf = $("headlines-frame");
|
||||
|
||||
var elems = $$("#headlines-frame > div[id*=RROW]");
|
||||
|
||||
for (var i = 0; i < elems.length; i++) {
|
||||
|
||||
var child = elems[i];
|
||||
|
||||
if (child.offsetTop + child.offsetHeight > hf.scrollTop) {
|
||||
if (child && child.offsetTop + child.offsetHeight > hf.scrollTop) {
|
||||
|
||||
var header = child.getElementsByClassName("cdmHeader")[0];
|
||||
|
||||
if (child.id != $("floatingTitle").getAttribute("rowid")) {
|
||||
$("floatingTitle").setAttribute("rowid", child.id);
|
||||
$("floatingTitle").innerHTML = header.innerHTML;
|
||||
if (unread_only || child.id != $("floatingTitle").getAttribute("rowid")) {
|
||||
if (child.id != $("floatingTitle").getAttribute("rowid")) {
|
||||
$("floatingTitle").setAttribute("rowid", child.id);
|
||||
$("floatingTitle").innerHTML = header.innerHTML;
|
||||
$("floatingTitle").firstChild.innerHTML = "<img class='anchor markedPic' src='images/page_white_go.png' onclick=\"scrollToRowId('"+child.id+"')\">" + $("floatingTitle").firstChild.innerHTML;
|
||||
|
||||
initFloatingMenu();
|
||||
|
||||
var cb = $$("#floatingTitle .dijitCheckBox")[0];
|
||||
|
||||
if (cb)
|
||||
cb.parentNode.removeChild(cb);
|
||||
}
|
||||
|
||||
if (child.hasClassName("Unread"))
|
||||
$("floatingTitle").addClassName("Unread");
|
||||
else
|
||||
$("floatingTitle").removeClassName("Unread");
|
||||
|
||||
PluginHost.run(PluginHost.HOOK_FLOATING_TITLE, child);
|
||||
}
|
||||
|
||||
if (child.offsetTop < hf.scrollTop - header.offsetHeight - 100 &&
|
||||
child.offsetTop + child.offsetHeight - hf.scrollTop > 100)
|
||||
if (child.offsetTop < hf.scrollTop - header.offsetHeight &&
|
||||
child.offsetTop + child.offsetHeight - hf.scrollTop > header.offsetHeight)
|
||||
Element.show("floatingTitle");
|
||||
else
|
||||
Element.hide("floatingTitle");
|
||||
|
||||
break;
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
exception_error("updateFloatingTitle", e);
|
||||
}
|
||||
|
||||
20
lib/floIcon.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
// Compatibility shim for hooking up jimIcon to Tiny Tiny RSS.
|
||||
|
||||
require_once "jimIcon.php";
|
||||
|
||||
class floIconIcon {
|
||||
function getImageResource() {
|
||||
return $this->img;
|
||||
}
|
||||
}
|
||||
|
||||
class floIcon {
|
||||
function readICO($file) {
|
||||
$jim = new jimIcon();
|
||||
$icon = new floIconIcon();
|
||||
$icon->img = $jim->fromiconstring(file_get_contents($file));
|
||||
$this->images = array($icon);
|
||||
}
|
||||
}
|
||||
?>
|
||||
270
lib/jimIcon.php
Normal file
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
|
||||
// Simple .ICO parsing. The ICO format is insanely complex and this may
|
||||
// fail to correctly handle some technically valid files, but it works
|
||||
// on the majority I've found.
|
||||
//
|
||||
// jimIcon was written in 2013 by Jim Paris <jim@jtan.com> and is
|
||||
// released under the terms of the CC0:
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all
|
||||
// copyright and related and neighboring rights to this software to
|
||||
// the public domain worldwide. This software is distributed without
|
||||
// any arranty.
|
||||
//
|
||||
// You may have received a copy of the CC0 Public Domain Dedication
|
||||
// along with this software. If not, see
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
class jimIcon {
|
||||
// Get an image color from a string
|
||||
function get_color($str, $img) {
|
||||
$b = ord($str[0]);
|
||||
$g = ord($str[1]);
|
||||
$r = ord($str[2]);
|
||||
if (strlen($str) > 3) {
|
||||
$a = 127 - (ord($str[3]) / 2);
|
||||
if ($a != 0 && $a != 127)
|
||||
$this->had_alpha = 1;
|
||||
} else {
|
||||
$a = 0;
|
||||
}
|
||||
if ($a != 127)
|
||||
$this->all_transaprent = 0;
|
||||
return imagecolorallocatealpha($img, $r, $g, $b, $a);
|
||||
}
|
||||
|
||||
// Given a string with the contents of an .ICO,
|
||||
// return a GD image of the icon, or false on error.
|
||||
function fromiconstring($ico) {
|
||||
$this->error = "(unknown error)";
|
||||
$this->had_alpha = 0;
|
||||
|
||||
// Read header
|
||||
if (strlen($ico) < 6) {
|
||||
$this->error = "too short";
|
||||
return false;
|
||||
}
|
||||
$h = unpack("vzero/vtype/vnum", $ico);
|
||||
|
||||
// Must be ICO format with at least one image
|
||||
if ($h["zero"] != 0 || $h["type"] != 1 || $h["num"] == 0) {
|
||||
// See if we can just parse it with GD directly
|
||||
// if it's not ICO format; maybe it was a mislabeled
|
||||
// PNG or something.
|
||||
$i = @imagecreatefromstring($ico);
|
||||
if ($i) {
|
||||
imagesavealpha($i, true);
|
||||
return $i;
|
||||
}
|
||||
$this->error = "not ICO or other image";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read directory entries to find the biggest image
|
||||
$most_pixels = 0;
|
||||
for ($i = 0; $i < $h["num"]; $i++) {
|
||||
$entry = substr($ico, 6 + 16 * $i, 16);
|
||||
if (!$entry || strlen($entry) < 16)
|
||||
continue;
|
||||
$e = unpack("Cwidth/" .
|
||||
"Cheight/" .
|
||||
"Ccolors/" .
|
||||
"Czero/" .
|
||||
"vplanes/" .
|
||||
"vbpp/" .
|
||||
"Vsize/" .
|
||||
"Voffset/",
|
||||
$entry);
|
||||
if ($e["width"] == 0)
|
||||
$e["width"] = 256;
|
||||
if ($e["height"] == 0)
|
||||
$e["height"] = 256;
|
||||
if ($e["zero"] != 0) {
|
||||
$this->error = "nonzero reserved field";
|
||||
return false;
|
||||
}
|
||||
$pixels = $e["width"] * $e["height"];
|
||||
if ($pixels > $most_pixels) {
|
||||
$most_pixels = $pixels;
|
||||
$most = $e;
|
||||
}
|
||||
}
|
||||
if ($most_pixels == 0) {
|
||||
$this->error = "no pixels";
|
||||
return false;
|
||||
}
|
||||
$e = $most;
|
||||
|
||||
// Extract image data
|
||||
$data = substr($ico, $e["offset"], $e["size"]);
|
||||
if (!$data || strlen($data) != $e["size"]) {
|
||||
$this->error = "bad image data";
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if we can parse it (might be PNG format here)
|
||||
$i = @imagecreatefromstring($data);
|
||||
if ($i) {
|
||||
imagesavealpha($img, true);
|
||||
return $i;
|
||||
}
|
||||
|
||||
// Must be a BMP. Parse it ourselves.
|
||||
$img = imagecreatetruecolor($e["width"], $e["height"]);
|
||||
imagesavealpha($img, true);
|
||||
$bg = imagecolorallocatealpha($img, 255, 0, 0, 127);
|
||||
imagefill($img, 0, 0, $bg);
|
||||
|
||||
// Skip over the BITMAPCOREHEADER or BITMAPINFOHEADER;
|
||||
// we'll just assume the palette and pixel data follow
|
||||
// in the most obvious format as described by the icon
|
||||
// directory entry.
|
||||
$bitmapinfo = unpack("Vsize", $data);
|
||||
if ($bitmapinfo["size"] == 40) {
|
||||
$info = unpack("Vsize/" .
|
||||
"Vwidth/" .
|
||||
"Vheight/" .
|
||||
"vplanes/" .
|
||||
"vbpp/" .
|
||||
"Vcompress/" .
|
||||
"Vsize/" .
|
||||
"Vxres/" .
|
||||
"Vyres/" .
|
||||
"Vpalcolors/" .
|
||||
"Vimpcolors/", $data);
|
||||
if ($e["bpp"] == 0) {
|
||||
$e["bpp"] = $info["bpp"];
|
||||
}
|
||||
}
|
||||
$data = substr($data, $bitmapinfo["size"]);
|
||||
|
||||
$height = $e["height"];
|
||||
$width = $e["width"];
|
||||
$bpp = $e["bpp"];
|
||||
|
||||
// For indexed images, we only support 1, 4, or 8 BPP
|
||||
switch ($bpp) {
|
||||
case 1:
|
||||
case 4:
|
||||
case 8:
|
||||
$indexed = 1;
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
$indexed = 0;
|
||||
break;
|
||||
default:
|
||||
$this->error = "bad BPP $bpp";
|
||||
return false;
|
||||
}
|
||||
|
||||
$offset = 0;
|
||||
if ($indexed) {
|
||||
$palette = array();
|
||||
$this->all_transparent = 1;
|
||||
for ($i = 0; $i < (1 << $bpp); $i++) {
|
||||
$entry = substr($data, $i * 4, 4);
|
||||
$palette[$i] = $this->get_color($entry, $img);
|
||||
}
|
||||
$offset = $i * 4;
|
||||
|
||||
// Hack for some icons: if everything was transparent,
|
||||
// discard alpha channel.
|
||||
if ($this->all_transparent) {
|
||||
for ($i = 0; $i < (1 << $bpp); $i++) {
|
||||
$palette[$i] &= 0xffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assume image data follows in bottom-up order.
|
||||
// First the "XOR" image
|
||||
if ((strlen($data) - $offset) < ($bpp * $height * $width / 8)) {
|
||||
$this->error = "short data";
|
||||
return false;
|
||||
}
|
||||
$XOR = array();
|
||||
for ($y = $height - 1; $y >= 0; $y--) {
|
||||
$x = 0;
|
||||
while ($x < $width) {
|
||||
if (!$indexed) {
|
||||
$bytes = $bpp / 8;
|
||||
$entry = substr($data, $offset, $bytes);
|
||||
$pixel = $this->get_color($entry, $img);
|
||||
$XOR[$y][$x] = $pixel;
|
||||
$x++;
|
||||
$offset += $bytes;
|
||||
} elseif ($bpp == 1) {
|
||||
$p = ord($data[$offset]);
|
||||
for ($b = 0x80; $b > 0; $b >>= 1) {
|
||||
if ($p & $b) {
|
||||
$pixel = $palette[1];
|
||||
} else {
|
||||
$pixel = $palette[0];
|
||||
}
|
||||
$XOR[$y][$x] = $pixel;
|
||||
$x++;
|
||||
}
|
||||
$offset++;
|
||||
} elseif ($bpp == 4) {
|
||||
$p = ord($data[$offset]);
|
||||
$pixel1 = $palette[$p >> 4];
|
||||
$pixel2 = $palette[$p & 0x0f];
|
||||
$XOR[$y][$x] = $pixel1;
|
||||
$XOR[$y][$x+1] = $pixel2;
|
||||
$x += 2;
|
||||
$offset++;
|
||||
} elseif ($bpp == 8) {
|
||||
$pixel = $palette[ord($data[$offset])];
|
||||
$XOR[$y][$x] = $pixel;
|
||||
$x += 1;
|
||||
$offset++;
|
||||
} else {
|
||||
$this->error = "bad BPP";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// End of row padding
|
||||
while ($offset & 3)
|
||||
$offset++;
|
||||
}
|
||||
|
||||
// Now the "AND" image, which is 1 bit per pixel. Ignore
|
||||
// if some of our image data already had alpha values,
|
||||
// or if there isn't enough data left.
|
||||
if ($this->had_alpha ||
|
||||
((strlen($data) - $offset) < ($height * $width / 8))) {
|
||||
// Just return what we've got
|
||||
for ($y = 0; $y < $height; $y++) {
|
||||
for ($x = 0; $x < $width; $x++) {
|
||||
imagesetpixel($img, $x, $y,
|
||||
$XOR[$y][$x]);
|
||||
}
|
||||
}
|
||||
return $img;
|
||||
}
|
||||
|
||||
// Mask what we have with the "AND" image
|
||||
for ($y = $height - 1; $y >= 0; $y--) {
|
||||
$x = 0;
|
||||
while ($x < $width) {
|
||||
for ($b = 0x80;
|
||||
$b > 0 && $x < $width; $b >>= 1) {
|
||||
if (!(ord($data[$offset]) & $b)) {
|
||||
imagesetpixel($img, $x, $y,
|
||||
$XOR[$y][$x]);
|
||||
}
|
||||
$x++;
|
||||
}
|
||||
$offset++;
|
||||
}
|
||||
|
||||
// End of row padding
|
||||
while ($offset & 3)
|
||||
$offset++;
|
||||
}
|
||||
return $img;
|
||||
}
|
||||
}
|
||||
?>
|
||||
1708
lib/languagedetect/LanguageDetect.php
Normal file
57
lib/languagedetect/Text/LanguageDetect/Exception.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
class Text_LanguageDetect_Exception extends Exception
|
||||
{
|
||||
/**
|
||||
* Database file could not be found
|
||||
*/
|
||||
const DB_NOT_FOUND = 10;
|
||||
|
||||
/**
|
||||
* Database file found, but not readable
|
||||
*/
|
||||
const DB_NOT_READABLE = 11;
|
||||
|
||||
/**
|
||||
* Database file is empty
|
||||
*/
|
||||
const DB_EMPTY = 12;
|
||||
|
||||
/**
|
||||
* Database contents is not a PHP array
|
||||
*/
|
||||
const DB_NOT_ARRAY = 13;
|
||||
|
||||
/**
|
||||
* Magic quotes are activated
|
||||
*/
|
||||
const MAGIC_QUOTES = 14;
|
||||
|
||||
|
||||
/**
|
||||
* Parameter of invalid type passed to method
|
||||
*/
|
||||
const PARAM_TYPE = 20;
|
||||
|
||||
/**
|
||||
* Character in parameter is invalid
|
||||
*/
|
||||
const INVALID_CHAR = 21;
|
||||
|
||||
|
||||
/**
|
||||
* Language is not in the database
|
||||
*/
|
||||
const UNKNOWN_LANGUAGE = 30;
|
||||
|
||||
|
||||
/**
|
||||
* Error during block detection
|
||||
*/
|
||||
const BLOCK_DETECTION = 40;
|
||||
|
||||
|
||||
/**
|
||||
* Error while clustering languages
|
||||
*/
|
||||
const NO_HIGHEST_KEY = 50;
|
||||
}
|
||||
341
lib/languagedetect/Text/LanguageDetect/ISO639.php
Normal file
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
/**
|
||||
* Part of Text_LanguageDetect
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Text
|
||||
* @package Text_LanguageDetect
|
||||
* @author Christian Weiske <cweiske@php.net>
|
||||
* @copyright 2011 Christian Weiske <cweiske@php.net>
|
||||
* @license http://www.debian.org/misc/bsd.license BSD
|
||||
* @version SVN: $Id$
|
||||
* @link http://pear.php.net/package/Text_LanguageDetect/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides a mapping between the languages from lang.dat and the
|
||||
* ISO 639-1 and ISO-639-2 codes.
|
||||
*
|
||||
* Note that this class contains only languages that exist in lang.dat.
|
||||
*
|
||||
* @category Text
|
||||
* @package Text_LanguageDetect
|
||||
* @author Christian Weiske <cweiske@php.net>
|
||||
* @copyright 2011 Christian Weiske <cweiske@php.net>
|
||||
* @license http://www.debian.org/misc/bsd.license BSD
|
||||
* @link http://www.loc.gov/standards/iso639-2/php/code_list.php
|
||||
*/
|
||||
class Text_LanguageDetect_ISO639
|
||||
{
|
||||
/**
|
||||
* Maps all language names from the language database to the
|
||||
* ISO 639-1 2-letter language code.
|
||||
*
|
||||
* NULL indicates that there is no 2-letter code.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $nameToCode2 = array(
|
||||
'albanian' => 'sq',
|
||||
'arabic' => 'ar',
|
||||
'azeri' => 'az',
|
||||
'bengali' => 'bn',
|
||||
'bulgarian' => 'bg',
|
||||
'cebuano' => null,
|
||||
'croatian' => 'hr',
|
||||
'czech' => 'cs',
|
||||
'danish' => 'da',
|
||||
'dutch' => 'nl',
|
||||
'english' => 'en',
|
||||
'estonian' => 'et',
|
||||
'farsi' => 'fa',
|
||||
'finnish' => 'fi',
|
||||
'french' => 'fr',
|
||||
'german' => 'de',
|
||||
'hausa' => 'ha',
|
||||
'hawaiian' => null,
|
||||
'hindi' => 'hi',
|
||||
'hungarian' => 'hu',
|
||||
'icelandic' => 'is',
|
||||
'indonesian' => 'id',
|
||||
'italian' => 'it',
|
||||
'kazakh' => 'kk',
|
||||
'kyrgyz' => 'ky',
|
||||
'latin' => 'la',
|
||||
'latvian' => 'lv',
|
||||
'lithuanian' => 'lt',
|
||||
'macedonian' => 'mk',
|
||||
'mongolian' => 'mn',
|
||||
'nepali' => 'ne',
|
||||
'norwegian' => 'no',
|
||||
'pashto' => 'ps',
|
||||
'pidgin' => null,
|
||||
'polish' => 'pl',
|
||||
'portuguese' => 'pt',
|
||||
'romanian' => 'ro',
|
||||
'russian' => 'ru',
|
||||
'serbian' => 'sr',
|
||||
'slovak' => 'sk',
|
||||
'slovene' => 'sl',
|
||||
'somali' => 'so',
|
||||
'spanish' => 'es',
|
||||
'swahili' => 'sw',
|
||||
'swedish' => 'sv',
|
||||
'tagalog' => 'tl',
|
||||
'turkish' => 'tr',
|
||||
'ukrainian' => 'uk',
|
||||
'urdu' => 'ur',
|
||||
'uzbek' => 'uz',
|
||||
'vietnamese' => 'vi',
|
||||
'welsh' => 'cy',
|
||||
);
|
||||
|
||||
/**
|
||||
* Maps all language names from the language database to the
|
||||
* ISO 639-2 3-letter language code.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $nameToCode3 = array(
|
||||
'albanian' => 'sqi',
|
||||
'arabic' => 'ara',
|
||||
'azeri' => 'aze',
|
||||
'bengali' => 'ben',
|
||||
'bulgarian' => 'bul',
|
||||
'cebuano' => 'ceb',
|
||||
'croatian' => 'hrv',
|
||||
'czech' => 'ces',
|
||||
'danish' => 'dan',
|
||||
'dutch' => 'nld',
|
||||
'english' => 'eng',
|
||||
'estonian' => 'est',
|
||||
'farsi' => 'fas',
|
||||
'finnish' => 'fin',
|
||||
'french' => 'fra',
|
||||
'german' => 'deu',
|
||||
'hausa' => 'hau',
|
||||
'hawaiian' => 'haw',
|
||||
'hindi' => 'hin',
|
||||
'hungarian' => 'hun',
|
||||
'icelandic' => 'isl',
|
||||
'indonesian' => 'ind',
|
||||
'italian' => 'ita',
|
||||
'kazakh' => 'kaz',
|
||||
'kyrgyz' => 'kir',
|
||||
'latin' => 'lat',
|
||||
'latvian' => 'lav',
|
||||
'lithuanian' => 'lit',
|
||||
'macedonian' => 'mkd',
|
||||
'mongolian' => 'mon',
|
||||
'nepali' => 'nep',
|
||||
'norwegian' => 'nor',
|
||||
'pashto' => 'pus',
|
||||
'pidgin' => 'crp',
|
||||
'polish' => 'pol',
|
||||
'portuguese' => 'por',
|
||||
'romanian' => 'ron',
|
||||
'russian' => 'rus',
|
||||
'serbian' => 'srp',
|
||||
'slovak' => 'slk',
|
||||
'slovene' => 'slv',
|
||||
'somali' => 'som',
|
||||
'spanish' => 'spa',
|
||||
'swahili' => 'swa',
|
||||
'swedish' => 'swe',
|
||||
'tagalog' => 'tgl',
|
||||
'turkish' => 'tur',
|
||||
'ukrainian' => 'ukr',
|
||||
'urdu' => 'urd',
|
||||
'uzbek' => 'uzb',
|
||||
'vietnamese' => 'vie',
|
||||
'welsh' => 'cym',
|
||||
);
|
||||
|
||||
/**
|
||||
* Maps ISO 639-1 2-letter language codes to the language names
|
||||
* in the language database
|
||||
*
|
||||
* Not all languages have a 2 letter code, so some are missing
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $code2ToName = array(
|
||||
'ar' => 'arabic',
|
||||
'az' => 'azeri',
|
||||
'bg' => 'bulgarian',
|
||||
'bn' => 'bengali',
|
||||
'cs' => 'czech',
|
||||
'cy' => 'welsh',
|
||||
'da' => 'danish',
|
||||
'de' => 'german',
|
||||
'en' => 'english',
|
||||
'es' => 'spanish',
|
||||
'et' => 'estonian',
|
||||
'fa' => 'farsi',
|
||||
'fi' => 'finnish',
|
||||
'fr' => 'french',
|
||||
'ha' => 'hausa',
|
||||
'hi' => 'hindi',
|
||||
'hr' => 'croatian',
|
||||
'hu' => 'hungarian',
|
||||
'id' => 'indonesian',
|
||||
'is' => 'icelandic',
|
||||
'it' => 'italian',
|
||||
'kk' => 'kazakh',
|
||||
'ky' => 'kyrgyz',
|
||||
'la' => 'latin',
|
||||
'lt' => 'lithuanian',
|
||||
'lv' => 'latvian',
|
||||
'mk' => 'macedonian',
|
||||
'mn' => 'mongolian',
|
||||
'ne' => 'nepali',
|
||||
'nl' => 'dutch',
|
||||
'no' => 'norwegian',
|
||||
'pl' => 'polish',
|
||||
'ps' => 'pashto',
|
||||
'pt' => 'portuguese',
|
||||
'ro' => 'romanian',
|
||||
'ru' => 'russian',
|
||||
'sk' => 'slovak',
|
||||
'sl' => 'slovene',
|
||||
'so' => 'somali',
|
||||
'sq' => 'albanian',
|
||||
'sr' => 'serbian',
|
||||
'sv' => 'swedish',
|
||||
'sw' => 'swahili',
|
||||
'tl' => 'tagalog',
|
||||
'tr' => 'turkish',
|
||||
'uk' => 'ukrainian',
|
||||
'ur' => 'urdu',
|
||||
'uz' => 'uzbek',
|
||||
'vi' => 'vietnamese',
|
||||
);
|
||||
|
||||
/**
|
||||
* Maps ISO 639-2 3-letter language codes to the language names
|
||||
* in the language database.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $code3ToName = array(
|
||||
'ara' => 'arabic',
|
||||
'aze' => 'azeri',
|
||||
'ben' => 'bengali',
|
||||
'bul' => 'bulgarian',
|
||||
'ceb' => 'cebuano',
|
||||
'ces' => 'czech',
|
||||
'crp' => 'pidgin',
|
||||
'cym' => 'welsh',
|
||||
'dan' => 'danish',
|
||||
'deu' => 'german',
|
||||
'eng' => 'english',
|
||||
'est' => 'estonian',
|
||||
'fas' => 'farsi',
|
||||
'fin' => 'finnish',
|
||||
'fra' => 'french',
|
||||
'hau' => 'hausa',
|
||||
'haw' => 'hawaiian',
|
||||
'hin' => 'hindi',
|
||||
'hrv' => 'croatian',
|
||||
'hun' => 'hungarian',
|
||||
'ind' => 'indonesian',
|
||||
'isl' => 'icelandic',
|
||||
'ita' => 'italian',
|
||||
'kaz' => 'kazakh',
|
||||
'kir' => 'kyrgyz',
|
||||
'lat' => 'latin',
|
||||
'lav' => 'latvian',
|
||||
'lit' => 'lithuanian',
|
||||
'mkd' => 'macedonian',
|
||||
'mon' => 'mongolian',
|
||||
'nep' => 'nepali',
|
||||
'nld' => 'dutch',
|
||||
'nor' => 'norwegian',
|
||||
'pol' => 'polish',
|
||||
'por' => 'portuguese',
|
||||
'pus' => 'pashto',
|
||||
'rom' => 'romanian',
|
||||
'rus' => 'russian',
|
||||
'slk' => 'slovak',
|
||||
'slv' => 'slovene',
|
||||
'som' => 'somali',
|
||||
'spa' => 'spanish',
|
||||
'sqi' => 'albanian',
|
||||
'srp' => 'serbian',
|
||||
'swa' => 'swahili',
|
||||
'swe' => 'swedish',
|
||||
'tgl' => 'tagalog',
|
||||
'tur' => 'turkish',
|
||||
'ukr' => 'ukrainian',
|
||||
'urd' => 'urdu',
|
||||
'uzb' => 'uzbek',
|
||||
'vie' => 'vietnamese',
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the 2-letter ISO 639-1 code for the given language name.
|
||||
*
|
||||
* @param string $lang English language name like "swedish"
|
||||
*
|
||||
* @return string Two-letter language code (e.g. "sv") or NULL if not found
|
||||
*/
|
||||
public static function nameToCode2($lang)
|
||||
{
|
||||
$lang = strtolower($lang);
|
||||
if (!isset(self::$nameToCode2[$lang])) {
|
||||
return null;
|
||||
}
|
||||
return self::$nameToCode2[$lang];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 3-letter ISO 639-2 code for the given language name.
|
||||
*
|
||||
* @param string $lang English language name like "swedish"
|
||||
*
|
||||
* @return string Three-letter language code (e.g. "swe") or NULL if not found
|
||||
*/
|
||||
public static function nameToCode3($lang)
|
||||
{
|
||||
$lang = strtolower($lang);
|
||||
if (!isset(self::$nameToCode3[$lang])) {
|
||||
return null;
|
||||
}
|
||||
return self::$nameToCode3[$lang];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the language name for the given 2-letter ISO 639-1 code.
|
||||
*
|
||||
* @param string $code Two-letter language code (e.g. "sv")
|
||||
*
|
||||
* @return string English language name like "swedish"
|
||||
*/
|
||||
public static function code2ToName($code)
|
||||
{
|
||||
$lang = strtolower($code);
|
||||
if (!isset(self::$code2ToName[$code])) {
|
||||
return null;
|
||||
}
|
||||
return self::$code2ToName[$code];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the language name for the given 3-letter ISO 639-2 code.
|
||||
*
|
||||
* @param string $code Three-letter language code (e.g. "swe")
|
||||
*
|
||||
* @return string English language name like "swedish"
|
||||
*/
|
||||
public static function code3ToName($code)
|
||||
{
|
||||
$lang = strtolower($code);
|
||||
if (!isset(self::$code3ToName[$code])) {
|
||||
return null;
|
||||
}
|
||||
return self::$code3ToName[$code];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||