55 Commits a1454a6c1d ... 70d9c7849a

Author SHA1 Message Date
  Andrew Dolgov 70d9c7849a Merge branch 'master' of git.fakecake.org:tt-rss 8 months ago
  Andrew Dolgov fd28d548ad Merge branch 'weblate-integration' 8 months ago
  Jesus Leal f80d146357 Translated using Weblate (Spanish) 8 months ago
  Andrew Dolgov b1f9ebe46e get_article_image: ignore data: schema images, other minor fixes 8 months ago
  Andrew Dolgov eb48aa5840 mailer.php: to_address/to_name was used instead of from_address/from_name 8 months ago
  Andrew Dolgov 986ca251f9 Merge branch 'weblate-integration' 8 months ago
  Andrew Dolgov c607b7836e onLoaded: clear this.headlines on first page load 8 months ago
  Andrew Dolgov 0517b88cce rpc, catchupfeed: return counters immediately so that frontend can figure out next unread feed correctly 8 months ago
  Andrew Dolgov f44c6d01b0 fix previous always disabling infscroll 8 months ago
  Andrew Dolgov c66db9bde8 headlines onloaded: when appending, check for duplicate IDs 8 months ago
  Dennis Mootz 676827ffac Translated using Weblate (German) 8 months ago
  Yann Soubeyrand 9ab375234a Translated using Weblate (French) 8 months ago
  Andrew Dolgov 60b40d39e8 Merge branch 'weblate-integration' 8 months ago
  Weblate 0a362baa7d Merge branch 'origin/weblate-integration' into Weblate 8 months ago
  Dennis Öberg eb52d4c407 Translated using Weblate (Swedish) 8 months ago
  Andrew Dolgov 734af3357d fix user plugins not saving properly in non-default profiles 8 months ago
  Andrew Dolgov 55ef85adc0 parser: clean() attribute values by default (except content) 8 months ago
  Andrew Dolgov 949bfa3457 add minor clean()-ing on some rss feed values 8 months ago
  Andrew Dolgov 2bd51c48d8 remove lib/mobile_detect 8 months ago
  Andrew Dolgov e70d42237a edit options after subscribe: use correct method name 8 months ago
  Andrew Dolgov 4729bdb132 queryFeedHeadlines: fix published field not returned when browsing by tag 8 months ago
  Andrew Dolgov aeb9f40257 Merge branch 'weblate-integration' 8 months ago
  Andrew Dolgov 1351ce370a truncate_middle: make it utf8 aware 8 months ago
  Andrew Dolgov 215c9f0f88 fail better if Feeds.view() data failed encoding to JSON 8 months ago
  Marek Pavelka d64ac993e7 Translated using Weblate (Czech) 8 months ago
  Andrew Dolgov eedd402807 rssutils: don't gzdecode() stuff 8 months ago
  Andrew Dolgov a5517fe857 fetch_file_contents: decompress gzipped data 8 months ago
  Andrew Dolgov 782eda45db Merge branch 'weblate-integration' 8 months ago
  Andrew Dolgov 54c9703a29 compact.css: fix italics 8 months ago
  Andrew Dolgov 7867f3efa4 prepare_headlines_digest: do not use PDO constants by reference 8 months ago
  Weblate 8cbf7468fa Merge branch 'origin/weblate-integration' into Weblate 8 months ago
  Marek Pavelka 88a5de83af Translated using Weblate (Czech) 9 months ago
  Andrew Dolgov 053c3efc8c properly show inverse filter rules as red 9 months ago
  Andrew Dolgov 51b069a1ee display filter tree rules as a list 9 months ago
  Andrew Dolgov e3c4540c12 Merge branch 'master' of git.fakecake.org:tt-rss 9 months ago
  Andrew Dolgov 5f1b39f7dc filter tree: don't crash on search, also search by filter titles 9 months ago
  Andrew Dolgov df00ebb1e2 filter tree: properly display huge multiline rules 9 months ago
  Andrew Dolgov 8393096947 selectionTogglePublished: fix typo which caused it to mark articles instead 9 months ago
  Andrew Dolgov dee210e546 headlines onLoaded: make sure a few more things respect append instead of offset == 0 9 months ago
  Andrew Dolgov 59d1fd481d mailer: set utf-8 content type 9 months ago
  Andrew Dolgov 8effabd075 append headline buffer if requested, don't just use offset 9 months ago
  Andrew Dolgov 5c481fb249 rpc/checkforupdates: restrict to administrative access level 9 months ago
  Andrew Dolgov 957c44d177 rework git update checking to be initiated by frontend, outside of runtime info output 9 months ago
  Andrew Dolgov c3b8b6a2a1 also prevent multiple requests 9 months ago
  Andrew Dolgov 54ce930b8d delay counters request on promise completion a bit 9 months ago
  Andrew Dolgov b66deb3240 rpc/getAllCounters: return seq 9 months ago
  Andrew Dolgov 8c49689fda filter test results: remove table bloat 9 months ago
  Andrew Dolgov 0efb6e1bc2 remove pub_set.png, replace usages with iconfont 9 months ago
  Andrew Dolgov 958fbfedb6 rssutils: check if returned data is in gzip format before trying to decode it 9 months ago
  Andrew Dolgov de9ff1644f Merge branch 'weblate-integration' 9 months ago
  Dario Di Ludovico fb4a8a3f80 Translated using Weblate (Italian) 9 months ago
  Glandos 488fb983e8 Translated using Weblate (French) 9 months ago
  Patrick Ahles 9d7d747dad Translated using Weblate (Dutch) 9 months ago
  Ptsa Daniel efbdd47ac2 Translated using Weblate (Chinese (Simplified)) 9 months ago
  Andrew Dolgov 356729310b remove jshrink 9 months ago
57 changed files with 828 additions and 2982 deletions
  1. 2 2
      classes/digest.php
  2. 10 10
      classes/feeditem/atom.php
  3. 27 27
      classes/feeditem/common.php
  4. 14 14
      classes/feeditem/rss.php
  5. 4 4
      classes/feedparser.php
  6. 9 1
      classes/feeds.php
  7. 9 7
      classes/handler/public.php
  8. 2 2
      classes/mailer.php
  9. 15 44
      classes/pref/filters.php
  10. 2 2
      classes/pref/prefs.php
  11. 31 4
      classes/rpc.php
  12. 8 22
      classes/rssutils.php
  13. 16 9
      css/default.css
  14. 1 1
      css/default.css.map
  15. 8 11
      css/dijit_basic.less
  16. 14 0
      css/tt-rss.less
  17. 2 0
      errors.php
  18. BIN
      images/pub_set.png
  19. BIN
      images/tag.png
  20. 30 34
      include/functions.php
  21. 9 22
      index.php
  22. 1 10
      js/AppBase.js
  23. 2 1
      js/CommonFilters.js
  24. 2 1
      js/Feeds.js
  25. 43 30
      js/Headlines.js
  26. 1 1
      js/PrefFilterTree.js
  27. 20 0
      js/tt-rss.js
  28. 0 1458
      lib/Mobile_Detect.php
  29. BIN
      locale/cs_CZ/LC_MESSAGES/messages.mo
  30. 175 205
      locale/cs_CZ/LC_MESSAGES/messages.po
  31. BIN
      locale/de_DE/LC_MESSAGES/messages.mo
  32. 20 23
      locale/de_DE/LC_MESSAGES/messages.po
  33. BIN
      locale/es_ES/LC_MESSAGES/messages.mo
  34. 22 15
      locale/es_ES/LC_MESSAGES/messages.po
  35. BIN
      locale/fr_FR/LC_MESSAGES/messages.mo
  36. 17 19
      locale/fr_FR/LC_MESSAGES/messages.po
  37. BIN
      locale/it_IT/LC_MESSAGES/messages.mo
  38. 17 18
      locale/it_IT/LC_MESSAGES/messages.po
  39. BIN
      locale/nl_NL/LC_MESSAGES/messages.mo
  40. 36 32
      locale/nl_NL/LC_MESSAGES/messages.po
  41. BIN
      locale/sv_SE/LC_MESSAGES/messages.mo
  42. 196 229
      locale/sv_SE/LC_MESSAGES/messages.po
  43. BIN
      locale/zh_CN/LC_MESSAGES/messages.mo
  44. 13 18
      locale/zh_CN/LC_MESSAGES/messages.po
  45. 1 2
      plugins/af_psql_trgm/init.php
  46. 3 3
      plugins/af_readability/init.php
  47. 9 6
      prefs.php
  48. 1 1
      themes/compact.css
  49. 1 1
      themes/compact.css.map
  50. 1 1
      themes/compact.less
  51. 16 9
      themes/night.css
  52. 1 1
      themes/night.css.map
  53. 16 9
      themes/night_blue.css
  54. 1 1
      themes/night_blue.css.map
  55. 0 24
      vendor/JShrink/LICENSE
  56. 0 587
      vendor/JShrink/Minifier.php
  57. 0 61
      vendor/JShrink/README.md

+ 2 - 2
classes/digest.php

@@ -141,8 +141,8 @@ class Digest
 				AND score >= 0
 			ORDER BY ttrss_feed_categories.title, ttrss_feeds.title, score DESC, date_updated DESC
 			LIMIT :limit");
-		$sth->bindParam(':user_id', intval($user_id, 10), \PDO::PARAM_INT);
-		$sth->bindParam(':limit', intval($limit, 10), \PDO::PARAM_INT);
+		$sth->bindParam(':user_id', intval($user_id, 10), PDO::PARAM_INT);
+		$sth->bindParam(':limit', intval($limit, 10), PDO::PARAM_INT);
 		$sth->execute();
 
 		$headlines_count = 0;

+ 10 - 10
classes/feeditem/atom.php

@@ -8,7 +8,7 @@ class FeedItem_Atom extends FeedItem_Common {
 		if ($id) {
 			return $id->nodeValue;
 		} else {
-			return $this->get_link();
+			return clean($this->get_link());
 		}
 	}
 
@@ -44,9 +44,9 @@ class FeedItem_Atom extends FeedItem_Common {
 				$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")));
+					return rewrite_relative_url($base, clean(trim($link->getAttribute("href"))));
 				else
-					return trim($link->getAttribute("href"));
+					return clean(trim($link->getAttribute("href")));
 
 			}
 		}
@@ -56,7 +56,7 @@ class FeedItem_Atom extends FeedItem_Common {
 		$title = $this->elem->getElementsByTagName("title")->item(0);
 
 		if ($title) {
-			return trim($title->nodeValue);
+			return clean(trim($title->nodeValue));
 		}
 	}
 
@@ -113,7 +113,7 @@ class FeedItem_Atom extends FeedItem_Common {
 		$categories = $this->xpath->query("dc:subject", $this->elem);
 
 		foreach ($categories as $cat) {
-			array_push($cats, trim($cat->nodeValue));
+			array_push($cats, clean(trim($cat->nodeValue)));
 		}
 
 		return $cats;
@@ -129,9 +129,9 @@ class FeedItem_Atom extends FeedItem_Common {
 				if ($link->getAttribute("rel") == "enclosure") {
 					$enc = new FeedEnclosure();
 
-					$enc->type = $link->getAttribute("type");
-					$enc->link = $link->getAttribute("href");
-					$enc->length = $link->getAttribute("length");
+					$enc->type = clean($link->getAttribute("type"));
+					$enc->link = clean($link->getAttribute("href"));
+					$enc->length = clean($link->getAttribute("length"));
 
 					array_push($encs, $enc);
 				}
@@ -147,12 +147,12 @@ class FeedItem_Atom extends FeedItem_Common {
 		$lang = $this->elem->getAttributeNS(self::NS_XML, "lang");
 
 		if (!empty($lang)) {
-			return $lang;
+			return clean($lang);
 		} else {
 			// Fall back to the language declared on the feed, if any.
 			foreach ($this->doc->childNodes as $child) {
 				if (method_exists($child, "getAttributeNS")) {
-					return $child->getAttributeNS(self::NS_XML, "lang");
+					return clean($child->getAttributeNS(self::NS_XML, "lang"));
 				}
 			}
 		}

+ 27 - 27
classes/feeditem/common.php

@@ -31,20 +31,20 @@ abstract class FeedItem_Common extends FeedItem {
 		if ($author) {
 			$name = $author->getElementsByTagName("name")->item(0);
 
-			if ($name) return $name->nodeValue;
+			if ($name) return clean($name->nodeValue);
 
 			$email = $author->getElementsByTagName("email")->item(0);
 
-			if ($email) return $email->nodeValue;
+			if ($email) return clean($email->nodeValue);
 
 			if ($author->nodeValue)
-				return $author->nodeValue;
+				return clean($author->nodeValue);
 		}
 
 		$author = $this->xpath->query("dc:creator", $this->elem)->item(0);
 
 		if ($author) {
-			return $author->nodeValue;
+			return clean($author->nodeValue);
 		}
 	}
 
@@ -53,15 +53,15 @@ abstract class FeedItem_Common extends FeedItem {
 		//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;
+		if ($com_url)
+			return clean($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;
+		if ($com_url)
+			return clean($com_url->nodeValue);
 	}
 
 	function get_comments_count() {
@@ -70,7 +70,7 @@ abstract class FeedItem_Common extends FeedItem {
 		$comments = $this->xpath->query($query, $this->elem)->item(0);
 
 		if ($comments) {
-			return $comments->nodeValue;
+			return clean($comments->nodeValue);
 		}
 	}
 
@@ -83,19 +83,19 @@ abstract class FeedItem_Common extends FeedItem {
 		foreach ($enclosures as $enclosure) {
 			$enc = new FeedEnclosure();
 
-			$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");
+			$enc->type = clean($enclosure->getAttribute("type"));
+			$enc->link = clean($enclosure->getAttribute("url"));
+			$enc->length = clean($enclosure->getAttribute("length"));
+			$enc->height = clean($enclosure->getAttribute("height"));
+			$enc->width = clean($enclosure->getAttribute("width"));
 
-			$medium = $enclosure->getAttribute("medium");
+			$medium = clean($enclosure->getAttribute("medium"));
 			if (!$enc->type && $medium) {
 				$enc->type = strtolower("$medium/generic");
 			}
 
 			$desc = $this->xpath->query("media:description", $enclosure)->item(0);
-			if ($desc) $enc->title = strip_tags($desc->nodeValue);
+			if ($desc) $enc->title = clean($desc->nodeValue);
 
 			array_push($encs, $enc);
 		}
@@ -108,23 +108,23 @@ abstract class FeedItem_Common extends FeedItem {
 			$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");
+				$enc->type = clean($content->getAttribute("type"));
+				$enc->link = clean($content->getAttribute("url"));
+				$enc->length = clean($content->getAttribute("length"));
+				$enc->height = clean($content->getAttribute("height"));
+				$enc->width = clean($content->getAttribute("width"));
 
-				$medium = $content->getAttribute("medium");
+				$medium = clean($content->getAttribute("medium"));
 				if (!$enc->type && $medium) {
 					$enc->type = strtolower("$medium/generic");
 				}
 
 				$desc = $this->xpath->query("media:description", $content)->item(0);
 				if ($desc) {
-					$enc->title = strip_tags($desc->nodeValue);
+					$enc->title = clean($desc->nodeValue);
 				} else {
 					$desc = $this->xpath->query("media:description", $enclosure)->item(0);
-					if ($desc) $enc->title = strip_tags($desc->nodeValue);
+					if ($desc) $enc->title = clean($desc->nodeValue);
 				}
 
 				array_push($encs, $enc);
@@ -137,9 +137,9 @@ abstract class FeedItem_Common extends FeedItem {
 			$enc = new FeedEnclosure();
 
 			$enc->type = "image/generic";
-			$enc->link = $enclosure->getAttribute("url");
-			$enc->height = $enclosure->getAttribute("height");
-			$enc->width = $enclosure->getAttribute("width");
+			$enc->link = clean($enclosure->getAttribute("url"));
+			$enc->height = clean($enclosure->getAttribute("height"));
+			$enc->width = clean($enclosure->getAttribute("width"));
 
 			array_push($encs, $enc);
 		}

+ 14 - 14
classes/feeditem/rss.php

@@ -4,9 +4,9 @@ class FeedItem_RSS extends FeedItem_Common {
 		$id = $this->elem->getElementsByTagName("guid")->item(0);
 
 		if ($id) {
-			return $id->nodeValue;
+			return clean($id->nodeValue);
 		} else {
-			return $this->get_link();
+			return clean($this->get_link());
 		}
 	}
 
@@ -33,20 +33,20 @@ class FeedItem_RSS extends FeedItem_Common {
 					|| $link->getAttribute("rel") == "alternate"
 					|| $link->getAttribute("rel") == "standout")) {
 
-				return trim($link->getAttribute("href"));
+				return clean(trim($link->getAttribute("href")));
 			}
 		}
 
 		$link = $this->elem->getElementsByTagName("guid")->item(0);
 
 		if ($link && $link->hasAttributes() && $link->getAttribute("isPermaLink") == "true") {
-			return trim($link->nodeValue);
+			return clean(trim($link->nodeValue));
 		}
 
 		$link = $this->elem->getElementsByTagName("link")->item(0);
 
 		if ($link) {
-			return trim($link->nodeValue);
+			return clean(trim($link->nodeValue));
 		}
 	}
 
@@ -54,7 +54,7 @@ class FeedItem_RSS extends FeedItem_Common {
 		$title = $this->xpath->query("title", $this->elem)->item(0);
 
 		if ($title) {
-			return trim($title->nodeValue);
+			return clean(trim($title->nodeValue));
 		}
 
 		// if the document has a default namespace then querying for
@@ -62,7 +62,7 @@ class FeedItem_RSS extends FeedItem_Common {
 		$title = $this->elem->getElementsByTagName("title")->item(0);
 
 		if ($title) {
-			return trim($title->nodeValue);
+			return clean(trim($title->nodeValue));
 		}
 	}
 
@@ -106,7 +106,7 @@ class FeedItem_RSS extends FeedItem_Common {
 		$categories = $this->xpath->query("dc:subject", $this->elem);
 
 		foreach ($categories as $cat) {
-			array_push($cats, trim($cat->nodeValue));
+			array_push($cats, clean(trim($cat->nodeValue)));
 		}
 
 		return $cats;
@@ -120,11 +120,11 @@ class FeedItem_RSS extends FeedItem_Common {
 		foreach ($enclosures as $enclosure) {
 			$enc = new FeedEnclosure();
 
-			$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");
+			$enc->type = clean($enclosure->getAttribute("type"));
+			$enc->link = clean($enclosure->getAttribute("url"));
+			$enc->length = clean($enclosure->getAttribute("length"));
+			$enc->height = clean($enclosure->getAttribute("height"));
+			$enc->width = clean($enclosure->getAttribute("width"));
 
 			array_push($encs, $enc);
 		}
@@ -141,7 +141,7 @@ class FeedItem_RSS extends FeedItem_Common {
 			return "";
 		}
 
-		return $languages[0]->textContent;
+		return clean($languages[0]->textContent);
 	}
 
 }

+ 4 - 4
classes/feedparser.php

@@ -246,11 +246,11 @@ class FeedParser {
 	}
 
 	function get_link() {
-		return $this->link;
+		return clean($this->link);
 	}
 
 	function get_title() {
-		return $this->title;
+		return clean($this->title);
 	}
 
 	function get_items() {
@@ -266,7 +266,7 @@ class FeedParser {
 
 			foreach ($links as $link) {
 				if (!$rel || $link->hasAttribute('rel') && $link->getAttribute('rel') == $rel) {
-					array_push($rv, trim($link->getAttribute('href')));
+					array_push($rv, clean(trim($link->getAttribute('href'))));
 				}
 			}
 			break;
@@ -275,7 +275,7 @@ class FeedParser {
 
 			foreach ($links as $link) {
 				if (!$rel || $link->hasAttribute('rel') && $link->getAttribute('rel') == $rel) {
-					array_push($rv, trim($link->getAttribute('href')));
+					array_push($rv, clean(trim($link->getAttribute('href'))));
 				}
 			}
 			break;

+ 9 - 1
classes/feeds.php

@@ -563,7 +563,14 @@ class Feeds extends Handler_Protected {
 		// this is parsed by handleRpcJson() on first viewfeed() to set cdm expanded, etc
 		$reply['runtime-info'] = make_runtime_info();
 
-		print json_encode($reply);
+		$reply_json = json_encode($reply);
+
+		if (!$reply_json) {
+		    $reply_json = json_encode(["error" => ["code" => 15,
+                "message" => json_last_error_msg()]]);
+        }
+
+		print $reply_json;
 
 	}
 
@@ -1798,6 +1805,7 @@ class Feeds extends Handler_Protected {
 							feed_id,
 							orig_feed_id,
 							marked,
+							published,
 							num_comments,
 							comments,
 							int_id,

+ 9 - 7
classes/handler/public.php

@@ -323,8 +323,7 @@ class Handler_Public extends Handler {
 
 		foreach ($enclosures as $enc) {
 			if (strpos($enc["content_type"], "image/") !== FALSE) {
-				$og_image = $enc["content_url"];
-				break;
+				return rewrite_relative_url($site_url, $enc["content_url"]);
 			}
 		}
 
@@ -333,15 +332,18 @@ class Handler_Public extends Handler {
 
 			if (@$tmpdoc->loadHTML(mb_substr($content, 0, 131070))) {
 				$tmpxpath = new DOMXPath($tmpdoc);
-				$first_img = $tmpxpath->query("//img")->item(0);
+				$imgs = $tmpxpath->query("//img");
+
+				foreach ($imgs as $img) {
+					$src = $img->getAttribute("src");
 
-				if ($first_img) {
-					$og_image = $first_img->getAttribute("src");
+					if (mb_strpos($src, "data:") !== 0)
+						return rewrite_relative_url($site_url, $src);
 				}
 			}
 		}
 
-		return rewrite_relative_url($site_url, $og_image);
+		return false;
     }
 
 	private function format_article($id, $owner_uid) {
@@ -846,7 +848,7 @@ class Handler_Public extends Handler {
 				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=\"method\" value=\"editfeed\">
 					<input type=\"hidden\" name=\"methodparam\" value=\"$feed_id\">
 					<input type=\"submit\" value=\"".__("Edit subscription options")."\">
 					</form>";

+ 2 - 2
classes/mailer.php

@@ -16,7 +16,7 @@ class Mailer {
 
 		$additional_headers = $params["headers"] ? $params["headers"] : [];
 
-		$from_combined = $from_name ? "$to_name <$to_address>" : $to_address;
+		$from_combined = $from_name ? "$from_name <$from_address>" : $from_address;
 		$to_combined = $to_name ? "$to_name <$to_address>" : $to_address;
 
 		Logger::get()->log("Sending mail from $from_combined to $to_combined <$to_address> [$subject]: $message");
@@ -37,7 +37,7 @@ class Mailer {
 				return 0;
 		}
 
-		$headers[] = "From: $from_combined";
+		$headers = [ "From: $from_combined", "Content-Type: text/plain; charset=UTF-8" ];
 
 		return mail($to_combined, $subject, $message, implode("\r\n", array_merge($headers, $additional_headers)));
 	}

+ 15 - 44
classes/pref/filters.php

@@ -146,48 +146,16 @@ class Pref_Filters extends Handler_Protected {
 
 				$content_preview = $line["content_preview"];
 
-				$tmp = "<tr style='margin-top : 5px'>";
-
-				#$tmp .= "<td width='5%' align='center'><input dojoType=\"dijit.form.CheckBox\"
-				#	checked=\"1\" disabled=\"1\" type=\"checkbox\"></td>";
-
-				$id = $line['id'];
-				$tmp .= "<td width='5%' align='center'><img style='cursor : pointer' title='".__("Preview article")."'
-					src='images/information.png' onclick='popupOpenArticle($id)'></td><td>";
-
-				/*foreach ($filter['rules'] as $rule) {
-					$reg_exp = str_replace('/', '\/', $rule["reg_exp"]);
-
-					$line["title"] = preg_replace("/($reg_exp)/i",
-						"<span class=\"highlight\">$1</span>", $line["title"]);
-
-					$content_preview = preg_replace("/($reg_exp)/i",
-						"<span class=\"highlight\">$1</span>", $content_preview);
-				}*/
-
-				$tmp .= "<strong>" . $line["title"] . "</strong><br/>";
-				$tmp .= $line['feed_title'] . ", " . mb_substr($line["date_entered"], 0, 16);
-				$tmp .= "<div class='insensitive'>" . $content_preview . "</div>";
-				$tmp .= "</td></tr>";
+				$tmp = "<li><span class='title'>" . $line["title"] . "</span><br/>" .
+					"<span class='feed'>" . $line['feed_title'] . "</span>, <span class='date'>" . mb_substr($line["date_entered"], 0, 16) . "</span>" .
+					"<div class='preview insensitive'>" . $content_preview . "</div>" .
+					"</li>";
 
 				array_push($rv, $tmp);
 
-				/*array_push($rv, array("title" => $line["title"],
-					"content" => $content_preview,
-					"date" => $line["date_entered"],
-					"feed" => $line["feed_title"])); */
-
 			}
 		}
 
-			//$offset += $limit;
-		//}
-
-		/*if ($found == 0) {
-			print "<tr><td align='center'>" .
-				__("No recent articles matching this filter have been found.");
-		}*/
-
 		print json_encode($rv);
 	}
 
@@ -199,9 +167,8 @@ class Pref_Filters extends Handler_Protected {
 
 		print "<div><img id='prefFilterLoadingIndicator' src='images/indicator_tiny.gif'>&nbsp;<span id='prefFilterProgressMsg'>Looking for articles...</span></div>";
 
-		print "<br/><div class='panel panel-scrollable'>";
-		print "<table width='100%' id='prefFilterTestResultList'>";
-		print "</table></div>";
+		print "<ul class='panel panel-scrollable list list-unstyled' id='prefFilterTestResultList'>";
+		print "</ul>";
 
 		print "<div style='text-align : center'>";
 		print "<button dojoType=\"dijit.form.Button\" onclick=\"dijit.byId('filterTestDlg').hide()\">".
@@ -210,7 +177,7 @@ class Pref_Filters extends Handler_Protected {
 
 	}
 
-	private function getfilterrules_concise($filter_id) {
+	private function getfilterrules_list($filter_id) {
 		$sth = $this->pdo->prepare("SELECT reg_exp,
 			inverse,
 			match_on,
@@ -260,11 +227,11 @@ class Pref_Filters extends Handler_Protected {
 
 			$inverse = $line["inverse"] ? "inverse" : "";
 
-			$rv .= "<span class='$inverse'>" . T_sprintf("%s on %s in %s %s",
+			$rv .= "<li class='$inverse'>" . T_sprintf("%s on %s in %s %s",
 				htmlspecialchars($line["reg_exp"]),
 				$line["field"],
 				$where,
-				$line["inverse"] ? __("(inverse)") : "") . "</span>";
+				$line["inverse"] ? __("(inverse)") : "") . "</li>";
 		}
 
 		return $rv;
@@ -301,6 +268,10 @@ class Pref_Filters extends Handler_Protected {
 
 			$match_ok = false;
 			if ($filter_search) {
+				if (mb_strpos($line['title'], $filter_search) !== false) {
+					$match_ok = true;
+				}
+
 				$rules_sth = $this->pdo->prepare("SELECT reg_exp
 					FROM ttrss_filters2_rules WHERE filter_id = ?");
 				$rules_sth->execute([$line['id']]);
@@ -335,7 +306,7 @@ class Pref_Filters extends Handler_Protected {
 			$filter['checkbox'] = false;
 			$filter['last_triggered'] = $line["last_triggered"] ? make_local_datetime($line["last_triggered"], false) : null;
 			$filter['enabled'] = $line["enabled"];
-			$filter['rules'] = $this->getfilterrules_concise($line['id']);
+			$filter['rules'] = $this->getfilterrules_list($line['id']);
 
 			if (!$filter_search || $match_ok) {
 				array_push($folder['items'], $filter);
@@ -785,7 +756,7 @@ class Pref_Filters extends Handler_Protected {
 		print "<div style='float : right; padding-right : 4px;'>
 			<input dojoType=\"dijit.form.TextBox\" id=\"filter_search\" size=\"20\" type=\"search\"
 				value=\"$filter_search\">
-			<button dojoType=\"dijit.form.Button\" onclick=\"updateFilterList()\">".
+			<button dojoType=\"dijit.form.Button\" onclick=\"dijit.byId('filterTree').reload()\">".
 				__('Search')."</button>
 			</div>";
 

+ 2 - 2
classes/pref/prefs.php

@@ -735,7 +735,7 @@ class Pref_Prefs extends Handler_Protected {
 				<td width='10%'>".__('Author')."</td></tr>";
 
 		$system_enabled = array_map("trim", explode(",", PLUGINS));
-		$user_enabled = array_map("trim", explode(",", get_pref("_ENABLED_PLUGINS", $_SESSION['uid'])));
+		$user_enabled = array_map("trim", explode(",", get_pref("_ENABLED_PLUGINS")));
 
 		$tmppluginhost = new PluginHost();
 		$tmppluginhost->load_all($tmppluginhost::KIND_ALL, $_SESSION["uid"], true);
@@ -973,7 +973,7 @@ class Pref_Prefs extends Handler_Protected {
 		else
 			$plugins = "";
 
-		set_pref("_ENABLED_PLUGINS", $plugins, $_SESSION["uid"]);
+		set_pref("_ENABLED_PLUGINS", $plugins);
 	}
 
 	function clearplugindata() {

+ 31 - 4
classes/rpc.php

@@ -274,7 +274,8 @@ class RPC extends Handler_Protected {
 		@$seq = (int) $_REQUEST['seq'];
 
 		$reply = [
-			'counters' => Counters::getAllCounters()
+			'counters' => Counters::getAllCounters(),
+			'seq' => $seq
 		];
 
 		if ($seq % 2 == 0)
@@ -323,7 +324,7 @@ class RPC extends Handler_Protected {
 
 		if ($reply['error']['code'] == 0) {
 			$reply['init-params'] = make_init_params();
-			$reply['runtime-info'] = make_runtime_info(true);
+			$reply['runtime-info'] = make_runtime_info();
 		}
 
 		print json_encode($reply);
@@ -423,7 +424,10 @@ class RPC extends Handler_Protected {
 
 		Feeds::catchup_feed($feed_id, $is_cat, false, $mode, [$search_query, $search_lang]);
 
-		print json_encode(array("message" => "UPDATE_COUNTERS"));
+		// return counters here synchronously so that frontend can figure out next unread feed properly
+		print json_encode(['counters' => Counters::getAllCounters()]);
+
+		//print json_encode(array("message" => "UPDATE_COUNTERS"));
 	}
 
 	function setpanelmode() {
@@ -596,4 +600,27 @@ class RPC extends Handler_Protected {
 		}
 
 	}
-}
+
+	function checkforupdates() {
+		$rv = [];
+
+		if (CHECK_FOR_UPDATES && $_SESSION["access_level"] >= 10 && defined("GIT_VERSION_TIMESTAMP")) {
+			$content = @fetch_file_contents(["url" => "https://tt-rss.org/version.json"]);
+
+			if ($content) {
+				$content = json_decode($content, true);
+
+				if ($content && isset($content["changeset"])) {
+					if ((int)GIT_VERSION_TIMESTAMP < (int)$content["changeset"]["timestamp"] &&
+						GIT_VERSION_HEAD != $content["changeset"]["id"]) {
+
+						$rv = $content["changeset"];
+					}
+				}
+			}
+		}
+
+		print json_encode($rv);
+	}
+
+}

+ 8 - 22
classes/rssutils.php

@@ -256,14 +256,6 @@ class RSSUtils {
 					FEED_FETCH_TIMEOUT,
 					0);
 
-				global $fetch_curl_used;
-
-				if (!$fetch_curl_used) {
-					$tmp = @gzdecode($feed_data);
-
-					if ($tmp) $feed_data = $tmp;
-				}
-
 				$feed_data = trim($feed_data);
 
 				$rss = new FeedParser($feed_data);
@@ -271,8 +263,8 @@ class RSSUtils {
 
 				if (!$rss->error()) {
 					$basic_info = array(
-						'title' => mb_substr($rss->get_title(), 0, 199),
-						'site_url' => mb_substr(rewrite_relative_url($fetch_url, $rss->get_link()), 0, 245)
+						'title' => mb_substr(clean($rss->get_title()), 0, 199),
+						'site_url' => mb_substr(rewrite_relative_url($fetch_url, clean($rss->get_link())), 0, 245)
 					);
 				}
 			}
@@ -430,14 +422,6 @@ class RSSUtils {
 				"last_modified" => $force_refetch ? "" : $stored_last_modified
 			]);
 
-			global $fetch_curl_used;
-
-			if (!$fetch_curl_used) {
-				$tmp = @gzdecode($feed_data);
-
-				if ($tmp) $feed_data = $tmp;
-			}
-
 			$feed_data = trim($feed_data);
 
 			Debug::log("fetch done.", Debug::$LOG_VERBOSE);
@@ -515,10 +499,10 @@ class RSSUtils {
 				return false;
 			}
 
-			$site_url = mb_substr(rewrite_relative_url($fetch_url, $rss->get_link()), 0, 245);
+			$site_url = mb_substr(rewrite_relative_url($fetch_url, clean($rss->get_link())), 0, 245);
 
 			Debug::log("site_url: $site_url", Debug::$LOG_VERBOSE);
-			Debug::log("feed_title: " . $rss->get_title(), Debug::$LOG_VERBOSE);
+			Debug::log("feed_title: " . clean($rss->get_title()), Debug::$LOG_VERBOSE);
 
 			if ($favicon_needs_check || $force_refetch) {
 
@@ -625,7 +609,7 @@ class RSSUtils {
 
 				$entry_title = strip_tags($item->get_title());
 
-				$entry_link = rewrite_relative_url($site_url, $item->get_link());
+				$entry_link = rewrite_relative_url($site_url, clean($item->get_link()));
 
 				$entry_language = mb_substr(trim($item->get_language()), 0, 2);
 
@@ -1602,6 +1586,8 @@ class RSSUtils {
 		}
 	}
 
-
+	static function is_gzipped($feed_data) {
+		return mb_strpos($feed_data, "\x1f" . "\x8b" . "\x08", 0, "US-ASCII") === 0;
+	}
 
 }

+ 16 - 9
css/default.css

@@ -1042,6 +1042,15 @@ body.ttrss_main ul.list-unstyled {
 body.ttrss_main .text-center {
   text-align: center;
 }
+body.ttrss_main #prefFilterTestResultList .preview {
+  margin: 8px;
+}
+body.ttrss_main #prefFilterTestResultList .title {
+  font-weight: bold;
+}
+body.ttrss_main #prefFilterTestResultList .feed {
+  color: #257aa7;
+}
 ::selection {
   background: #257aa7;
   color: #ffffff;
@@ -1745,14 +1754,10 @@ body#sharepopup input {
 .flat li {
   padding: 2px;
 }
-.flat .filterRules span {
-  display: block;
-  color: green;
-}
 .flat #filterDlg_Matches span.filterRule {
   color: green;
 }
-.flat .filterRules span.inverse,
+.flat #filterTree .filterRules li.inverse,
 .flat #filterDlg_Matches span.filterRule.inverse {
   color: red;
 }
@@ -1793,7 +1798,7 @@ body#sharepopup input {
 .flat .dijitTree .dijitFolderOpened {
   display: none;
 }
-.flat .dijitTree .dijitTreeRowSelected .filterRules span {
+.flat .dijitTree .dijitTreeRowSelected .filterRules li {
   color: white;
 }
 .flat .dijitTree .dijitTreeRowSelected .dijitTreeExpando {
@@ -1820,11 +1825,13 @@ body#sharepopup input {
   float: right;
 }
 .flat .dijitTree .filterRules {
-  display: block;
-  color: #ccc;
   font-size: 12px;
-  margin-left: 100px;
   line-height: normal;
+  white-space: normal;
+  margin-left: 28px;
+}
+.flat .dijitTree .filterRules li {
+  color: green;
 }
 .flat .dijitTree .dijitTreeContainer {
   max-width: 100%;

File diff suppressed because it is too large
+ 1 - 1
css/default.css.map


+ 8 - 11
css/dijit_basic.less

@@ -4,16 +4,11 @@
 		padding: 2px;
 	}
 
-	.filterRules span {
-		display: block;
-		color: green;
-	}
-
 	#filterDlg_Matches span.filterRule {
 		color: green;
 	}
 
-	.filterRules span.inverse,
+	#filterTree .filterRules li.inverse,
 	#filterDlg_Matches span.filterRule.inverse {
 		color: red;
 	}
@@ -69,7 +64,7 @@
 		}
 
 		.dijitTreeRowSelected {
-			.filterRules span {
+			.filterRules li {
 				color : white;
 			}
 
@@ -105,13 +100,15 @@
 		}
 
 		.filterRules {
-			display: block;
-			color: #ccc;
 			font-size: 12px;
-			margin-left: 100px;
 			line-height : normal;
-		}
+			white-space: normal;
+			margin-left : 28px;
 
+			li {
+				color : green;
+			}
+		}
 
 		.dijitTreeContainer {
 			max-width : 100%;

+ 14 - 0
css/tt-rss.less

@@ -1246,6 +1246,20 @@ body.ttrss_main {
 		text-align : center;
 	}
 
+	#prefFilterTestResultList {
+		.preview {
+			margin : 8px;
+		}
+
+		.title {
+			font-weight: bold;
+		}
+
+		.feed {
+			color : @color-accent;
+		}
+	}
+
 }
 
 ::selection {

+ 2 - 0
errors.php

@@ -38,6 +38,8 @@
 
 	$ERRORS[14] = __("Plugin not found");
 
+	$ERRORS[15] = __("Encoding data as JSON failed");
+
 	if ($_REQUEST['mode'] == 'js') {
 		header("Content-Type: text/javascript; charset=UTF-8");
 

BIN
images/pub_set.png


BIN
images/tag.png


+ 30 - 34
include/functions.php

@@ -437,6 +437,14 @@
 
 			curl_close($ch);
 
+			$is_gzipped = RSSUtils::is_gzipped($contents);
+
+			if ($is_gzipped) {
+				$tmp = @gzdecode($contents);
+
+				if ($tmp) $contents = $tmp;
+			}
+
 			return $contents;
 		} else {
 
@@ -522,6 +530,15 @@
 
 				return false;
 			}
+
+			$is_gzipped = RSSUtils::is_gzipped($data);
+
+			if ($is_gzipped) {
+				$tmp = @gzdecode($data);
+
+				if ($tmp) $data = $tmp;
+			}
+
 			return $data;
 		}
 
@@ -679,8 +696,6 @@
 				$_SESSION["user_agent"] = sha1($_SERVER['HTTP_USER_AGENT']);
 				$_SESSION["pwd_hash"] = $row["pwd_hash"];
 
-				$_SESSION["last_version_check"] = time();
-
 				initialize_user_prefs($_SESSION["uid"]);
 
 				return true;
@@ -848,10 +863,18 @@
 		}
 	}
 
-	// is not utf8 clean
+	function mb_substr_replace($original, $replacement, $position, $length) {
+		$startString = mb_substr($original, 0, $position, "UTF-8");
+		$endString = mb_substr($original, $position + $length, mb_strlen($original), "UTF-8");
+
+		$out = $startString . $replacement . $endString;
+
+		return $out;
+	}
+
 	function truncate_middle($str, $max_len, $suffix = '&hellip;') {
-		if (strlen($str) > $max_len) {
-			return substr_replace($str, $suffix, $max_len / 2, mb_strlen($str) - $max_len);
+		if (mb_strlen($str) > $max_len) {
+			return mb_substr_replace($str, $suffix, $max_len / 2, mb_strlen($str) - $max_len);
 		} else {
 			return $str;
 		}
@@ -1068,6 +1091,7 @@
 			$params[strtolower($param)] = (int) get_pref($param);
 		}
 
+		$params["check_for_updates"] = CHECK_FOR_UPDATES;
 		$params["icons_url"] = ICONS_URL;
 		$params["cookie_lifetime"] = SESSION_COOKIE_LIFETIME;
 		$params["default_view_mode"] = get_pref("_DEFAULT_VIEW_MODE");
@@ -1270,27 +1294,7 @@
 		return array($prefixes, $hotkeys);
 	}
 
-	function check_for_update() {
-		if (defined("GIT_VERSION_TIMESTAMP")) {
-			$content = @fetch_file_contents(array("url" => "http://tt-rss.org/version.json", "timeout" => 5));
-
-			if ($content) {
-				$content = json_decode($content, true);
-
-				if ($content && isset($content["changeset"])) {
-					if ((int)GIT_VERSION_TIMESTAMP < (int)$content["changeset"]["timestamp"] &&
-						GIT_VERSION_HEAD != $content["changeset"]["id"]) {
-
-						return $content["changeset"]["id"];
-					}
-				}
-			}
-		}
-
-		return "";
-	}
-
-	function make_runtime_info($disable_update_check = false) {
+	function make_runtime_info() {
 		$data = array();
 
 		$pdo = Db::pdo();
@@ -1323,14 +1327,6 @@
 			}
 		}
 
-		if (CHECK_FOR_UPDATES && !$disable_update_check && $_SESSION["last_version_check"] + 86400 + rand(-1000, 1000) < time()) {
-			$update_result = @check_for_update();
-
-			$data["update_result"] = $update_result;
-
-			$_SESSION["last_version_check"] = time();
-		}
-
 		if (file_exists(LOCK_DIRECTORY . "/update_daemon.lock")) {
 
 			$data['daemon_is_running'] = (int) file_is_locked("update_daemon.lock");

+ 9 - 22
index.php

@@ -26,25 +26,9 @@
 	require_once "version.php";
 	require_once "config.php";
 	require_once "db-prefs.php";
-	require_once "lib/Mobile_Detect.php";
-
-	$mobile = new Mobile_Detect();
 
 	if (!init_plugins()) return;
 
-	if (!$_REQUEST['mobile']) {
-		if ($mobile->isTablet() && PluginHost::getInstance()->get_plugin("digest")) {
-			header('Location: backend.php?op=digest');
-			exit;
-		} else if ($mobile->isMobile() && PluginHost::getInstance()->get_plugin("mobile")) {
-			header('Location: backend.php?op=mobile');
-			exit;
-		} else if ($mobile->isMobile() && PluginHost::getInstance()->get_plugin("digest")) {
-			header('Location: backend.php?op=digest');
-			exit;
-		}
-	}
-
 	login_sequence();
 
 	header('Content-Type: text/html; charset=utf-8');
@@ -117,12 +101,15 @@
 	<?php
 		foreach (PluginHost::getInstance()->get_plugins() as $n => $p) {
 			if (method_exists($p, "get_js")) {
-				echo "try {";
-				echo JShrink\Minifier::minify($p->get_js());
-				echo "} catch (e) {
-				 	console.warn('failed to initialize plugin JS: $n');
-					console.warn(e);
-				}";
+			    $script = $p->get_js();
+
+			    if ($script) {
+					echo "try {
+					    $script
+					} catch (e) {
+                        console.warn('failed to initialize plugin JS: $n', e);
+                    }";
+				}
 			}
 		}
 

+ 1 - 10
js/AppBase.js

@@ -209,8 +209,7 @@ define(["dojo/_base/declare"], function (declare) {
 					const seq = reply['seq'];
 
 					if (seq && this.get_seq() != seq) {
-						console.log("[handleRpcJson] sequence mismatch: " + seq +
-							" (want: " + this.get_seq() + ")");
+						console.log("[handleRpcJson] sequence mismatch: ", seq, '!=', this.get_seq());
 						return true;
 					}
 
@@ -263,14 +262,6 @@ define(["dojo/_base/declare"], function (declare) {
 						return;
 					}
 
-					if (k == "update_result") {
-						if (v) {
-							Element.show("updates-available");
-						} else {
-							Element.hide("updates-available");
-						}
-					}
-
 					if (k == "recent_log_events") {
 						const alert = $$(".log-alert")[0];
 

+ 2 - 1
js/CommonFilters.js

@@ -218,7 +218,8 @@ define(["dojo/_base/declare"], function (declare) {
 									Element.hide("prefFilterLoadingIndicator");
 
 									if (test_dlg.results == 0) {
-										$("prefFilterTestResultList").innerHTML = "<tr><td align='center'>No recent articles matching this filter have been found.</td></tr>";
+										$("prefFilterTestResultList").innerHTML = `<tr><td align='center'>
+											${__('No recent articles matching this filter have been found.')}</td></tr>`;
 										$("prefFilterProgressMsg").innerHTML = "Articles matching this filter:";
 									} else {
 										$("prefFilterProgressMsg").innerHTML = __("Found %d articles matching this filter:")

+ 2 - 1
js/Feeds.js

@@ -282,6 +282,7 @@ define(["dojo/_base/declare"], function (declare) {
 			const is_cat = !!params.is_cat || false;
 			const offset = params.offset || 0;
 			const viewfeed_debug = params.viewfeed_debug;
+			const append = params.append || false;
 			const method = params.method;
 			// this is used to quickly switch between feeds, sets active but xhr is on a timeout
 			const delayed = params.delayed || false;
@@ -349,7 +350,7 @@ define(["dojo/_base/declare"], function (declare) {
 					try {
 						window.clearTimeout(this._infscroll_timeout);
 						this.setExpando(feed, is_cat, 'images/blank_icon.gif');
-						Headlines.onLoaded(transport, offset);
+						Headlines.onLoaded(transport, offset, append);
 						PluginHost.run(PluginHost.HOOK_FEED_LOADED, [feed, is_cat]);
 					} catch (e) {
 						App.Error.report(e);

+ 43 - 30
js/Headlines.js

@@ -4,6 +4,7 @@ define(["dojo/_base/declare"], function (declare) {
 	Headlines = {
 		vgroup_last_feed: undefined,
 		_headlines_scroll_timeout: 0,
+		_observer_counters_timeout: 0,
 		headlines: [],
 		current_first_id: 0,
 		row_observer: new MutationObserver((mutations) => {
@@ -141,7 +142,11 @@ define(["dojo/_base/declare"], function (declare) {
 
 			if (promises.length > 0)
 				Promise.all([promises]).then(() => {
-					Feeds.requestCounters(true);
+					window.clearTimeout(this._observer_counters_timeout);
+
+					this._observer_counters_timeout = setTimeout(() => {
+						Feeds.requestCounters(true);
+					}, 1000);
 				});
 
 		},
@@ -213,7 +218,7 @@ define(["dojo/_base/declare"], function (declare) {
 
 			console.log("loadMore, offset=", offset);
 
-			Feeds.open({feed: Feeds.getActive(), is_cat: Feeds.activeIsCat(), offset: offset});
+			Feeds.open({feed: Feeds.getActive(), is_cat: Feeds.activeIsCat(), offset: offset, append: true});
 		},
 		scrollHandler: function () {
 			try {
@@ -524,19 +529,16 @@ define(["dojo/_base/declare"], function (declare) {
 
 			return tmp.firstChild;
 		},
-		onLoaded: function (transport, offset) {
+		onLoaded: function (transport, offset, append) {
 			const reply = App.handleRpcJson(transport);
 
-			console.log("Headlines.onLoaded: offset=", offset);
+			console.log("Headlines.onLoaded: offset=", offset, "append=", append);
 
 			let is_cat = false;
 			let feed_id = false;
 
 			if (reply) {
 
-				if (offset == 0)
-					Article.setActive(0);
-
 				is_cat = reply['headlines']['is_cat'];
 				feed_id = reply['headlines']['id'];
 				Feeds.last_search_query = reply['headlines']['search_query'];
@@ -544,32 +546,34 @@ define(["dojo/_base/declare"], function (declare) {
 				if (feed_id != -7 && (feed_id != Feeds.getActive() || is_cat != Feeds.activeIsCat()))
 					return;
 
-				try {
-					if (offset == 0) {
-						$("headlines-frame").scrollTop = 0;
-
-						Element.hide("floatingTitle");
-						$("floatingTitle").setAttribute("data-article-id", 0);
-						$("floatingTitle").innerHTML = "";
-					}
-				} catch (e) {
-				}
-
-				$("headlines-frame").removeClassName("cdm");
-				$("headlines-frame").removeClassName("normal");
-
-				$("headlines-frame").addClassName(App.isCombinedMode() ? "cdm" : "normal");
-
 				const headlines_count = reply['headlines-info']['count'];
-				Feeds.infscroll_disabled = parseInt(headlines_count) != 30;
 
+				Feeds.infscroll_disabled = parseInt(headlines_count) < 30;
 				console.log('received', headlines_count, 'headlines, infscroll disabled=', Feeds.infscroll_disabled);
 
 				//this.vgroup_last_feed = reply['headlines-info']['vgroup_last_feed'];
 				this.current_first_id = reply['headlines']['first_id'];
 
-				if (offset == 0) {
-					//this.headlines = [];
+				if (!append) {
+
+					$("headlines-frame").removeClassName("cdm");
+					$("headlines-frame").removeClassName("normal");
+
+					$("headlines-frame").addClassName(App.isCombinedMode() ? "cdm" : "normal");
+
+					Article.setActive(0);
+
+					try {
+						$("headlines-frame").scrollTop = 0;
+
+						Element.hide("floatingTitle");
+						$("floatingTitle").setAttribute("data-article-id", 0);
+						$("floatingTitle").innerHTML = "";
+					} catch (e) {
+						console.warn(e);
+					}
+
+					this.headlines = [];
 					this.vgroup_last_feed = undefined;
 
 					dojo.html.set($("toolbar-headlines"),
@@ -619,18 +623,27 @@ define(["dojo/_base/declare"], function (declare) {
 					if (hsp)
 						c.domNode.removeChild(hsp);
 
+					let headlines_appended = 0;
+
 					if (typeof reply['headlines']['content'] == 'string') {
 						$("headlines-frame").innerHTML = reply['headlines']['content'];
 					} else {
 						for (let i = 0; i < reply['headlines']['content'].length; i++) {
 							const hl = reply['headlines']['content'][i];
 
-							$("headlines-frame").appendChild(this.render(reply['headlines'], hl));
+							if (!this.headlines[parseInt(hl.id)]) {
+								$("headlines-frame").appendChild(this.render(reply['headlines'], hl));
 
-							this.headlines[parseInt(hl.id)] = hl;
+								this.headlines[parseInt(hl.id)] = hl;
+								++headlines_appended;
+							}
 						}
 					}
 
+					Feeds.infscroll_disabled = headlines_appended != 30;
+
+					console.log('appended', headlines_appended, 'headlines, infscroll_disabled=', Feeds.infscroll_disabled);
+
 					if (!hsp) {
 						hsp = document.createElement("div");
 						hsp.id = "headlines-spacer";
@@ -746,7 +759,7 @@ define(["dojo/_base/declare"], function (declare) {
 			}
 
 			ids.each((id) => {
-				this.toggleMark(id);
+				this.togglePub(id);
 			});
 		},
 		toggleMark: function (id) {
@@ -1379,4 +1392,4 @@ define(["dojo/_base/declare"], function (declare) {
 	}
 
 	return Headlines;
-});
+});

+ 1 - 1
js/PrefFilterTree.js

@@ -17,7 +17,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], functio
 			}
 
 			if (rules) {
-				param = dojo.doc.createElement('span');
+				param = dojo.doc.createElement('ul');
 				param.className = 'filterRules';
 				param.innerHTML = rules;
 				domConstruct.place(param, tnode.rowNode, 'next');

+ 20 - 0
js/tt-rss.js

@@ -163,11 +163,31 @@ require(["dojo/_base/kernel",
 						window.setInterval(() => { Feeds.updateRandom() }, 30 * 1000);
 					}
 
+					if (App.getInitParam('check_for_updates')) {
+						window.setInterval(() => {
+							App.checkForUpdates();
+						}, 3600 * 1000);
+					}
+
 					console.log("second stage ok");
 
 					PluginHost.run(PluginHost.HOOK_INIT_COMPLETE, null);
 
 				},
+				checkForUpdates: function() {
+					console.log('checking for updates...');
+
+					xhrJson("backend.php", {op: 'rpc', method: 'checkforupdates'})
+						.then((reply) => {
+							console.log('update reply', reply);
+
+							if (reply.id) {
+								$("updates-available").show();
+							} else {
+								$("updates-available").hide();
+							}
+						});
+				},
 				updateTitle: function() {
 					let tmp = "Tiny Tiny RSS";
 

File diff suppressed because it is too large
+ 0 - 1458
lib/Mobile_Detect.php


BIN
locale/cs_CZ/LC_MESSAGES/messages.mo


File diff suppressed because it is too large
+ 175 - 205
locale/cs_CZ/LC_MESSAGES/messages.po


BIN
locale/de_DE/LC_MESSAGES/messages.mo


+ 20 - 23
locale/de_DE/LC_MESSAGES/messages.po

@@ -12,9 +12,10 @@ msgstr ""
 "Project-Id-Version: tt-rss git\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2018-12-11 14:31+0300\n"
-"PO-Revision-Date: 2018-12-05 18:43+0000\n"
-"Last-Translator: ZerFEr <[email protected]>\n"
-"Language-Team: German <https://weblate.tt-rss.org/projects/tt-rss/messages/de/>\n"
+"PO-Revision-Date: 2019-01-02 09:12+0000\n"
+"Last-Translator: Dennis Mootz <[email protected]>\n"
+"Language-Team: German <https://weblate.tt-rss.org/projects/tt-rss/messages/"
+"de/>\n"
 "Language: de_DE\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -33,23 +34,23 @@ msgstr "Niemals löschen"
 
 #: backend.php:75
 msgid "1 week old"
-msgstr "Nach 1 Woche"
+msgstr "Nach einer Woche"
 
 #: backend.php:76
 msgid "2 weeks old"
-msgstr "Nach 2 Wochen"
+msgstr "Nach zwei Wochen"
 
 #: backend.php:77
 msgid "1 month old"
-msgstr "Nach 1 Monat"
+msgstr "Nach einem Monat"
 
 #: backend.php:78
 msgid "2 months old"
-msgstr "Nach 2 Monaten"
+msgstr "Nach zwei Monaten"
 
 #: backend.php:79
 msgid "3 months old"
-msgstr "Nach 3 Monaten"
+msgstr "Nach drei Monaten"
 
 #: backend.php:82
 msgid "Default interval"
@@ -199,7 +200,7 @@ msgstr "Kommunikationsfehler mit Server."
 
 #: index.php:168
 msgid "Recent entries found in event log."
-msgstr ""
+msgstr "Neue Einträge im Event-Log gefunden."
 
 #: index.php:171
 msgid "Updates are available from Git."
@@ -335,9 +336,8 @@ msgstr "Breitbild-Modus umschalten"
 
 #: index.php:245
 #: include/functions.php:1177
-#, fuzzy
 msgid "Toggle night mode"
-msgstr "Kombinierte Feed-Anzeige umschalten"
+msgstr "Nacht-Modus umschalten"
 
 #: index.php:246
 msgid "Keyboard shortcuts help"
@@ -2036,9 +2036,8 @@ msgid "Customize"
 msgstr "Anpassen"
 
 #: classes/pref/prefs.php:563
-#, fuzzy
 msgid "default"
-msgstr "Standard"
+msgstr "standard"
 
 #: classes/pref/prefs.php:625
 msgid "Register"
@@ -2126,9 +2125,10 @@ msgid "Incorrect password"
 msgstr "Falsches Passwort"
 
 #: classes/pref/prefs.php:989
-#, fuzzy
 msgid "You can override colors, fonts and layout of your currently selected theme with custom CSS declarations here."
-msgstr "Sie können Farben, Schriftarten und das Layout Ihres aktuell gewählten Themas mit einem eigenen CSS-Stylesheet überschreiben. <a target=\"_blank\" class=\"visibleLink\" href=\"%s\">Diese Datei</a> kann als Grundlage benutzt werden."
+msgstr ""
+"Sie können Farben, Schriftarten und das Layout Ihres aktuell gewählten "
+"Themas mit einem eigenen CSS-Stylesheet überschreiben."
 
 #: classes/pref/prefs.php:1024
 msgid "Create profile"
@@ -2316,9 +2316,8 @@ msgid "Include settings"
 msgstr "Inklusive Einstellungen"
 
 #: classes/pref/feeds.php:1313
-#, fuzzy
 msgid "Published OPML"
-msgstr "Veröffentlicht"
+msgstr "OPML veröffentlicht"
 
 #: classes/pref/feeds.php:1315
 msgid "Your OPML can be published publicly and can be subscribed by anyone who knows the URL below."
@@ -2341,9 +2340,8 @@ msgid "Published & shared articles / Generated feeds"
 msgstr "Veröffentlichte & geteilte Artikel / erzeugte Feeds"
 
 #: classes/pref/feeds.php:1330
-#, fuzzy
 msgid "Published articles can be subscribed by anyone who knows the following URL:"
-msgstr "Ihre OPML können veröffentlicht werden, so dass jeder, der die URL kennt, diese abonnieren kann."
+msgstr "Mit der folgenden URL können sie veröffentlichte Artikel beobachten:"
 
 #: classes/pref/feeds.php:1338
 msgid "Display URL"
@@ -2628,9 +2626,8 @@ msgid "Inline article content"
 msgstr "Artikelinhalt"
 
 #: plugins/toggle_sidebar/init.php:23
-#, fuzzy
 msgid "Toggle feedlist"
-msgstr "Feedliste verbergen"
+msgstr "Feed-Liste verbergen"
 
 #: plugins/import_export/init.php:54
 msgid "Import and export"
@@ -2708,7 +2705,7 @@ msgstr "Fehler erklärt"
 
 #: js/AppBase.js:408
 msgid "Fatal error"
-msgstr ""
+msgstr "Schwerwiegender Fehler"
 
 #: js/Article.js:33
 msgid "Please enter new score for selected articles:"
@@ -3123,7 +3120,7 @@ msgstr "<span onclick=\"App.explainError(3)\">Aktualisierungs-Dienst aktualisier
 
 #: js/AppBase.js:458
 msgid "Unhandled exception"
-msgstr ""
+msgstr "Schwerwiegender Fehler: (Unhandled Exception)"
 
 #: js/Article.js:229
 msgid "Edit article Tags"

BIN
locale/es_ES/LC_MESSAGES/messages.mo


+ 22 - 15
locale/es_ES/LC_MESSAGES/messages.po

@@ -8,15 +8,16 @@ msgstr ""
 "Project-Id-Version: tt-rss git\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2018-12-11 14:31+0300\n"
-"PO-Revision-Date: 2014-03-10 14:18+0100\n"
-"Last-Translator: DavidM <[email protected]>\n"
-"Language-Team: Español <[email protected]>\n"
+"PO-Revision-Date: 2019-01-10 10:12+0000\n"
+"Last-Translator: Jesus Leal <[email protected]>\n"
+"Language-Team: Spanish <https://weblate.tt-rss.org/projects/tt-rss/messages/"
+"es/>\n"
 "Language: es_ES\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 1.5.4\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 3.3\n"
 
 #: backend.php:73
 msgid "Use default"
@@ -200,11 +201,11 @@ msgstr "Problema de comunicación con el servidor."
 
 #: index.php:168
 msgid "Recent entries found in event log."
-msgstr ""
+msgstr "Se encontraron entradas recientes en el log de eventos."
 
 #: index.php:171
 msgid "Updates are available from Git."
-msgstr ""
+msgstr "Existen actualizaciones disponibles en Git."
 
 #: index.php:185
 msgid "Show articles"
@@ -496,7 +497,7 @@ msgstr "No se han encontrado fuentes."
 #: include/functions.php:928
 #, php-format
 msgid "%d min"
-msgstr ""
+msgstr "%d min"
 
 #: include/functions.php:1119
 msgid "Navigation"
@@ -664,7 +665,7 @@ msgstr "Invertir orden de titulares"
 
 #: include/functions.php:1159
 msgid "Toggle headline grouping"
-msgstr ""
+msgstr "Cambiar agrupación de titulares"
 
 #: include/functions.php:1160
 msgid "Debug feed update"
@@ -735,19 +736,23 @@ msgstr "Mostrar el diálogo de ayuda"
 
 #: include/functions.php:2462
 msgid "There is no error, the file uploaded with success"
-msgstr ""
+msgstr "No hay errores, el fichero se ha actualizado correctamente"
 
 #: include/functions.php:2463
 msgid "The uploaded file exceeds the upload_max_filesize directive in php.ini"
 msgstr ""
+"El fichero cargado excede la directiva upload_max_filesize directive en "
+"php.ini"
 
 #: include/functions.php:2464
 msgid "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form"
 msgstr ""
+"El fichero cargado excede la directiva MAX_FILE_SIZE especificada en el "
+"formulario HTML"
 
 #: include/functions.php:2465
 msgid "The uploaded file was only partially uploaded"
-msgstr ""
+msgstr "El fichero cargado solo fue subido parcialmente"
 
 #: include/functions.php:2466
 #, fuzzy
@@ -756,15 +761,15 @@ msgstr "No se ha cargado ningún archivo."
 
 #: include/functions.php:2467
 msgid "Missing a temporary folder"
-msgstr ""
+msgstr "No se ha encontrado una carpeta temporal"
 
 #: include/functions.php:2468
 msgid "Failed to write file to disk."
-msgstr ""
+msgstr "Fallo en la escritura en disco."
 
 #: include/functions.php:2469
 msgid "A PHP extension stopped the file upload."
-msgstr ""
+msgstr "Una extensión PHP detuvo la carga del fichero."
 
 #: include/login_form.php:84
 #: classes/handler/public.php:673
@@ -879,6 +884,8 @@ msgstr "Puede compartir este artículo con la siguiente URL única:"
 #: classes/dlg.php:189
 msgid "You are using default tt-rss password. Please change it in the Preferences (Personal data / Authentication)."
 msgstr ""
+"Está utilizando el password por defecto de tt-rss. Por favor, debe cambiarlo "
+"en Preferencias (Datos personales / Auntentificación)."
 
 #: classes/dlg.php:193
 #, fuzzy
@@ -1404,7 +1411,7 @@ msgstr "Buscar"
 #: classes/feeds.php:770
 #, php-format
 msgid "in %s"
-msgstr ""
+msgstr "en %s"
 
 #: classes/feeds.php:775
 msgid "Used for word stemming"

BIN
locale/fr_FR/LC_MESSAGES/messages.mo


+ 17 - 19
locale/fr_FR/LC_MESSAGES/messages.po

@@ -13,9 +13,10 @@ msgstr ""
 "Project-Id-Version: Tiny Tiny RSS\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2018-12-11 14:31+0300\n"
-"PO-Revision-Date: 2018-12-05 06:14+0000\n"
-"Last-Translator: Glandos <[email protected]>\n"
-"Language-Team: French <https://weblate.tt-rss.org/projects/tt-rss/messages/fr/>\n"
+"PO-Revision-Date: 2019-01-01 16:12+0000\n"
+"Last-Translator: Yann Soubeyrand <[email protected]>\n"
+"Language-Team: French <https://weblate.tt-rss.org/projects/tt-rss/messages/"
+"fr/>\n"
 "Language: fr_FR\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -199,7 +200,7 @@ msgstr "Un problème de communication avec le serveur est survenu."
 
 #: index.php:168
 msgid "Recent entries found in event log."
-msgstr ""
+msgstr "Des nouveaux évènements ont été journalisés."
 
 #: index.php:171
 msgid "Updates are available from Git."
@@ -335,9 +336,8 @@ msgstr "Basculer le mode écran large"
 
 #: index.php:245
 #: include/functions.php:1177
-#, fuzzy
 msgid "Toggle night mode"
-msgstr "Basculer le mode combiné"
+msgstr "(Dés)activer le mode nuit"
 
 #: index.php:246
 msgid "Keyboard shortcuts help"
@@ -1211,7 +1211,7 @@ msgstr "Aucun"
 
 #: classes/feeds.php:67
 msgid "Selection toggle:"
-msgstr "Sélectionner :"
+msgstr "Basculer la sélection :"
 
 #: classes/feeds.php:73
 msgid "Selection:"
@@ -2036,9 +2036,8 @@ msgid "Customize"
 msgstr "Personnaliser"
 
 #: classes/pref/prefs.php:563
-#, fuzzy
 msgid "default"
-msgstr "Utiliser la valeur par défaut"
+msgstr "défaut"
 
 #: classes/pref/prefs.php:625
 msgid "Register"
@@ -2126,9 +2125,10 @@ msgid "Incorrect password"
 msgstr "Mot de passe incorrect"
 
 #: classes/pref/prefs.php:989
-#, fuzzy
 msgid "You can override colors, fonts and layout of your currently selected theme with custom CSS declarations here."
-msgstr "Vous pouvez redéfinir les couleurs, les polices et la mise en page du thème actuellement sélectionné à l’aide de vos propres instructions CSS ici. <a target=\"_blank\" class=\"visibleLink\" href=\"%s\">Ce fichier</a> peut être utilisé comme base de départ."
+msgstr ""
+"Vous pouvez ici redéfinir les couleurs, les polices et la mise en page du "
+"thème actuellement sélectionné à l’aide de vos propres instructions CSS."
 
 #: classes/pref/prefs.php:1024
 msgid "Create profile"
@@ -2316,9 +2316,8 @@ msgid "Include settings"
 msgstr "Inclure les paramètres"
 
 #: classes/pref/feeds.php:1313
-#, fuzzy
 msgid "Published OPML"
-msgstr "Publiés"
+msgstr "OPML publiés"
 
 #: classes/pref/feeds.php:1315
 msgid "Your OPML can be published publicly and can be subscribed by anyone who knows the URL below."
@@ -2341,9 +2340,9 @@ msgid "Published & shared articles / Generated feeds"
 msgstr "Articles publiés et partagés / Flux générés"
 
 #: classes/pref/feeds.php:1330
-#, fuzzy
 msgid "Published articles can be subscribed by anyone who knows the following URL:"
-msgstr "Votre fichier OPML peut être publié et toute personne qui connaît l’adresse indiquée ci-dessous peut s’y abonner."
+msgstr ""
+"Quiconque connaît l'adresse suivante peut s’abonner à vos articles publiés :"
 
 #: classes/pref/feeds.php:1338
 msgid "Display URL"
@@ -2628,9 +2627,8 @@ msgid "Inline article content"
 msgstr "Simplifier le contenu de l’article"
 
 #: plugins/toggle_sidebar/init.php:23
-#, fuzzy
 msgid "Toggle feedlist"
-msgstr "Contracter la liste des flux"
+msgstr "Afficher/masquer la liste des flux"
 
 #: plugins/import_export/init.php:54
 msgid "Import and export"
@@ -2708,7 +2706,7 @@ msgstr "Erreur expliquée"
 
 #: js/AppBase.js:408
 msgid "Fatal error"
-msgstr ""
+msgstr "Erreur fatale"
 
 #: js/Article.js:33
 msgid "Please enter new score for selected articles:"
@@ -3123,7 +3121,7 @@ msgstr "<span onclick=\"App.explainError(3)\">Le service de mise-à-jour ne met
 
 #: js/AppBase.js:458
 msgid "Unhandled exception"
-msgstr ""
+msgstr "Exception non gérée"
 
 #: js/Article.js:229
 msgid "Edit article Tags"

BIN
locale/it_IT/LC_MESSAGES/messages.mo


+ 17 - 18
locale/it_IT/LC_MESSAGES/messages.po

@@ -10,9 +10,10 @@ msgstr ""
 "Project-Id-Version: Tiny Tiny RSS\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2018-12-11 14:31+0300\n"
-"PO-Revision-Date: 2018-12-04 03:09+0000\n"
-"Last-Translator: Stefano D. <[email protected]>\n"
-"Language-Team: Italian <https://weblate.tt-rss.org/projects/tt-rss/messages/it/>\n"
+"PO-Revision-Date: 2018-12-13 18:19+0000\n"
+"Last-Translator: Dario Di Ludovico <[email protected]>\n"
+"Language-Team: Italian <https://weblate.tt-rss.org/projects/tt-rss/messages/"
+"it/>\n"
 "Language: it_IT\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -196,7 +197,7 @@ msgstr "Problema di comunicazione con il server."
 
 #: index.php:168
 msgid "Recent entries found in event log."
-msgstr ""
+msgstr "Nuove voci nel registro degli eventi."
 
 #: index.php:171
 msgid "Updates are available from Git."
@@ -332,9 +333,8 @@ msgstr "Modalità widescreen"
 
 #: index.php:245
 #: include/functions.php:1177
-#, fuzzy
 msgid "Toggle night mode"
-msgstr "Attiva/disattiva modalità combinata"
+msgstr "Attiva/disattiva modalità notturna"
 
 #: index.php:246
 msgid "Keyboard shortcuts help"
@@ -2033,9 +2033,8 @@ msgid "Customize"
 msgstr "Personalizza"
 
 #: classes/pref/prefs.php:563
-#, fuzzy
 msgid "default"
-msgstr "Predefinito"
+msgstr "predefinito"
 
 #: classes/pref/prefs.php:625
 msgid "Register"
@@ -2123,9 +2122,10 @@ msgid "Incorrect password"
 msgstr "Password sbagliata"
 
 #: classes/pref/prefs.php:989
-#, fuzzy
 msgid "You can override colors, fonts and layout of your currently selected theme with custom CSS declarations here."
-msgstr "Si possono cambiare i colori, i caratteri e la disposizione del tema correntemente selezionato attraverso le dichiarazioni CSS personalizzate. <a target=\"_blank\" class=\"visibleLink\" href=\"%s\">Questo file</a> può essere usato come esempio."
+msgstr ""
+"Si possono cambiare i colori, i caratteri e la disposizione del tema "
+"correntemente selezionato attraverso le dichiarazioni CSS personalizzate."
 
 #: classes/pref/prefs.php:1024
 msgid "Create profile"
@@ -2313,9 +2313,8 @@ msgid "Include settings"
 msgstr "Includi le impostazioni"
 
 #: classes/pref/feeds.php:1313
-#, fuzzy
 msgid "Published OPML"
-msgstr "Pubblicati"
+msgstr "Pubblicati in OPML"
 
 #: classes/pref/feeds.php:1315
 msgid "Your OPML can be published publicly and can be subscribed by anyone who knows the URL below."
@@ -2338,9 +2337,10 @@ msgid "Published & shared articles / Generated feeds"
 msgstr "Articoli pubblicati e condivisi / Notiziari generati"
 
 #: classes/pref/feeds.php:1330
-#, fuzzy
 msgid "Published articles can be subscribed by anyone who knows the following URL:"
-msgstr "Il tuo OPML può essere reso pubblico e può essere sottoscritto da chiunque conosca l'URL seguente."
+msgstr ""
+"Gli articoli pubblicati possono essere sottoscritti da chiunque conosca "
+"l'URL seguente:"
 
 #: classes/pref/feeds.php:1338
 msgid "Display URL"
@@ -2625,9 +2625,8 @@ msgid "Inline article content"
 msgstr "Contenuto completo dell'articolo"
 
 #: plugins/toggle_sidebar/init.php:23
-#, fuzzy
 msgid "Toggle feedlist"
-msgstr "Riduci elenco notiziari"
+msgstr "Attiva/disattiva la lista dei feed"
 
 #: plugins/import_export/init.php:54
 msgid "Import and export"
@@ -2705,7 +2704,7 @@ msgstr "Errore spiegato"
 
 #: js/AppBase.js:408
 msgid "Fatal error"
-msgstr ""
+msgstr "Errore fatale"
 
 #: js/Article.js:33
 msgid "Please enter new score for selected articles:"
@@ -3120,7 +3119,7 @@ msgstr "<span onclick=\"App.explainError(3)\">Il daemon di aggiornamento non sta
 
 #: js/AppBase.js:458
 msgid "Unhandled exception"
-msgstr ""
+msgstr "Eccezione non gestita"
 
 #: js/Article.js:229
 msgid "Edit article Tags"

BIN
locale/nl_NL/LC_MESSAGES/messages.mo


+ 36 - 32
locale/nl_NL/LC_MESSAGES/messages.po

@@ -8,9 +8,10 @@ msgstr ""
 "Project-Id-Version: tt-rss git\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2018-12-11 14:31+0300\n"
-"PO-Revision-Date: 2018-12-10 00:37+0000\n"
+"PO-Revision-Date: 2018-12-13 18:19+0000\n"
 "Last-Translator: Patrick Ahles <[email protected]>\n"
-"Language-Team: Dutch <https://weblate.tt-rss.org/projects/tt-rss/messages/nl/>\n"
+"Language-Team: Dutch <https://weblate.tt-rss.org/projects/tt-rss/messages/nl/"
+">\n"
 "Language: nl_NL\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -197,7 +198,7 @@ msgstr "Communicatieprobleem met de server."
 
 #: index.php:168
 msgid "Recent entries found in event log."
-msgstr ""
+msgstr "Recente meldingen gevonden in het gebeurtenissenlogboek."
 
 #: index.php:171
 msgid "Updates are available from Git."
@@ -333,9 +334,8 @@ msgstr "Wisselen breedbeeldmodus"
 
 #: index.php:245
 #: include/functions.php:1177
-#, fuzzy
 msgid "Toggle night mode"
-msgstr "In/uitschakelen gecombineerde modus"
+msgstr "In/uitschakelen nacht modus"
 
 #: index.php:246
 msgid "Keyboard shortcuts help"
@@ -2034,9 +2034,8 @@ msgid "Customize"
 msgstr "Aanpassen"
 
 #: classes/pref/prefs.php:563
-#, fuzzy
 msgid "default"
-msgstr "Standaard"
+msgstr "standaard"
 
 #: classes/pref/prefs.php:625
 msgid "Register"
@@ -2124,9 +2123,10 @@ msgid "Incorrect password"
 msgstr "Onjuist wachtwoord"
 
 #: classes/pref/prefs.php:989
-#, fuzzy
 msgid "You can override colors, fonts and layout of your currently selected theme with custom CSS declarations here."
-msgstr "U kunt door de CSS-declaraties aan te passen de kleuren, lettertypen en lay-out van uw huidige thema hier aanpassen. <a target=\"_blank\" class=\"visibleLink\" href=\"%s\">Dit bestand</a> kan als richtlijn worden gebruikt."
+msgstr ""
+"U kunt door de CSS-declaraties aan te passen de kleuren, lettertypen en lay-"
+"out van uw huidige thema hier aanpassen."
 
 #: classes/pref/prefs.php:1024
 msgid "Create profile"
@@ -2314,9 +2314,8 @@ msgid "Include settings"
 msgstr "Toevoegingsinstellingen"
 
 #: classes/pref/feeds.php:1313
-#, fuzzy
 msgid "Published OPML"
-msgstr "Gepubliceerd"
+msgstr "Gepubliceerde OPML"
 
 #: classes/pref/feeds.php:1315
 msgid "Your OPML can be published publicly and can be subscribed by anyone who knows the URL below."
@@ -2339,9 +2338,10 @@ msgid "Published & shared articles / Generated feeds"
 msgstr "Gepubliceerde & gedeelde artikelen / Gegenereerde feeds"
 
 #: classes/pref/feeds.php:1330
-#, fuzzy
 msgid "Published articles can be subscribed by anyone who knows the following URL:"
-msgstr "Uw OPML kan openbaar worden gepubliceerd en er kan op worden geabonneerd door iedereen die de URL hieronder kent."
+msgstr ""
+"Iedereen die de volgende URL kent kan zich abonneeren op de gepubliceerde "
+"artikelen:"
 
 #: classes/pref/feeds.php:1338
 msgid "Display URL"
@@ -2626,7 +2626,6 @@ msgid "Inline article content"
 msgstr "Artikelinhoud weergeven"
 
 #: plugins/toggle_sidebar/init.php:23
-#, fuzzy
 msgid "Toggle feedlist"
 msgstr "Feedlijst inklappen"
 
@@ -2706,7 +2705,7 @@ msgstr "Foutuitleg"
 
 #: js/AppBase.js:408
 msgid "Fatal error"
-msgstr ""
+msgstr "Fatale fout"
 
 #: js/Article.js:33
 msgid "Please enter new score for selected articles:"
@@ -2752,7 +2751,10 @@ msgstr "Abonneren op feed"
 
 #: js/CommonDialogs.js:96
 msgid "Failed to parse output. This can indicate server timeout and/or network issues. Backend output was logged to browser console."
-msgstr "Kan de uitvoer niet ontleden. Dit kan een server timeout en/of netwerkproblemen aangeven. Backend-output is naar de browser-console geschreven."
+msgstr ""
+"Kan de uitvoer niet ontleden. Dit kan een server-timeout en/of "
+"netwerkproblemen aangeven. Backend-output is naar de browser-console "
+"geschreven."
 
 #: js/CommonDialogs.js:111
 #, perl-format
@@ -2906,7 +2908,7 @@ msgstr "Open origineel artikel"
 
 #: js/Headlines.js:1195
 msgid "Display article URL"
-msgstr "Toon artikel URL"
+msgstr "Toon artikel-URL"
 
 #: js/Headlines.js:1302
 msgid "Assign label"
@@ -2939,7 +2941,9 @@ msgstr "Categorie verwijderen"
 #: js/PrefFeedTree.js:140
 #, perl-format
 msgid "Remove category %s? Any nested feeds would be placed into Uncategorized."
-msgstr "Categorie %s verwijderen? elke genestelde feed zal in de rubriek 'Ongecategoriseerd' worden geplaatst."
+msgstr ""
+"Categorie %s verwijderen? Elke genestelde feed zal in de rubriek "
+"'Ongecategoriseerd' worden geplaatst."
 
 #: js/PrefFeedTree.js:153
 msgid "Unsubscribe from selected feeds?"
@@ -2967,7 +2971,7 @@ msgstr "Categorie hernoemen in:"
 
 #: js/PrefFeedTree.js:327
 msgid "Category title:"
-msgstr "Categorie titel:"
+msgstr "Categorietitel:"
 
 #: js/PrefFeedTree.js:351
 msgid "Subscribing to feeds..."
@@ -3045,7 +3049,7 @@ msgstr "Wis opgeslagen data voor deze plug-in?"
 
 #: js/PrefHelpers.js:168
 msgid "Please choose an OPML file first."
-msgstr "kies eerst een OPML-bestand aub."
+msgstr "Kies eerst een OPML-bestand aub."
 
 #: js/PrefHelpers.js:192
 msgid "OPML Import"
@@ -3065,7 +3069,7 @@ msgstr "Verwante artikelen"
 
 #: plugins/share/share_prefs.js:3
 msgid "This will invalidate all previously shared article URLs. Continue?"
-msgstr "Dit zal all eerder gedeelde artikel-URL's ongeldig maken. Doorgaan?"
+msgstr "Dit zal alle eerder gedeelde artikel-URL's ongeldig maken. Doorgaan?"
 
 #: plugins/share/share.js:10
 msgid "Share article by URL"
@@ -3090,7 +3094,7 @@ msgstr "Artikel doorsturen per e-mail"
 
 #: plugins/mail/mail.js:30
 msgid "Error sending email:"
-msgstr "Fout bij verzenden van email:"
+msgstr "Fout bij verzenden van e-mail:"
 
 #: plugins/import_export/import_export.js:13
 msgid "Export Data"
@@ -3121,15 +3125,15 @@ msgstr "<span onclick=\"App.explainError(3)\">Update daemon werkt geen feeds bij
 
 #: js/AppBase.js:458
 msgid "Unhandled exception"
-msgstr ""
+msgstr "Niet verwerkte uitzondering"
 
 #: js/Article.js:229
 msgid "Edit article Tags"
-msgstr "Bewerk artikel tags"
+msgstr "Bewerk artikel-tags"
 
 #: js/Article.js:233
 msgid "Saving article tags..."
-msgstr "Artikel tags opslaan..."
+msgstr "Artikel-tags opslaan..."
 
 #: js/CommonDialogs.js:13
 msgid "Upload complete."
@@ -3145,11 +3149,11 @@ msgstr "Upload mislukt."
 
 #: js/CommonDialogs.js:31
 msgid "Removing feed icon..."
-msgstr "Opgeslagen feed pictogram verwijderen..."
+msgstr "Opgeslagen feedpictogram verwijderen..."
 
 #: js/CommonDialogs.js:36
 msgid "Feed icon removed."
-msgstr "Feed pictogram verwijderd."
+msgstr "Feedpictogram verwijderd."
 
 #: js/CommonDialogs.js:54
 msgid "Uploading, please wait..."
@@ -3290,11 +3294,11 @@ msgstr "Geselecteerde filters verwijderen..."
 #: js/PrefHelpers.js:5
 #: plugins/share/share_prefs.js:4
 msgid "Clearing URLs..."
-msgstr "URLs opruimen..."
+msgstr "URL's opruimen..."
 
 #: js/PrefHelpers.js:8
 msgid "Generated URLs cleared."
-msgstr "Genereerde URLs gewist."
+msgstr "Genereerde URL's gewist."
 
 #: js/PrefHelpers.js:50
 msgid "Removing selected profiles..."
@@ -3311,7 +3315,7 @@ msgstr "Aan 't importeren, even wachten aub..."
 
 #: js/PrefLabelTree.js:69
 msgid "Label Editor"
-msgstr "Label editor"
+msgstr "Labeleditor"
 
 #: js/PrefLabelTree.js:126
 msgid "Reset selected labels to default colors?"
@@ -3359,7 +3363,7 @@ msgstr "Wachtwoord van geselecteerde gebruiker opnieuw instellen?"
 
 #: js/PrefUsers.js:67
 msgid "Resetting password for selected user..."
-msgstr "Wachtwoord van geselecteerde gebruiker opnieuw instellen..."
+msgstr "Wachtwoord van geselecteerde gebruiker opnieuw aan het instellen..."
 
 #: js/PrefUsers.js:82
 msgid "Remove selected users? Neither default admin nor your account will be removed."
@@ -3396,7 +3400,7 @@ msgstr "Artikel notitie opslaan..."
 
 #: plugins/share/share_prefs.js:9
 msgid "Shared URLs cleared."
-msgstr "Gedeelde URLs opgeruimd."
+msgstr "Gedeelde URL's opgeruimd."
 
 #: plugins/share/share.js:15
 msgid "Trying to change URL..."

BIN
locale/sv_SE/LC_MESSAGES/messages.mo


File diff suppressed because it is too large
+ 196 - 229
locale/sv_SE/LC_MESSAGES/messages.po


BIN
locale/zh_CN/LC_MESSAGES/messages.mo


+ 13 - 18
locale/zh_CN/LC_MESSAGES/messages.po

@@ -9,9 +9,10 @@ msgstr ""
 "Project-Id-Version: Tiny Tiny RSS\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2018-12-11 14:31+0300\n"
-"PO-Revision-Date: 2018-12-04 13:27+0000\n"
-"Last-Translator: Henry Wang <[email protected]>\n"
-"Language-Team: Chinese (Simplified) <https://weblate.tt-rss.org/projects/tt-rss/messages/zh_Hans/>\n"
+"PO-Revision-Date: 2018-12-13 18:18+0000\n"
+"Last-Translator: Ptsa Daniel <[email protected]>\n"
+"Language-Team: Chinese (Simplified) <https://weblate.tt-rss.org/projects/"
+"tt-rss/messages/zh_Hans/>\n"
 "Language: zh_CN\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -195,7 +196,7 @@ msgstr "连接服务器出错."
 
 #: index.php:168
 msgid "Recent entries found in event log."
-msgstr ""
+msgstr "在事件日志中找到的最近条目."
 
 #: index.php:171
 msgid "Updates are available from Git."
@@ -331,9 +332,8 @@ msgstr "切换宽屏模式"
 
 #: index.php:245
 #: include/functions.php:1177
-#, fuzzy
 msgid "Toggle night mode"
-msgstr "切换合并模式"
+msgstr "切换夜间模式"
 
 #: index.php:246
 msgid "Keyboard shortcuts help"
@@ -2029,7 +2029,6 @@ msgid "Customize"
 msgstr "自定义"
 
 #: classes/pref/prefs.php:563
-#, fuzzy
 msgid "default"
 msgstr "默认"
 
@@ -2119,9 +2118,8 @@ msgid "Incorrect password"
 msgstr "密码错误"
 
 #: classes/pref/prefs.php:989
-#, fuzzy
 msgid "You can override colors, fonts and layout of your currently selected theme with custom CSS declarations here."
-msgstr "您可以通过自定义 CSS 来更改颜色,字体和版式。具体可参考 <a target=\"_blank\" class=\"visibleLink\" href=\"%s\">本文件</a>。"
+msgstr "您可以通过自定义 CSS 来更改颜色,字体和版式。"
 
 #: classes/pref/prefs.php:1024
 msgid "Create profile"
@@ -2308,9 +2306,8 @@ msgid "Include settings"
 msgstr "包含设置"
 
 #: classes/pref/feeds.php:1313
-#, fuzzy
 msgid "Published OPML"
-msgstr "发布"
+msgstr "发布OPML"
 
 #: classes/pref/feeds.php:1315
 msgid "Your OPML can be published publicly and can be subscribed by anyone who knows the URL below."
@@ -2318,7 +2315,7 @@ msgstr "您可以公开发布您的 OPML 。网上的任何人都可以通过如
 
 #: classes/pref/feeds.php:1317
 msgid "Published OPML does not include your Tiny Tiny RSS settings, feeds that require authentication or feeds hidden from Popular feeds."
-msgstr ""
+msgstr "已发布的OPML中不包括您的Tiny Tiny RSS设置,需要身份验证的信息源或者最受欢迎的信息源中隐藏的信息源."
 
 #: classes/pref/feeds.php:1319
 msgid "Public OPML URL"
@@ -2333,9 +2330,8 @@ msgid "Published & shared articles / Generated feeds"
 msgstr "已发布的文章和生成的信息源"
 
 #: classes/pref/feeds.php:1330
-#, fuzzy
 msgid "Published articles can be subscribed by anyone who knows the following URL:"
-msgstr "您可以公开发布您的 OPML 。网上的任何人都可以通过如下 URL 订阅该文件。"
+msgstr "知道以下网址的任何人都可以订阅已发布的文章:"
 
 #: classes/pref/feeds.php:1338
 msgid "Display URL"
@@ -2620,9 +2616,8 @@ msgid "Inline article content"
 msgstr "Inline 文章内容"
 
 #: plugins/toggle_sidebar/init.php:23
-#, fuzzy
 msgid "Toggle feedlist"
-msgstr "收缩侧边栏"
+msgstr "切换侧边栏"
 
 #: plugins/import_export/init.php:54
 msgid "Import and export"
@@ -2697,7 +2692,7 @@ msgstr "Error释义"
 
 #: js/AppBase.js:408
 msgid "Fatal error"
-msgstr ""
+msgstr "致命错误"
 
 #: js/Article.js:33
 msgid "Please enter new score for selected articles:"
@@ -3104,7 +3099,7 @@ msgstr "<span onclick=\"App.explainError(3)\">更新程序未更新订阅源.</s
 
 #: js/AppBase.js:458
 msgid "Unhandled exception"
-msgstr ""
+msgstr "未处理的异常"
 
 #: js/Article.js:229
 msgid "Edit article Tags"

+ 1 - 2
plugins/af_psql_trgm/init.php

@@ -202,8 +202,7 @@ class Af_Psql_Trgm extends Plugin {
 				print "<ul class=\"panel panel-scrollable list list-unstyled\">";
 				foreach ($enabled_feeds as $f) {
 					print "<li>" .
-						"<img src='images/pub_set.png'
-							style='vertical-align : middle'> <a href='#'
+						"<i class='material-icons'>rss_feed</i> <a href='#'
 							onclick='CommonDialogs.editFeed($f)'>" .
 						Feeds::getFeedTitle($f) . "</a></li>";
 				}

+ 3 - 3
plugins/af_readability/init.php

@@ -93,8 +93,7 @@ class Af_Readability extends Plugin {
 			print "<ul class='panel panel-scrollable list list-unstyled'>";
 			foreach ($enabled_feeds as $f) {
 				print "<li>" .
-					"<img src='images/pub_set.png'
-						style='vertical-align : middle'> <a href='#'
+					"<i class='material-icons'>rss_feed</i> <a href='#'
 						onclick='CommonDialogs.editFeed($f)'>".
 					Feeds::getFeedTitle($f) . "</a></li>";
 			}
@@ -149,6 +148,7 @@ class Af_Readability extends Plugin {
 	}
 
 	public function extract_content($url) {
+
 		global $fetch_effective_url;
 
 		$tmp = fetch_file_contents([
@@ -159,7 +159,7 @@ class Af_Readability extends Plugin {
 		if ($tmp && mb_strlen($tmp) < 1024 * 500) {
 			$tmpdoc = new DOMDocument("1.0", "UTF-8");
 
-			if (!$tmpdoc->loadHTML('<?xml encoding="utf-8" ?>\n' . $tmp))
+			if (!$tmpdoc->loadHTML($tmp))
 				return false;
 
 			if (strtolower($tmpdoc->encoding) != 'utf-8') {

+ 9 - 6
prefs.php

@@ -84,12 +84,15 @@
 	<?php
 		foreach (PluginHost::getInstance()->get_plugins() as $n => $p) {
 			if (method_exists($p, "get_prefs_js")) {
-				echo "try {";
-				echo JShrink\Minifier::minify($p->get_prefs_js());
-				echo "} catch (e) {
-				 	console.warn('failed to initialize plugin JS: $n');
-					console.warn(e);
-				}";
+				$script = $p->get_prefs_js();
+
+				if ($script) {
+					echo "try {
+					    $script
+					} catch (e) {
+                        console.warn('failed to initialize plugin JS: $n', e);
+                    }";
+				}
 			}
 		}
 

+ 1 - 1
themes/compact.css

@@ -9,7 +9,7 @@ body.ttrss_main.ttrss_index.flat .cdm .content,
 body.ttrss_main.ttrss_index.flat .post .content {
   font-size: 12px ! important;
 }
-body.ttrss_main.ttrss_index.flat div[id*=RROW] i {
+body.ttrss_main.ttrss_index.flat div[id*=RROW] i.material-icons {
   font-size: 18px;
 }
 body.ttrss_main.ttrss_index.flat .hl,

+ 1 - 1
themes/compact.css.map

@@ -1 +1 @@
-{"version":3,"sources":["compact.less"],"names":[],"mappings":"QAAQ;AAER,IAAI,WAAW,YAAY,KAEzB,UAAS,UAAW;EAClB,2BAAA;;AAHJ,IAAI,WAAW,YAAY,KAMzB,WAAW;AANb,IAAI,WAAW,YAAY,KAOzB;AAPF,IAAI,WAAW,YAAY,KAQzB;AARF,IAAI,WAAW,YAAY,KASzB,KAAK;AATP,IAAI,WAAW,YAAY,KAUzB,MAAM;EACJ,2BAAA;;AAXJ,IAAI,WAAW,YAAY,KAczB,IAAG,UACD;EACE,eAAA;;AAhBN,IAAI,WAAW,YAAY,KAoBzB;AApBF,IAAI,WAAW,YAAY,KAqBzB,MAAM,QAAQ;AArBhB,IAAI,WAAW,YAAY,KAsBzB,eAAe,EAAC;AAtBlB,IAAI,WAAW,YAAY,KAuBzB,KAAK;EACH,2BAAA","file":"compact.css"}
+{"version":3,"sources":["compact.less"],"names":[],"mappings":"QAAQ;AAER,IAAI,WAAW,YAAY,KAEzB,UAAS,UAAW;EAClB,2BAAA;;AAHJ,IAAI,WAAW,YAAY,KAMzB,WAAW;AANb,IAAI,WAAW,YAAY,KAOzB;AAPF,IAAI,WAAW,YAAY,KAQzB;AARF,IAAI,WAAW,YAAY,KASzB,KAAK;AATP,IAAI,WAAW,YAAY,KAUzB,MAAM;EACJ,2BAAA;;AAXJ,IAAI,WAAW,YAAY,KAczB,IAAG,UACD,EAAC;EACC,eAAA;;AAhBN,IAAI,WAAW,YAAY,KAoBzB;AApBF,IAAI,WAAW,YAAY,KAqBzB,MAAM,QAAQ;AArBhB,IAAI,WAAW,YAAY,KAsBzB,eAAe,EAAC;AAtBlB,IAAI,WAAW,YAAY,KAuBzB,KAAK;EACH,2BAAA","file":"compact.css"}

+ 1 - 1
themes/compact.less

@@ -15,7 +15,7 @@ body.ttrss_main.ttrss_index.flat {
   }
 
   div[id*=RROW] {
-    i {
+    i.material-icons {
       font-size: 18px;
     }
   }

+ 16 - 9
themes/night.css

@@ -1043,6 +1043,15 @@ body.ttrss_main ul.list-unstyled {
 body.ttrss_main .text-center {
   text-align: center;
 }
+body.ttrss_main #prefFilterTestResultList .preview {
+  margin: 8px;
+}
+body.ttrss_main #prefFilterTestResultList .title {
+  font-weight: bold;
+}
+body.ttrss_main #prefFilterTestResultList .feed {
+  color: #b87d2c;
+}
 ::selection {
   background: #b87d2c;
   color: #333333;
@@ -1746,14 +1755,10 @@ body#sharepopup input {
 .flat li {
   padding: 2px;
 }
-.flat .filterRules span {
-  display: block;
-  color: green;
-}
 .flat #filterDlg_Matches span.filterRule {
   color: green;
 }
-.flat .filterRules span.inverse,
+.flat #filterTree .filterRules li.inverse,
 .flat #filterDlg_Matches span.filterRule.inverse {
   color: red;
 }
@@ -1794,7 +1799,7 @@ body#sharepopup input {
 .flat .dijitTree .dijitFolderOpened {
   display: none;
 }
-.flat .dijitTree .dijitTreeRowSelected .filterRules span {
+.flat .dijitTree .dijitTreeRowSelected .filterRules li {
   color: white;
 }
 .flat .dijitTree .dijitTreeRowSelected .dijitTreeExpando {
@@ -1821,11 +1826,13 @@ body#sharepopup input {
   float: right;
 }
 .flat .dijitTree .filterRules {
-  display: block;
-  color: #ccc;
   font-size: 12px;
-  margin-left: 100px;
   line-height: normal;
+  white-space: normal;
+  margin-left: 28px;
+}
+.flat .dijitTree .filterRules li {
+  color: green;
 }
 .flat .dijitTree .dijitTreeContainer {
   max-width: 100%;

File diff suppressed because it is too large
+ 1 - 1
themes/night.css.map


+ 16 - 9
themes/night_blue.css

@@ -1043,6 +1043,15 @@ body.ttrss_main ul.list-unstyled {
 body.ttrss_main .text-center {
   text-align: center;
 }
+body.ttrss_main #prefFilterTestResultList .preview {
+  margin: 8px;
+}
+body.ttrss_main #prefFilterTestResultList .title {
+  font-weight: bold;
+}
+body.ttrss_main #prefFilterTestResultList .feed {
+  color: #257aa7;
+}
 ::selection {
   background: #257aa7;
   color: #333333;
@@ -1746,14 +1755,10 @@ body#sharepopup input {
 .flat li {
   padding: 2px;
 }
-.flat .filterRules span {
-  display: block;
-  color: green;
-}
 .flat #filterDlg_Matches span.filterRule {
   color: green;
 }
-.flat .filterRules span.inverse,
+.flat #filterTree .filterRules li.inverse,
 .flat #filterDlg_Matches span.filterRule.inverse {
   color: red;
 }
@@ -1794,7 +1799,7 @@ body#sharepopup input {
 .flat .dijitTree .dijitFolderOpened {
   display: none;
 }
-.flat .dijitTree .dijitTreeRowSelected .filterRules span {
+.flat .dijitTree .dijitTreeRowSelected .filterRules li {
   color: white;
 }
 .flat .dijitTree .dijitTreeRowSelected .dijitTreeExpando {
@@ -1821,11 +1826,13 @@ body#sharepopup input {
   float: right;
 }
 .flat .dijitTree .filterRules {
-  display: block;
-  color: #ccc;
   font-size: 12px;
-  margin-left: 100px;
   line-height: normal;
+  white-space: normal;
+  margin-left: 28px;
+}
+.flat .dijitTree .filterRules li {
+  color: green;
 }
 .flat .dijitTree .dijitTreeContainer {
   max-width: 100%;

File diff suppressed because it is too large
+ 1 - 1
themes/night_blue.css.map


+ 0 - 24
vendor/JShrink/LICENSE

@@ -1,24 +0,0 @@
-Copyright (c) 2009, Robert Hafner
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
-    * Neither the name of the Stash Project nor the
-      names of its contributors may be used to endorse or promote products
-      derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL Robert Hafner BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 0 - 587
vendor/JShrink/Minifier.php

@@ -1,587 +0,0 @@
-<?php
-/*
- * This file is part of the JShrink package.
- *
- * (c) Robert Hafner <[email protected]>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * JShrink
- *
- *
- * @package    JShrink
- * @author     Robert Hafner <[email protected]>
- */
-
-namespace JShrink;
-
-/**
- * Minifier
- *
- * Usage - Minifier::minify($js);
- * Usage - Minifier::minify($js, $options);
- * Usage - Minifier::minify($js, array('flaggedComments' => false));
- *
- * @package JShrink
- * @author Robert Hafner <[email protected]>
- * @license http://www.opensource.org/licenses/bsd-license.php  BSD License
- */
-class Minifier
-{
-    /**
-     * The input javascript to be minified.
-     *
-     * @var string
-     */
-    protected $input;
-
-    /**
-     * The location of the character (in the input string) that is next to be
-     * processed.
-     *
-     * @var int
-     */
-    protected $index = 0;
-
-    /**
-     * The first of the characters currently being looked at.
-     *
-     * @var string
-     */
-    protected $a = '';
-
-    /**
-     * The next character being looked at (after a);
-     *
-     * @var string
-     */
-    protected $b = '';
-
-    /**
-     * This character is only active when certain look ahead actions take place.
-     *
-     *  @var string
-     */
-    protected $c;
-
-    /**
-     * Contains the options for the current minification process.
-     *
-     * @var array
-     */
-    protected $options;
-
-    /**
-     * Contains the default options for minification. This array is merged with
-     * the one passed in by the user to create the request specific set of
-     * options (stored in the $options attribute).
-     *
-     * @var array
-     */
-    protected static $defaultOptions = array('flaggedComments' => true);
-
-    /**
-     * Contains lock ids which are used to replace certain code patterns and
-     * prevent them from being minified
-     *
-     * @var array
-     */
-    protected $locks = array();
-
-    /**
-     * Takes a string containing javascript and removes unneeded characters in
-     * order to shrink the code without altering it's functionality.
-     *
-     * @param  string      $js      The raw javascript to be minified
-     * @param  array       $options Various runtime options in an associative array
-     * @throws \Exception
-     * @return bool|string
-     */
-    public static function minify($js, $options = array())
-    {
-        try {
-            ob_start();
-
-            $jshrink = new Minifier();
-            $js = $jshrink->lock($js);
-            $jshrink->minifyDirectToOutput($js, $options);
-
-            // Sometimes there's a leading new line, so we trim that out here.
-            $js = ltrim(ob_get_clean());
-            $js = $jshrink->unlock($js);
-            unset($jshrink);
-
-            return $js;
-
-        } catch (\Exception $e) {
-
-            if (isset($jshrink)) {
-                // Since the breakdownScript function probably wasn't finished
-                // we clean it out before discarding it.
-                $jshrink->clean();
-                unset($jshrink);
-            }
-
-            // without this call things get weird, with partially outputted js.
-            ob_end_clean();
-            throw $e;
-        }
-    }
-
-    /**
-     * Processes a javascript string and outputs only the required characters,
-     * stripping out all unneeded characters.
-     *
-     * @param string $js      The raw javascript to be minified
-     * @param array  $options Various runtime options in an associative array
-     */
-    protected function minifyDirectToOutput($js, $options)
-    {
-        $this->initialize($js, $options);
-        $this->loop();