Merge branch 'owncloud'

This commit is contained in:
Jeena 2013-09-20 14:12:23 +02:00
commit 5b2868233d
7 changed files with 439 additions and 90 deletions

View file

@ -73,6 +73,11 @@ button:active, a:active, .button:active {
padding: 10px 20px;
}
#login .backends label {
display: block;
margin-bottom: 1px;
}
label {
display: none;
}
@ -130,7 +135,7 @@ img {
}
@media screen and (width: 320px) {
#full > article * {
#full > article * , #full > article pre {
max-width: 300px !important;
overflow: auto;
}

View file

@ -11,6 +11,7 @@
<script src="js/App.js"></script>
<script src="js/TinyTinyRSS.js"></script>
<script src="js/OwnCloud.js"></script>
<script src="js/Login.js"></script>
<script src="js/jester.js"></script>
</head>
@ -61,6 +62,10 @@
<p class="smallogo">
<img src="img/icon-128.png" alt="Logo, an ape head">
</p>
<p class="backends">
<label class="button"><input type="radio" name="backend" value="TinyTinyRSS" checked="checked" /> Tiny Tiny RSS</label>
<label class="button"><input type="radio" name="backend" value="OwnCloud" /> OwnCloud News</label>
</p>
<p>
<label for="url">URL:</label>
<input class="button" type="text" name="url" id="url" value="" placeholder="http://example.com/tt-rss/" />

View file

@ -13,7 +13,7 @@ App.prototype.authenticate = function() {
};
App.prototype.after_login = function() {
App.prototype.after_login = function(backend) {
var request = window.navigator.mozApps.getSelf();
request.onsuccess = function() {
@ -92,12 +92,16 @@ App.prototype.after_login = function() {
this.changeToPage("#list");
this.ttrss = new TinyTinyRSS(this, localStorage.server_url, localStorage.session_id);
if(backend == "OwnCloud") {
this.backend = new OwnCloud(this, localStorage.server_url, localStorage.session_id);
} else {
this.backend = new TinyTinyRSS(this, localStorage.server_url, localStorage.session_id);
}
this.reload();
};
App.prototype.logout = function() {
this.ttrss.logOut();
this.backend.logOut();
this.unread_articles = [];
this.populateList();
this.login.log_out();
@ -131,7 +135,7 @@ App.prototype.setColor = function(color) {
App.prototype.reload = function() {
this.unread_articles = [];
$("#all-read").innerHTML = "❌";
this.ttrss.getUnreadFeeds(this.gotUnreadFeeds.bind(this));
this.backend.reload(this.gotUnreadFeeds.bind(this));
};
App.prototype.gotUnreadFeeds = function(new_articles) {
@ -149,7 +153,7 @@ App.prototype.gotUnreadFeeds = function(new_articles) {
this.unread_articles = this.unread_articles.concat(new_articles);
if(new_articles.length > 0) {
this.ttrss.getUnreadFeeds(this.gotUnreadFeeds.bind(this), this.unread_articles.length);
this.backend.getUnreadFeeds(this.gotUnreadFeeds.bind(this), this.unread_articles);
} else {
localStorage.unread_articles = JSON.stringify(this.unread_articles);
this.populateList();
@ -210,7 +214,9 @@ App.prototype.updateList = function() {
this.updatePieChart();
};
App.prototype.updatePieChart = function(all, unread) {
App.prototype.updatePieChart = function() {
if(!this.unread_articles) return; // happens on loginpage
var all = this.unread_articles.length;
var unread = 0;
@ -312,7 +318,7 @@ App.prototype.setCurrentRead = function() {
if(!article.set_unread) {
article.unread = false;
this.updateList();
this.ttrss.setArticleRead(article.id);
this.backend.setArticleRead(article);
}
article.set_unread = false;
@ -335,39 +341,39 @@ App.prototype.toggleCurrentUnread = function() {
}
this.updateList();
this.ttrss.setArticleUnread(article.id);
this.backend.setArticleUnread(article);
};
App.prototype.toggleAllRead = function() {
if($("#all-read").innerHTML == "❌") { // set all read
var ids = [];
var articles = [];
for (var i = 0; i < this.unread_articles.length; i++) {
var article = this.unread_articles[i];
article.unread = false;
article.set_unread = false;
ids.push(article.id);
articles.push(article);
}
$("#all-read").innerHTML = "&#10003;";
this.updateList();
this.ttrss.setArticleRead(ids.join(","));
this.backend.setArticlesRead(articles);
} else {
var ids = [];
var articles = [];
for (var i = 0; i < this.unread_articles.length; i++) {
var article = this.unread_articles[i];
article.unread = true;
article.set_unread = false;
ids.push(article.id);
articles.push(article);
}
$("#all-read").innerHTML = "&#10060;";
this.updateList();
this.ttrss.setArticleUnread(ids.join(","));
this.backend.setArticlesUnread(articles);
}
};
@ -379,13 +385,13 @@ App.prototype.toggleStarred = function() {
if(!article.marked) {
article.marked = true;
this.updateList();
this.ttrss.setArticleStarred(article.id);
this.backend.setArticleStarred(article);
$("#setstarred").innerHTML = "&#9733;";
}
else {
article.marked = false;
this.updateList();
this.ttrss.setArticleUnStarred(article.id);
this.backend.setArticleUnstarred(article);
$("#setstarred").innerHTML = "&#9734;";
}

View file

@ -1,11 +1,10 @@
function Login(app) {
this.app = app;
if(!this.is_logged_in()) {
this.log_in();
if(!this.onLine()) alert("You need to be on line to log in to your server.");
}
else this.app.after_login();
else this.app.after_login(localStorage.backend);
};
Login.prototype.onLine = function() {
@ -13,11 +12,22 @@ Login.prototype.onLine = function() {
};
Login.prototype.is_logged_in = function() {
return localStorage.server_url && localStorage.session_id;
return localStorage.backend && localStorage.server_url && localStorage.session_id;
};
Login.prototype.log_in = function() {
this.app.changeToPage("#login");
$("#login form").backend.forEach(function(o, i) {
o.addEventListener("change", function(e) {
if(e.target.checked) {
if(e.target.value == "OwnCloud") {
$("#url").placeholder = "http://example.com/owncloud/";
} else {
$("#url").placeholder = "http://example.com/tt-rss/";
}
}
});
});
$("#login form").addEventListener('submit', this.authenticate.bind(this));
};
@ -26,6 +36,9 @@ Login.prototype.authenticate = function(e) {
e.preventDefault();
e.stopPropagation();
var backend = "TinyTinyRSS";
if($("#login form").backend[1].checked) backend = "OwnCloud";
var server_url = $("#url").value;
var user = $("#un").value;
var password = $("#pw").value;
@ -45,6 +58,25 @@ Login.prototype.authenticate = function(e) {
}
var _this = this;
if(backend == "OwnCloud") {
OwnCloud.login(server_url, user, password, function(data) {
if(data.version) {
var auth = btoa(user + ':' + password);
localStorage.server_url = server_url;
localStorage.session_id = auth;
localStorage.backend = "OwnCloud";
_this.app.after_login(localStorage.backend);
$("#url").value = "";
$("#un").value = "";
$("#pw").value = "";
} else {
alert("Something went wrong, please check every input field and try again.");
}
});
} else {
TinyTinyRSS.login(server_url, user, password, function(data) {
if(data.error) {
if(data.error == "API_DISABLED") {
@ -58,13 +90,15 @@ Login.prototype.authenticate = function(e) {
} else {
localStorage.server_url = server_url;
localStorage.session_id = data.session_id;
_this.app.after_login();
localStorage.backend = "TinyTinyRSS";
_this.app.after_login(localStorage.backend);
$("#url").value = "";
$("#un").value = "";
$("#pw").value = "";
}
});
}
return false;
};

253
js/OwnCloud.js Normal file
View file

@ -0,0 +1,253 @@
function OwnCloud(app, server_url, user_pass_btoa) {
this.app = app;
this.server_url = server_url;
this.session_id = user_pass_btoa;
this.feeds = {};
var feeds = localStorage.feeds;
if(feeds) this.feeds = JSON.parse(feeds);
window.addEventListener("offline", this.onoffline.bind(this));
window.addEventListener("online", this.ononline.bind(this));
}
OwnCloud.prototype.onoffline = function() {
// Do nothing
};
OwnCloud.prototype.ononline = function() {
["read", "unread", "starred", "unstarred"].forEach(function(type) {
var articles = localStorage[type + "_articles"];
if(articles) {
var callback = function(ok) { if(ok) localStorage[type + "_articles"] = null }
this.call("setArticles" + type.capitalize(), [JSON.parse(articles), callback]);
}
});
};
OwnCloud.prototype.doOperation = function(method, operation, new_options, callback) {
if(!navigator.onLine) {
callback(null);
return;
}
var url = this.server_url + "/index.php/apps/news/api/v1-2/" + operation;
var options = {};
for (var key in new_options) {
options[key] = new_options[key];
}
if(method == "GET" || method == "HEAD") {
var a = [];
for(var key in options) {
a.push(key + "=" + options[key]);
}
url += "?" + a.join("&");
}
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
if(callback)
callback(JSON.parse(xhr.responseText));
} else {
if(xhr.status != 0) alert("error: " + xhr.status + " " + xhr.statusText);
if(callback) callback(null);
}
}
}
xhr.open(method, url, true);
xhr.withCredentials = true;
xhr.setRequestHeader('Authorization', 'Basic ' + this.session_id);
var body = JSON.stringify(options);
xhr.send(body);
}
OwnCloud.prototype.reload = function(callback) {
var _this = this;
this.getFeeds(function() { _this.getUnreadFeeds(callback); });
};
OwnCloud.prototype.getUnreadFeeds = function(callback, skip) {
if(skip) {
skip = skip[skip.length - 1].id;
}
var options = {
batchSize: 700,
offset: skip || 0,
type: 3,
id: 0,
getRead: false
};
var _this = this;
this.doOperation("GET", "items", options, function(data) {
var items = data.items;
function isFeedAvailable(o) {
return !!_this.feeds[o.feedId];
}
if(items.every(isFeedAvailable)) {
callback(items.map(_this.normalize_article, _this));
} else {
_this.getFeeds(function() {
callback(items.map(_this.normalize_article, _this));
});
}
});
};
OwnCloud.prototype.toString = function() {
return "OwnCloud"
};
OwnCloud.prototype.getFeeds = function(callback) {
var _this = this;
this.doOperation("GET", "feeds", {}, function(data) {
this.feeds = {};
for (var i = 0; i < data.feeds.length; i++) {
var feed = data.feeds[i];
this.feeds[feed.id] = feed;
}
localStorage.feeds = JSON.stringify(this.feeds);
callback();
});
};
OwnCloud.prototype.setArticlesRead = function(articles, callback) {
var options = {
items: articles.map(function(o) { return o.id; }),
};
if (navigator.onLine) {
this.doOperation("PUT", "items/read/multiple", options, callback);
} else {
this.append("read_articles", articles);
}
}
OwnCloud.prototype.setArticleRead = function(article, callback) {
this.setArticlesRead([article], callback);
}
OwnCloud.prototype.setArticlesUnread = function(articles, callback) {
var options = {
items: articles.map(function(o) { return o.id; }),
};
if (navigator.onLine) this.doOperation("PUT", "items/unread/multiple", options, callback);
else {
this.append("unread_articles", articles);
}
};
OwnCloud.prototype.setArticleUnread = function(article, callback) {
this.setArticlesUnread([article], callback);
}
OwnCloud.prototype.setArticlesStarred = function(articles, callback) {
console.log(JSON.stringify(articles))
var options = {
items: articles.map(function(o) { return { feedId: o.feed_id, guidHash: o.guid_hash }; })
};
if (navigator.onLine) {
this.doOperation("PUT", "items/star/multiple", options, callback);
} else {
this.append("starred_articles", articles);
}
};
OwnCloud.prototype.setArticleStarred = function(article, callback) {
this.setArticlesStarred([article], callback);
}
OwnCloud.prototype.setArticlesUnstarred = function(articles, callback) {
var options = {
items: articles.map(function(o) { return { feedId: o.feed_id, guidHash: o.guid_hash }; })
};
if (navigator.onLine) {
this.doOperation("PUT", "items/unstar/multiple", options, callback);
} else {
this.append("unstarred_articles", articles);
}
};
OwnCloud.prototype.setArticleUnstarred = function(articles, callback) {
this.setArticlesUnstarred([articles], callback);
}
OwnCloud.prototype.normalize_article = function(article) {
var feed = this.feeds[article.feedId];
var feed_title = "";
if(feed) {
feed_title = feed.title;
}
return {
id: article.id,
guid_hash: article.guidHash,
title: article.title,
content: article.body,
feed_title: feed_title,
feed_id: article.feedId,
excerpt: article.body.stripHTML().substring(0, 50),
updated: article.pubDate,
link: article.link,
marked: article.starred,
unread: article.unread
}
};
OwnCloud.prototype.logOut = function() {
this.doOperation("logout");
};
OwnCloud.prototype.getFeedFor = function(o) {
return this.feeds[o.feedId];
};
OwnCloud.prototype.append = function(key, array) {
var tmp = localStorage[key];
if (typeof tmp !== "undefined") tmp = JSON.parse(tmp);
else tmp = [];
tmp.concat(options.items);
localStorage[key] = JSON.stringify(tmp);
};
OwnCloud.login = function(server_url, user, password, callback) {
var url = server_url + "/index.php/apps/news/api/v1-2/version";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
callback(JSON.parse(xhr.responseText))
} else {
alert("error: " + xhr.status + " " + xhr.statusText)
}
}
}
xhr.open("GET", url, true);
xhr.withCredentials = true;
var auth = btoa(user + ':' + password);
xhr.setRequestHeader('Authorization', 'Basic ' + auth);
xhr.send();
}

View file

@ -12,22 +12,14 @@ TinyTinyRSS.prototype.onoffline = function() {
};
TinyTinyRSS.prototype.ononline = function() {
var read_articles = localStorage.read_articles;
if (read_articles ) {
read_articles = JSON.parse(localStorage.read_articles);
this.setArticleRead(read_articles.join(","), function() {
localStorage.read_articles = null;
});
}
var unread_articles = localStorage.unread_articles;
if (unread_articles) {
unread_articles = JSON.parse(unread_articles);
this.setArticleUnread(unread_articles.join(","), function() {
localStorage.unread_articles();
});
["read", "unread", "starred", "unstarred"].forEach(function(type) {
var articles = localStorage[type + "_articles"];
if(articles) {
var callback = function(ok) { if(ok) localStorage[type + "_articles"] = null }
this.call("setArticles" + type.capitalize(), [JSON.parse(articles), callback]);
}
});
};
TinyTinyRSS.prototype.doOperation = function(operation, new_options, callback) {
@ -62,7 +54,12 @@ TinyTinyRSS.prototype.doOperation = function(operation, new_options, callback) {
xhr.send(JSON.stringify(options));
}
TinyTinyRSS.prototype.reload = function(callback) {
this.getUnreadFeeds(callback, []);
};
TinyTinyRSS.prototype.getUnreadFeeds = function(callback, skip) {
skip = skip.length;
var options = {
show_excerpt: false,
view_mode: "unread",
@ -74,63 +71,92 @@ TinyTinyRSS.prototype.getUnreadFeeds = function(callback, skip) {
this.doOperation("getHeadlines", options, callback);
}
TinyTinyRSS.prototype.setArticleRead = function(article_id) {
TinyTinyRSS.prototype.setArticlesRead = function(articles, callback) {
var options = {
article_ids: article_id,
article_ids: articles.map(function(o) { return o.id }).join(","),
mode: 0,
field: 2
};
if (navigator.onLine) {
this.doOperation("updateArticle", options, callback);
} else {
this.append("read_articles", articles);
}
};
TinyTinyRSS.prototype.setArticleRead = function(article, callback) {
this.setArticlesRead([article], callback);
};
TinyTinyRSS.prototype.setArticlesUnread = function(articles, callback) {
var options = {
article_ids: articles.map(function(o) { return o.id }).join(","),
mode: 1,
field: 2
};
if (navigator.onLine) {
this.doOperation("updateArticle", options, callback);
} else {
this.append("unread_articles", articles);
}
};
TinyTinyRSS.prototype.setArticleUnread = function(article, callback) {
this.setArticlesUnread([article], callback);
};
TinyTinyRSS.prototype.setArticlesStarred = function(articles, callback) {
var options = {
article_ids: articles.map(function(o) { return o.id }).join(","),
mode: 1,
field: 0
};
if (navigator.onLine) {
this.doOperation("updateArticle", options);
} else {
var read_articles = localStorage.read_articles;
if(typeof read_articles !== "undefined") read_articles = JSON.parse(read_articles);
else read_articles = [];
read_articles.push(article_id);
localStorage.read_articles = JSON.stringify(read_articles);
this.append("starred_articles", articles);
}
};
TinyTinyRSS.prototype.setArticleStarred = function(article_id) {
var options = {
article_ids: article_id,
mode: 1,
field: 0
TinyTinyRSS.prototype.setArticleStarred = function(article, callback) {
this.setArticlesStarred([article], callback);
};
if (navigator.onLine) {
this.doOperation("updateArticle", options);
}
};
TinyTinyRSS.prototype.setArticlesUnstarred = function(articles, callback) {
TinyTinyRSS.prototype.setArticleUnStarred = function(article_id) {
var options = {
article_ids: article_id,
article_ids: articles.map(function(o) { return o.id}).join(","),
mode: 0,
field: 0
};
if (navigator.onLine) {
this.doOperation("updateArticle", options);
this.doOperation("updateArticle", options, callback);
} else {
this.append("unstarred_articles", articles);
}
};
TinyTinyRSS.prototype.setArticleUnread = function(article_id) {
var options = {
article_ids: article_id,
mode: 1,
field: 2
TinyTinyRSS.prototype.setArticleUnstarred = function(article, callback) {
this.setArticlesUnstarred([article], callback);
};
if (navigator.onLine) this.doOperation("updateArticle", options);
else {
var unread_articles = localStorage.unread_articles;
if (typeof unread_articles !== "undefined") unread_articles = JSON.parse(unread_articles);
else unread_articles = [];
unread_articles.push(article_id);
localStorage.unread_articles = JSON.stringify(unread_articles);
}
TinyTinyRSS.prototype.append = function(key, array) {
var tmp = localStorage[key];
if (typeof tmp !== "undefined") tmp = JSON.parse(tmp);
else tmp = [];
tmp.concat(options.items);
localStorage[key] = JSON.stringify(tmp);
};
TinyTinyRSS.prototype.logOut = function() {

View file

@ -34,5 +34,25 @@ Node.prototype.removeClass = function(cls) {
}
};
var __entityMap = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;"
};
String.prototype.escapeHTML = function() {
return String(this).replace(/[&<>]/g, function (s) {
return __entityMap[s];
});
}
String.prototype.stripHTML = function() {
return this.replace(/(<([^>]+)>)/ig, "");
}
String.prototype.capitalize = function() {
return this.charAt(0).toUpperCase() + this.slice(1);
}
if(!window.app) window.app = new App();