summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--feedlist.js21
-rw-r--r--functions.php16
-rw-r--r--gears_init.js87
-rw-r--r--manifest.json18
-rw-r--r--tt-rss.js57
-rw-r--r--tt-rss.php2
-rw-r--r--viewfeed.js155
7 files changed, 309 insertions, 47 deletions
diff --git a/feedlist.js b/feedlist.js
index 8f1b5efec..582509e40 100644
--- a/feedlist.js
+++ b/feedlist.js
@@ -30,13 +30,25 @@ function viewCategory(cat) {
return false;
}
+function render_feedlist(data) {
+ try {
+
+ var f = document.getElementById("feeds-frame");
+ f.innerHTML = data;
+ cache_invalidate("FEEDLIST");
+ cache_inject("FEEDLIST", data, getInitParam("num_feeds"));
+ feedlist_init();
+
+ } catch (e) {
+ exception_error("render_feedlist", e);
+ }
+}
+
function feedlist_callback2(transport) {
try {
debug("feedlist_callback2");
if (!transport_error_check(transport)) return;
- var f = document.getElementById("feeds-frame");
- f.innerHTML = transport.responseText;
- feedlist_init();
+ render_feedlist(transport.responseText);
} catch (e) {
exception_error("feedlist_callback2", e);
}
@@ -257,6 +269,7 @@ function viewfeed(feed, subop, is_cat, subop_param, skip_history, offset) {
f.innerHTML = cache_find_param(cache_prefix + feed, unread_ctr);
request_counters();
+ remove_splash();
} else {
@@ -605,6 +618,8 @@ function request_counters_real() {
try {
+ if (offline_mode) return;
+
debug("requesting counters...");
var query = "backend.php?op=rpc&subop=getAllCounters";
diff --git a/functions.php b/functions.php
index 523c74944..80488b09f 100644
--- a/functions.php
+++ b/functions.php
@@ -3002,12 +3002,28 @@
print "<param key=\"sync_counters\" value=\"1\"/>";
+ $result = db_query($link, "SELECT COUNT(*) AS cf FROM
+ ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]);
+
+ $num_feeds = db_fetch_result($result, 0, "cf");
+
+ print "<param key=\"num_feeds\" value=\"".
+ (int)$num_feeds. "\"/>";
+
print "</init-params>";
}
function print_runtime_info($link) {
print "<runtime-info>";
+ $result = db_query($link, "SELECT COUNT(*) AS cf FROM
+ ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]);
+
+ $num_feeds = db_fetch_result($result, 0, "cf");
+
+ print "<param key=\"num_feeds\" value=\"".
+ (int)$num_feeds. "\"/>";
+
if (ENABLE_UPDATE_DAEMON) {
print "<param key=\"daemon_is_running\" value=\"".
sprintf("%d", file_is_locked("update_daemon.lock")) . "\"/>";
diff --git a/gears_init.js b/gears_init.js
new file mode 100644
index 000000000..3462d73e8
--- /dev/null
+++ b/gears_init.js
@@ -0,0 +1,87 @@
+// Copyright 2007, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// 2. 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.
+// 3. Neither the name of Google Inc. 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 AUTHOR ``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 THE AUTHOR 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.
+//
+// Sets up google.gears.*, which is *the only* supported way to access Gears.
+//
+// Circumvent this file at your own risk!
+//
+// In the future, Gears may automatically define google.gears.* without this
+// file. Gears may use these objects to transparently fix bugs and compatibility
+// issues. Applications that use the code below will continue to work seamlessly
+// when that happens.
+
+(function() {
+ // We are already defined. Hooray!
+ if (window.google && google.gears) {
+ return;
+ }
+
+ var factory = null;
+
+ // Firefox
+ if (typeof GearsFactory != 'undefined') {
+ factory = new GearsFactory();
+ } else {
+ // IE
+ try {
+ factory = new ActiveXObject('Gears.Factory');
+ // privateSetGlobalObject is only required and supported on IE Mobile on
+ // WinCE.
+ if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
+ factory.privateSetGlobalObject(this);
+ }
+ } catch (e) {
+ // Safari
+ if ((typeof navigator.mimeTypes != 'undefined')
+ && navigator.mimeTypes["application/x-googlegears"]) {
+ factory = document.createElement("object");
+ factory.style.display = "none";
+ factory.width = 0;
+ factory.height = 0;
+ factory.type = "application/x-googlegears";
+ document.documentElement.appendChild(factory);
+ }
+ }
+ }
+
+ // *Do not* define any objects if Gears is not installed. This mimics the
+ // behavior of Gears defining the objects in the future.
+ if (!factory) {
+ return;
+ }
+
+ // Now set up the objects, being careful not to overwrite anything.
+ //
+ // Note: In Internet Explorer for Windows Mobile, you can't add properties to
+ // the window object. However, global objects are automatically added as
+ // properties of the window object in all browsers.
+ if (!window.google) {
+ google = {};
+ }
+
+ if (!google.gears) {
+ google.gears = {factory: factory};
+ }
+})();
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 000000000..6dd6ecc9b
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,18 @@
+{
+ "betaManifestVersion": 1,
+ "version": "0",
+ "entries": [
+ { "url": "tt-rss.php"},
+ { "url": "tt-rss.css"},
+ { "url": "viewfeed.js"},
+ { "url": "feedlist.js"},
+ { "url": "functions.js"},
+ { "url": "tt-rss.js"},
+ { "url": "lib/scriptaculous/effects.js"},
+ { "url": "lib/scriptaculous/controls.js"},
+ { "url": "lib/scriptaculous/dragdrop.js"},
+ { "url": "lib/scriptaculous/scriptaculous.js"},
+ { "url": "lib/prototype.js"},
+ { "url": "gears_init.js"}
+ ]
+}
diff --git a/tt-rss.js b/tt-rss.js
index 17e33bf85..6048de057 100644
--- a/tt-rss.js
+++ b/tt-rss.js
@@ -19,6 +19,10 @@ var ver_offset = 0;
var hor_offset = 0;
var feeds_sort_by_unread = false;
var feedlist_sortable_enabled = false;
+var offline_mode = false;
+var store = false;
+var localServer = false;
+var db = false;
function activeFeedIsCat() {
return _active_feed_is_cat;
@@ -131,7 +135,11 @@ function backend_sanity_check_callback(transport) {
}
if (!transport.responseXML) {
- fatalError(3, "Sanity check: Received reply is not XML", transport.responseText);
+ if (!google.gears) {
+ fatalError(3, "Sanity check: Received reply is not XML", transport.responseText);
+ } else {
+ init_offline();
+ }
return;
}
@@ -369,6 +377,8 @@ function init() {
if (arguments.callee.done) return;
arguments.callee.done = true;
+ init_gears();
+
disableContainerChildren("headlinesToolbar", true);
Form.disable("main_toolbar_form");
@@ -500,7 +510,14 @@ function init_second_stage() {
daemon_refresh_only = getInitParam("daemon_refresh_only") == 1;
feeds_sort_by_unread = getInitParam("feeds_sort_by_unread") == 1;
- setTimeout('updateFeedList(false, false)', 50);
+ var fl = cache_find_param("FEEDLIST", getInitParam("num_feeds"));
+
+ if (fl) {
+ render_feedlist(fl);
+ request_counters();
+ } else {
+ setTimeout('updateFeedList(false, false)', 50);
+ }
debug("second stage ok");
@@ -720,6 +737,10 @@ function parse_runtime_info(elem) {
debug("RI: " + k + " => " + v);
+ if (k == "num_feeds") {
+ init_params[k] = v;
+ }
+
if (k == "new_version_available") {
var icon = document.getElementById("newVersionIcon");
if (icon) {
@@ -1451,3 +1472,35 @@ function feedBrowserSubscribe() {
}
}
+function init_gears() {
+ try {
+
+ if (google.gears) {
+ localServer = google.gears.factory.create("beta.localserver");
+ store = localServer.createManagedStore("tt-rss");
+ db = google.gears.factory.create('beta.database');
+ db.open('tt-rss');
+
+ db.execute("CREATE TABLE IF NOT EXISTS cache (id text, article text, param text, added text)");
+ }
+
+ cache_expire();
+
+ } catch (e) {
+ exception_error("init_gears", e);
+ }
+}
+
+function init_offline() {
+ try {
+ offline_mode = true;
+
+ render_feedlist(cache_find("FEEDLIST"));
+ document.getElementById("quickMenuChooser").disabled = true;
+
+ remove_splash();
+ } catch (e) {
+ exception_error("init_offline", e);
+ }
+}
+
diff --git a/tt-rss.php b/tt-rss.php
index 4ca516615..09e7d1bc9 100644
--- a/tt-rss.php
+++ b/tt-rss.php
@@ -49,6 +49,8 @@
<script type="text/javascript" charset="utf-8" src="feedlist.js?<?php echo $dt_add ?>"></script>
<script type="text/javascript" charset="utf-8" src="viewfeed.js?<?php echo $dt_add ?>"></script>
+ <script type="text/javascript" src="gears_init.js"></script>
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript">
diff --git a/viewfeed.js b/viewfeed.js
index 828a2e89c..fd811d7f5 100644
--- a/viewfeed.js
+++ b/viewfeed.js
@@ -362,14 +362,16 @@ function article_callback2(transport, id, feed_id) {
setTimeout('updateFeedList(false, false)', 50);
_reload_feedlist_after_view = false;
} else {
- var counters = transport.responseXML.getElementsByTagName("counters")[0];
+ if (transport.responseXML) {
+ var counters = transport.responseXML.getElementsByTagName("counters")[0];
- if (counters) {
- debug("parsing piggybacked counters: " + counters);
- parse_counters(counters, false);
- } else {
- debug("counters container not found in reply, requesting...");
- request_counters();
+ if (counters) {
+ debug("parsing piggybacked counters: " + counters);
+ parse_counters(counters, false);
+ } else {
+ debug("counters container not found in reply, requesting...");
+ request_counters();
+ }
}
}
@@ -1466,65 +1468,127 @@ function cdmWatchdog() {
function cache_inject(id, article, param) {
- if (!cache_check_param(id, param)) {
- debug("cache_article: miss: " + id + " [p=" + param + "]");
-
- var cache_obj = new Array();
-
- cache_obj["id"] = id;
- cache_obj["data"] = article;
- cache_obj["param"] = param;
+ try {
+ if (!cache_check_param(id, param)) {
+ debug("cache_article: miss: " + id + " [p=" + param + "]");
+
+
+ if (db) {
- article_cache.push(cache_obj);
+ var date = new Date();
+ var ts = Math.round(date.getTime() / 1000);
- } else {
- debug("cache_article: hit: " + id + " [p=" + param + "]");
+ db.execute("INSERT INTO cache (id, article, param, added) VALUES (?, ?, ?, ?)",
+ [id, article, param, ts]);
+ } else {
+
+ var cache_obj = new Array();
+
+ cache_obj["id"] = id;
+ cache_obj["data"] = article;
+ cache_obj["param"] = param;
+
+ article_cache.push(cache_obj);
+ }
+
+ } else {
+ debug("cache_article: hit: " + id + " [p=" + param + "]");
+ }
+ } catch (e) {
+ exception_error("cache_inject", e);
}
}
function cache_find(id) {
- for (var i = 0; i < article_cache.length; i++) {
- if (article_cache[i]["id"] == id) {
- return article_cache[i]["data"];
+
+ if (db) {
+ var rs = db.execute("SELECT article FROM cache WHERE id = ?", [id]);
+
+ if (rs.isValidRow()) {
+ return rs.field(0);
+ }
+
+ } else {
+ for (var i = 0; i < article_cache.length; i++) {
+ if (article_cache[i]["id"] == id) {
+ return article_cache[i]["data"];
+ }
}
}
return false;
}
function cache_find_param(id, param) {
- for (var i = 0; i < article_cache.length; i++) {
- if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
- return article_cache[i]["data"];
+
+ if (db) {
+ var rs = db.execute("SELECT article FROM cache WHERE id = ? AND param = ?",
+ [id, param]);
+
+ if (rs.isValidRow()) {
+ return rs.field(0);
+ }
+
+ } else {
+ for (var i = 0; i < article_cache.length; i++) {
+ if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
+ return article_cache[i]["data"];
+ }
}
}
return false;
}
function cache_check(id) {
- for (var i = 0; i < article_cache.length; i++) {
- if (article_cache[i]["id"] == id) {
- return true;
+
+ if (db) {
+ var rs = db.execute("SELECT COUNT(*) AS c FROM cache WHERE id = ?",
+ [id]);
+
+ if (rs.isValidRow()) {
+ return rs.field(0) != "0";
+ }
+
+ } else {
+ for (var i = 0; i < article_cache.length; i++) {
+ if (article_cache[i]["id"] == id) {
+ return true;
+ }
}
}
return false;
}
function cache_check_param(id, param) {
- for (var i = 0; i < article_cache.length; i++) {
-// debug("cache_check_param " + article_cache[i]["id"] + ":" +
-// article_cache[i]["param"] + " vs " + id + ":" + param);
+ if (db) {
+ var rs = db.execute("SELECT COUNT(*) AS c FROM cache WHERE id = ? AND param = ?",
+ [id, param]);
- if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
- return true;
+ if (rs.isValidRow()) {
+ return rs.field(0) != "0";
+ }
+
+ } else {
+ for (var i = 0; i < article_cache.length; i++) {
+ if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) {
+ return true;
+ }
}
}
return false;
}
function cache_expire() {
- while (article_cache.length > 25) {
- article_cache.shift();
+ if (db) {
+ var date = new Date();
+ var ts = Math.round(date.getTime() / 1000);
+
+ db.execute("DELETE FROM cache WHERE added < ? - 600", [ts]);
+
+ } else {
+ while (article_cache.length > 25) {
+ article_cache.shift();
+ }
}
}
@@ -1533,18 +1597,25 @@ function cache_empty() {
}
function cache_invalidate(id) {
- var i = 0
-
try {
- while (i < article_cache.length) {
- if (article_cache[i]["id"] == id) {
- debug("cache_invalidate: removed id " + id);
- article_cache.splice(i, 1);
- return true;
+ if (db) {
+ rs = db.execute("DELETE FROM cache WHERE id = ?", [id]);
+ return rs.rowsAffected != 0;
+ } else {
+
+ var i = 0
+
+ while (i < article_cache.length) {
+ if (article_cache[i]["id"] == id) {
+ debug("cache_invalidate: removed id " + id);
+ article_cache.splice(i, 1);
+ return true;
+ }
+ i++;
}
- i++;
}
+
debug("cache_invalidate: id not found: " + id);
return false;
} catch (e) {