FeedMonkey HTML5 RSS Feed Reader

Check-in [52fc589285]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Modernize JS in TinyTiny RSS support. (I'd update the others, but without access to a server, I couldn't verify if I got it right.)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | origin/clean | trunk | master
Files: files | file ages | folders
SHA3-256:52fc5892858eb61dd9d55e6909b59af57f207cd5e320f1b73e61cbc1851e2c75
User & Date: vandys 2019-04-20 00:50:48
Context
2019-04-20
17:24
Whoops, class method for login attempt. check-in: 14d57ed185 user: vandys tags: origin/clean, trunk, master
00:50
Modernize JS in TinyTiny RSS support. (I'd update the others, but without access to a server, I couldn't verify if I got it right.) check-in: 52fc589285 user: vandys tags: origin/clean, trunk, master
2019-03-05
15:45
Make read/unread indicator dim when read. check-in: 3bb0214a02 user: vandys tags: origin/clean, trunk, master
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to js/TinyTinyRSS.js.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

16

17
18

19

20
21
22
23
24

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

47

48


49
50
51

52
53
54
55
56
57
58
59
60

61
62
63
64
65
66
67
68
69
70
71
72
73
74




75
76
77
78

79
80






































81
82
83
84
85
86
87
88
89

90
91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107
108
109

110
111
112
113

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174

175
176
177
178
179
180
181
182
183
184
185

186
187
188
189

190
191
192
193


194

195
196
197
198
199

200
201
202
203

204
205
206
207
208
209
210
211
212
213
214
215

216
217
218
219
220
221
222
223
224
225


function TinyTinyRSS(app, server_url, session_id) {
	this.app = app;
	this.server_url = server_url;
	this.session_id = session_id;

	window.addEventListener("offline", this.onoffline.bind(this));
	window.addEventListener("online", this.ononline.bind(this));
}

TinyTinyRSS.prototype.onoffline = function() {
	// Do nothing
};

TinyTinyRSS.prototype.ononline = function() {


	["read", "unread", "starred", "unstarred", "published", "unpublished"].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) {
	if(!navigator.onLine) {
		callback(null);
		return;
	}

	var url = this.server_url + "/api/";
	var options = {
		sid: this.session_id,
		op: operation
	};
	
	for (var key in new_options) {
		options[key] = new_options[key];
	}

	var xhr = new XMLHttpRequest({mozSystem: true});
	xhr.onreadystatechange = function() {
		if(xhr.readyState == 4) {
			if(xhr.status == 200) {
				if(callback)
					callback(JSON.parse(xhr.responseText).content);

			} else {

				if(xhr.status != 0) alert("error: " + xhr.status + " " + xhr.statusText);


				if(callback) callback(null);
			}
		}

	}
	xhr.open("POST", url, true);
	xhr.send(JSON.stringify(options));
}

TinyTinyRSS.prototype.reload = function(callback,limit) {
	this.getUnreadFeeds(callback, 0, limit);
};


TinyTinyRSS.prototype.getUnreadFeeds = function(callback, skip, limit) {
	skip = skip.length;
	var options = {
		show_excerpt: false,
		view_mode: "unread",
		show_content: true,
		feed_id: -4,
		limit: limit || 0,
		skip: skip || 0
	};

	this.doOperation("getHeadlines", options, callback);
}





TinyTinyRSS.prototype.setArticlesRead = function(articles, callback) {

	var options = {
		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 {
		this.append("starred_articles", articles);
	}
};

TinyTinyRSS.prototype.setArticleStarred = function(article, callback) {
	this.setArticlesStarred([article], callback);
};

TinyTinyRSS.prototype.setArticlesUnstarred = function(articles, callback) {

	var options = {
		article_ids: articles.map(function(o) { return o.id}).join(","),
		mode: 0,
		field: 0
	};

	if (navigator.onLine) {
		this.doOperation("updateArticle", options, callback);
	} else {
		this.append("unstarred_articles", articles);
	}
};

TinyTinyRSS.prototype.setArticleUnstarred = function(article, callback) {
	this.setArticlesUnstarred([article], callback);
};

TinyTinyRSS.prototype.setArticlesPublished = function(articles, callback) {

	var options = {
		article_ids: articles.map(function(o) { return o.id }).join(","),
		mode: 1,
		field: 1
	};

	if (navigator.onLine) {
		this.doOperation("updateArticle", options);
	} else {
		this.append("published_articles", articles);
	}
};

TinyTinyRSS.prototype.setArticlePublished = function(article, callback) {
	this.setArticlesPublished([article], callback);
};

TinyTinyRSS.prototype.setArticlesUnpublished = function(articles, callback) {

	var options = {
		article_ids: articles.map(function(o) { return o.id}).join(","),

		mode: 0,
		field: 1
	};

	if (navigator.onLine) {
		this.doOperation("updateArticle", options, callback);
	} else {
		this.append("unpublished_articles", articles);
	}
};


TinyTinyRSS.prototype.setArticleUnpublished = function(article, callback) {
	this.setArticlesUnpublished([article], callback);
};


TinyTinyRSS.prototype.append = function(key, array) {
	var tmp = localStorage[key];

	if (typeof tmp !== "undefined") tmp = JSON.parse(tmp);


	else tmp = [];


	tmp.concat(array);
	localStorage[key] = JSON.stringify(tmp);
};


TinyTinyRSS.prototype.logOut = function() {
	this.doOperation("logout");
};


TinyTinyRSS.login = function(server_url, user, password, callback) {
	
	var url = server_url + "/api/";
	var options = {op: "login", user: user, password: password};

	var xhr = new XMLHttpRequest({mozSystem: true});
	xhr.onreadystatechange = function() {
		if(xhr.readyState == 4) {
			if(xhr.status == 200) {
				callback(JSON.parse(xhr.responseText).content)
			} else {
				if(xhr.status == 0) {

					alert("Something went wrong, please check your credentials and the server address")
				} else {
					alert("error: " + xhr.status + " " + xhr.statusText)
				}
			}
		}
	}
	xhr.open("POST", url, true);
	xhr.send(JSON.stringify(options));
}

>
|






|

|

<
|
<

>
|
>
|
|
>
|
>
|
|

<
|
>
|
|
|
|


|
|
|
|


|
|


|

|
|
|
|
>
|
>
|
>
>
|
|

>



|

|

<
|
>
|

|
|
|
|
|
|
|



|

>
>
>
>
|

|
<
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



|

|

<
|
>
|
|
<
|

|

|
<
>
|
|



|

|

<
|
>
|
|
<
|
>
|

|
|
|
|



|

|

<
|
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
<
|
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|


<
>
|
|



|

|

<
|
>
|

<
|
>
|
|

|
>
>
|
>



<
|
>
|

<
|
>
|

|
|

|
|
|
|
|
|
|
>
|
|
|
|
|
|



|
>
1
2
3
4
5
6
7
8
9
10
11
12

13

14
15
16
17
18
19
20
21
22
23
24
25

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137

138
139
140
141

142
143
144
145
146

147
148
149
150
151
152
153
154
155
156

157
158
159
160

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175

176



177















178
179

180

181

















182
183
184

185
186
187
188
189
190
191
192
193
194

195
196
197
198

199
200
201
202
203
204
205
206
207
208
209
210
211

212
213
214
215

216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
class TinyTinyRSS {
    constructor(app, server_url, session_id) {
	this.app = app;
	this.server_url = server_url;
	this.session_id = session_id;

	window.addEventListener("offline", this.onoffline.bind(this));
	window.addEventListener("online", this.ononline.bind(this));
    }

    onoffline() {
	// Do nothing

    }


    ononline() {
	["read", "unread", "starred", "unstarred",
		"published", "unpublished"].forEach(typ => {
	    const articles = localStorage[typ + "_articles"];
	    if (articles) {
		const callback = ok => { if (ok) {
		    localStorage[typ + "_articles"] = null }};
		this.call("setArticles" + typ.capitalize(),
		    [JSON.parse(articles), callback]);
	    }
	});

    }

    doOperation(operation, new_options, callback) {
	if (!navigator.onLine) {
	    callback(null);
	    return;
	}

	const url = this.server_url + "/api/";
	const options = {
	    sid: this.session_id,
	    op: operation
	};
	
	for (let key in new_options) {
	    options[key] = new_options[key];
	}

	const xhr = new XMLHttpRequest({mozSystem: true});
	xhr.onreadystatechange = function() {
	    if(xhr.readyState == 4) {
		if (xhr.status == 200) {
		    if (callback) {
			callback(JSON.parse(xhr.responseText).content);
		    }
		} else {
		    if (xhr.status != 0) {
			alert("error: " + xhr.status + " " + xhr.statusText);
		    }
		    if (callback) {
			callback(null);
		    }
		}
	    }
	}
	xhr.open("POST", url, true);
	xhr.send(JSON.stringify(options));
    }

    reload(callback, limit) {
	this.getUnreadFeeds(callback, 0, limit);

    }

    getUnreadFeeds(callback, skip, limit) {
	skip = skip.length;
	const options = {
	    show_excerpt: false,
	    view_mode: "unread",
	    show_content: true,
	    feed_id: -4,
	    limit: limit || 0,
	    skip: skip || 0
	};

	this.doOperation("getHeadlines", options, callback);
    }

    idlist(articles) {
	return(articles.map(o => { return o.id }).join(","));
    }

    setArticlesRead(articles, callback) {

	const options = {

	    article_ids: this.idlist(articles),
	    mode: 0,
	    field: 2
	};

	if (navigator.onLine) {
	    this.doOperation("updateArticle", options, callback);
	} else {
	    this.append("read_articles", articles);
	}
    }

    setArticleRead(article, callback) {
	this.setArticlesRead([article], callback);
    }

    setArticlesUnread(articles, callback) {

	const options = {
	    article_ids: this.idlist(articles),
	    mode: 1,
	    field: 2
	};

	if (navigator.onLine) {
	    this.doOperation("updateArticle", options, callback);
	} else {
	    this.append("unread_articles", articles);
	}
    }

    setArticleUnread(article, callback) {
	this.setArticlesUnread([article], callback);
    }

    setArticlesStarred(articles, callback) {

	var options = {
	    article_ids: this.idlist(articles),
	    mode: 1,
	    field: 0
	};

	if (navigator.onLine) {
	    this.doOperation("updateArticle", options);
	} else {
	    this.append("starred_articles", articles);
	}

    }

    setArticleStarred(article, callback) {
	this.setArticlesStarred([article], callback);

    }

    setArticlesUnstarred(articles, callback) {

	const options = {

	    article_ids: this.idlist(articles),
	    mode: 0,
	    field: 0
	};

	if (navigator.onLine) {
	    this.doOperation("updateArticle", options, callback);
	} else {
	    this.append("unstarred_articles", articles);
	}

}

    setArticleUnstarred(article, callback) {
	this.setArticlesUnstarred([article], callback);

    }

    setArticlesPublished(articles, callback) {

	const options = {
	    article_ids: this.idlist(articles),
	    mode: 1,
	    field: 1
	};

	if (navigator.onLine) {
	    this.doOperation("updateArticle", options);
	} else {
	    this.append("published_articles", articles);
	}

    }



















    setArticlePublished(article, callback) {
	this.setArticlesPublished([article], callback);

    }



















    setArticlesUnpublished(articles, callback) {

	var options = {

	    article_ids: this.idlist(articles),
	    mode: 0,
	    field: 1
	};

	if (navigator.onLine) {
	    this.doOperation("updateArticle", options, callback);
	} else {
	    this.append("unpublished_articles", articles);
	}

    }

    setArticleUnpublished(article, callback) {
	this.setArticlesUnpublished([article], callback);

    }

    append(key, array) {
	let tmp = localStorage[key];

	if (typeof tmp !== "undefined") {
	    tmp = JSON.parse(tmp);
	} else {
	    tmp = [];
	}

	tmp.concat(array);
	localStorage[key] = JSON.stringify(tmp);

    }

    logOut() {
	this.doOperation("logout");

    }

    login(server_url, user, password, callback) {
	
	const url = server_url + "/api/";
	const options = {op: "login", user: user, password: password};

	const xhr = new XMLHttpRequest({mozSystem: true});
	xhr.onreadystatechange = () => {
	    if (xhr.readyState == 4) {
		if (xhr.status == 200) {
		    callback(JSON.parse(xhr.responseText).content);
		} else {
		    if (xhr.status == 0) {
			alert(
"Something went wrong, please check your credentials and the server address")
		    } else {
			alert("error: " + xhr.status + " " + xhr.statusText)
		    }
		}
	    }
	}
	xhr.open("POST", url, true);
	xhr.send(JSON.stringify(options));
    }
}