diff options
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | backend.php | 285 | ||||
-rw-r--r-- | functions.js | 24 | ||||
-rw-r--r-- | prefs.js | 165 | ||||
-rw-r--r-- | schema/ttrss_schema_mysql.sql | 2 | ||||
-rw-r--r-- | schema/ttrss_schema_pgsql.sql | 2 | ||||
-rw-r--r-- | tt-rss.css | 30 |
7 files changed, 438 insertions, 71 deletions
@@ -10,6 +10,7 @@ v1.1 (Dec xy, 2005) * Interactive user preferences editor * Per-feed content filters * Support for user stylesheets + * Feed categories v1.0.7 (Nov 14, 2005) diff --git a/backend.php b/backend.php index 1dcfd4deb..f0ad01499 100644 --- a/backend.php +++ b/backend.php @@ -172,6 +172,11 @@ /* virtual feeds */ + if (get_pref($link, 'ENABLE_FEED_CATS')) { + print "<li class=\"feedCat\">Special</li>"; + print "<ul class=\"feedCatList\">"; + } + $result = db_query($link, "SELECT count(id) as num_starred FROM ttrss_entries,ttrss_user_entries WHERE marked = true AND @@ -186,13 +191,22 @@ printFeedEntry(-1, $class, "Starred articles", $num_starred, "images/mark_set.png", $link); + if (get_pref($link, 'ENABLE_FEED_CATS')) { + print "</ul>"; + } + if (get_pref($link, 'ENABLE_LABELS')) { $result = db_query($link, "SELECT id,sql_exp,description FROM ttrss_labels WHERE owner_uid = '$owner_uid' ORDER by description"); if (db_num_rows($result) > 0) { - print "<li><hr></li>"; + if (get_pref($link, 'ENABLE_FEED_CATS')) { + print "<li class=\"feedCat\">Labels</li>"; + print "<ul class=\"feedCatList\">"; + } else { + print "<li><hr></li>"; + } } while ($line = db_fetch_assoc($result)) { @@ -218,9 +232,24 @@ $class, $line["description"], $count, "images/label.png", $link); } + + if (db_num_rows($result) > 0) { + if (get_pref($link, 'ENABLE_FEED_CATS')) { + print "</ul>"; + } + } + + } + +// if (!get_pref($link, 'ENABLE_FEED_CATS')) { + print "<li><hr></li>"; +// } + + if (get_pref($link, 'ENABLE_FEED_CATS')) { + $order_by_qpart = "category,title"; + } else { + $order_by_qpart = "title"; } - - print "<li><hr></li>"; $result = db_query($link, "SELECT *, (SELECT count(id) FROM ttrss_entries,ttrss_user_entries @@ -230,8 +259,10 @@ (SELECT count(id) FROM ttrss_entries,ttrss_user_entries WHERE feed_id = ttrss_feeds.id AND unread = true AND ttrss_user_entries.ref_id = ttrss_entries.id - AND owner_uid = '$owner_uid') as unread - FROM ttrss_feeds WHERE owner_uid = '$owner_uid' ORDER BY title"); + AND owner_uid = '$owner_uid') as unread, + (SELECT title FROM ttrss_feed_categories + WHERE id = cat_id) AS category + FROM ttrss_feeds WHERE owner_uid = '$owner_uid' ORDER BY $order_by_qpart"); $actid = $_GET["actid"]; @@ -240,6 +271,8 @@ $lnum = 0; $total_unread = 0; + + $category = ""; while ($line = db_fetch_assoc($result)) { @@ -250,6 +283,12 @@ $total = $line["total"]; $unread = $line["unread"]; + + $tmp_category = $line["category"]; + + if (!$tmp_category) { + $tmp_category = "Uncategorized"; + } // $class = ($lnum % 2) ? "even" : "odd"; @@ -262,11 +301,25 @@ } $total_unread += $unread; + + if ($category != $tmp_category && get_pref($link, 'ENABLE_FEED_CATS')) { + + if ($category) { + print "</li></ul></li>"; + } + + $category = $tmp_category; + + print "<li class=\"feedCat\">$category</li>"; + print "<li><ul class=\"feedCatList\">"; + } - printFeedEntry($feed_id, $class, $feed, $unread, "icons/$feed_id.ico", $link); + printFeedEntry($feed_id, $class, $feed, $unread, + "icons/$feed_id.ico", $link); ++$lnum; } + } else { // tags @@ -897,7 +950,8 @@ $feed_link = db_escape_string($_GET["l"]); $upd_intl = db_escape_string($_GET["ui"]); $purge_intl = db_escape_string($_GET["pi"]); - $feed_id = $_GET["id"]; + $feed_id = db_escape_string($_GET["id"]); + $cat_id = db_escape_string($_GET["catid"]); if (strtoupper($upd_intl) == "DEFAULT") $upd_intl = 0; @@ -908,10 +962,17 @@ if (strtoupper($purge_intl) == "DISABLED") $purge_intl = -1; + if ($cat_id != 0) { + $category_qpart = "cat_id = '$cat_id'"; + } else { + $category_qpart = 'cat_id = NULL'; + } + $result = db_query($link, "UPDATE ttrss_feeds SET + $category_qpart, title = '$feed_title', feed_url = '$feed_link', update_interval = '$upd_intl', - purge_interval = '$purge_intl' + purge_interval = '$purge_intl' WHERE id = '$feed_id' AND owner_uid = " . $_SESSION["uid"]); } @@ -969,6 +1030,64 @@ } } + if ($subop == "addCat") { + + if (!WEB_DEMO_MODE) { + + $feed_cat = db_escape_string(trim($_GET["cat"])); + + $result = db_query($link, + "SELECT id FROM ttrss_feed_categories + WHERE title = '$feed_cat' AND owner_uid = ".$_SESSION["uid"]); + + if (db_num_rows($result) == 0) { + + $result = db_query($link, + "INSERT INTO ttrss_feed_categories (owner_uid,title) + VALUES ('".$_SESSION["uid"]."', '$feed_cat')"); + + } else { + + print "<div class=\"warning\"> + Category <b>$feed_cat</b> already exists in the database. + </div>"; + } + + + } + } + + if ($subop == "removeCats") { + + if (!WEB_DEMO_MODE) { + + $ids = split(",", $_GET["ids"]); + + foreach ($ids as $id) { + + db_query($link, "BEGIN"); + + $result = db_query($link, + "SELECT count(id) as num_feeds FROM ttrss_feeds + WHERE cat_id = '$id'"); + + $num_feeds = db_fetch_result($result, 0, "num_feeds"); + + if ($num_feeds == 0) { + db_query($link, "DELETE FROM ttrss_feed_categories + WHERE id = '$id' AND owner_uid = " . $_SESSION["uid"]); + } else { + + print "<div class=\"warning\"> + Unable to delete non empty feed categories.</div>"; + + } + + db_query($link, "COMMIT"); + } + } + } + $result = db_query($link, "SELECT id,title,feed_url,last_error FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ".$_SESSION["uid"]); @@ -990,6 +1109,99 @@ } + if (get_pref($link, 'ENABLE_FEED_CATS')) { + + // print "<h3>Categories</h3>"; + + print "<div class=\"prefGenericAddBox\"> + <input id=\"fadd_cat\" size=\"40\"> <input + type=\"submit\" class=\"button\" + onclick=\"javascript:addFeedCat()\" value=\"Add category\"></div>"; + + $result = db_query($link, "SELECT title,id FROM ttrss_feed_categories + WHERE owner_uid = ".$_SESSION["uid"]." + ORDER BY title"); + + print "<p><table width=\"100%\" class=\"prefFeedCatList\" id=\"prefFeedCatList\">"; + print "<tr class=\"title\"> + <td width=\"10%\">Select</td><td width=\"80%\">Title</td> + </tr>"; + + $lnum = 0; + + while ($line = db_fetch_assoc($result)) { + + $class = ($lnum % 2) ? "even" : "odd"; + + $cat_id = $line["id"]; + + $edit_cat_id = $_GET["id"]; + + if ($subop == "editCat" && $cat_id != $edit_cat_id) { + $class .= "Grayed"; + } + + print "<tr class=\"$class\" id=\"FCATR-$cat_id\">"; + + $edit_title = htmlspecialchars(db_unescape_string($line["title"])); + + if (!$edit_cat_id || $subop != "editCat") { + + print "<td><input onclick='toggleSelectRow(this);' + type=\"checkbox\" id=\"FCCHK-".$line["id"]."\"></td>"; + + print "<td><a href=\"javascript:editFeedCat($cat_id);\">" . + $edit_title . "</a></td>"; + + } else if ($cat_id != $edit_cat_id) { + + print "<td><input disabled=\"true\" type=\"checkbox\" + id=\"FRCHK-".$line["id"]."\"></td>"; + + print "<td>$edit_title</td>"; + + } else { + + print "<td><input disabled=\"true\" type=\"checkbox\" checked></td>"; + + print "<td><input id=\"iedit_title\" value=\"$edit_title\"></td>"; + + } + + print "</tr>"; + + ++$lnum; + } + + if ($lnum == 0) { + print "<tr><td colspan=\"5\" align=\"center\">No categories defined.</td></tr>"; + } + + print "</table>"; + + print "<p>"; + + if ($subop == "editCat") { + print "Edit category: + <input type=\"submit\" class=\"button\" + onclick=\"javascript:feedCatEditCancel()\" value=\"Cancel\"> + <input type=\"submit\" class=\"button\" + onclick=\"javascript:feedCatEditSave()\" value=\"Save\">"; + } else { + + print " + Selection: + <input type=\"submit\" class=\"button\" + onclick=\"javascript:editSelectedFeedCat()\" value=\"Edit\"> + <input type=\"submit\" class=\"button\" + onclick=\"javascript:removeSelectedFeedCats()\" value=\"Remove\">"; + } + } + +// print "<h3>Feeds</h3>"; + + print "<hr><p>"; + print "<div class=\"prefGenericAddBox\"> <input id=\"fadd_link\" size=\"40\"> <input type=\"submit\" class=\"button\" @@ -997,7 +1209,9 @@ $result = db_query($link, "SELECT id,title,feed_url,substring(last_updated,1,16) as last_updated, - update_interval,purge_interval + update_interval,purge_interval, + (SELECT title FROM ttrss_feed_categories + WHERE id = cat_id) AS category FROM ttrss_feeds WHERE owner_uid = '".$_SESSION["uid"]."' ORDER by title"); @@ -1005,9 +1219,14 @@ print "<p><table width=\"100%\" class=\"prefFeedList\" id=\"prefFeedList\">"; print "<tr class=\"title\"> - <td> </td><td>Select</td><td width=\"30%\">Title</td> - <td width=\"30%\">Link</td> - <td width=\"10%\">Update Interval</td> + <td> </td><td>Select</td><td width=\"20%\">Title</td> + <td width=\"20%\">Link</td>"; + + if (get_pref($link, 'ENABLE_FEED_CATS')) { + print "<td width=\"10%\">Category</td>"; + } + + print "<td width=\"10%\">Update Interval</td> <td width=\"10%\">Purge Days</td> <td>Last updated</td></tr>"; @@ -1039,6 +1258,9 @@ $edit_title = htmlspecialchars(db_unescape_string($line["title"])); $edit_link = htmlspecialchars(db_unescape_string($line["feed_url"])); + $edit_cat = htmlspecialchars(db_unescape_string($line["category"])); + + if (!$edit_cat) $edit_cat = "Uncategorized"; if (!$edit_feed_id || $subop != "edit") { @@ -1047,9 +1269,13 @@ print "<td><a href=\"javascript:editFeed($feed_id);\">" . $edit_title . "</a></td>"; + print "<td><a href=\"javascript:editFeed($feed_id);\">" . $edit_link . "</a></td>"; + print "<td><a href=\"javascript:editFeed($feed_id);\">" . + $edit_cat . "</a></td>"; + if ($line["update_interval"] == "0") $line["update_interval"] = "Default"; @@ -1072,6 +1298,7 @@ print "<td>$edit_title</td>"; print "<td>$edit_link</td>"; + print "<td>$edit_cat</td>"; if ($line["update_interval"] == "0") $line["update_interval"] = "Default"; @@ -1092,8 +1319,38 @@ print "<td><input id=\"iedit_title\" value=\"$edit_title\"></td>"; print "<td><input id=\"iedit_link\" value=\"$edit_link\"></td>"; - print "<td><input id=\"iedit_updintl\" value=\"".$line["update_interval"]."\"></td>"; - print "<td><input id=\"iedit_purgintl\" value=\"".$line["purge_interval"]."\"></td>"; + + print "<td>"; + + print "<select id=\"iedit_fcat\">"; + + print "<option id=\"0\">Uncategorized</option>"; + + if (db_num_rows($result) > 0) { + print "<option disabled>--------</option>"; + } + + $tmp_result = db_query($link, "SELECT id,title FROM ttrss_feed_categories + WHERE owner_uid = ".$_SESSION["uid"]." ORDER BY title"); + + while ($tmp_line = db_fetch_assoc($tmp_result)) { + if ($tmp_line["id"] == $line["cat_id"]) { + $is_selected = "selected"; + } else { + $is_selected = ""; + } + printf("<option $is_selected id='%d'>%s</option>", + $tmp_line["id"], $tmp_line["title"]); + } + + print "</select></td>"; + + print "</td>"; + + print "<td><input id=\"iedit_updintl\" + value=\"".$line["update_interval"]."\"></td>"; + print "<td><input id=\"iedit_purgintl\" + value=\"".$line["purge_interval"]."\"></td>"; } diff --git a/functions.js b/functions.js index c4d79e517..c7f1b8a64 100644 --- a/functions.js +++ b/functions.js @@ -415,3 +415,27 @@ function fatalError(code) { window.location = "error.php?c=" + param_escape(code); } + +function getSelectedTableRowIds(content_id, prefix) { + + var content = document.getElementById(content_id); + + if (!content) { + alert("[getSelectedTableRowIds] Element " + content_id + " not found."); + return; + } + + var sel_rows = new Array(); + + for (i = 0; i < content.rows.length; i++) { + if (content.rows[i].className.match("Selected")) { + var row_id = content.rows[i].id.replace(prefix + "-", ""); + sel_rows.push(row_id); + } + } + + return sel_rows; + +} + + @@ -6,6 +6,7 @@ var xmlhttp = false; var active_feed = false; +var active_feed_cat = false; var active_filter = false; var active_label = false; var active_user = false; @@ -295,6 +296,30 @@ function addFeed() { } +function addFeedCat() { + + if (!xmlhttp_ready(xmlhttp)) { + printLockingError(); + return + } + + var cat = document.getElementById("fadd_cat"); + + if (cat.value.length == 0) { + notify("Missing feed category."); + } else { + notify("Adding feed category..."); + + xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=addCat&cat=" + + param_escape(cat.value), true); + xmlhttp.onreadystatechange=feedlist_callback; + xmlhttp.send(null); + + link.value = ""; + + } + +} function addUser() { if (!xmlhttp_ready(xmlhttp)) { @@ -386,71 +411,43 @@ function editFeed(feed) { } -function getSelectedLabels() { - - var content = document.getElementById("prefLabelList"); - - var sel_rows = new Array(); +function editFeedCat(cat) { - for (i = 0; i < content.rows.length; i++) { - if (content.rows[i].className.match("Selected")) { - var row_id = content.rows[i].id.replace("LILRR-", ""); - sel_rows.push(row_id); - } + if (!xmlhttp_ready(xmlhttp)) { + printLockingError(); + return } - return sel_rows; -} - -function getSelectedUsers() { - - var content = document.getElementById("prefUserList"); + active_feed_cat = cat; - var sel_rows = new Array(); - - for (i = 0; i < content.rows.length; i++) { - if (content.rows[i].className.match("Selected")) { - var row_id = content.rows[i].id.replace("UMRR-", ""); - sel_rows.push(row_id); - } - } + xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=editCat&id=" + + param_escape(cat), true); + xmlhttp.onreadystatechange=feedlist_callback; + xmlhttp.send(null); - return sel_rows; } +function getSelectedLabels() { + return getSelectedTableRowIds("prefLabelList", "LILRR"); +} -function getSelectedFilters() { - - var content = document.getElementById("prefFilterList"); - - var sel_rows = new Array(); - - for (i = 0; i < content.rows.length; i++) { - if (content.rows[i].className.match("Selected")) { - var row_id = content.rows[i].id.replace("FILRR-", ""); - sel_rows.push(row_id); - } - } - - return sel_rows; +function getSelectedUsers() { + return getSelectedTableRowIds("prefUserList", "UMRR"); } function getSelectedFeeds() { + return getSelectedTableRowIds("prefFeedList", "FEEDR"); +} - var content = document.getElementById("prefFeedList"); - - var sel_rows = new Array(); - - for (i = 0; i < content.rows.length; i++) { - if (content.rows[i].className.match("Selected")) { - var row_id = content.rows[i].id.replace("FEEDR-", ""); - sel_rows.push(row_id); - } - } +function getSelectedFilters() { + return getSelectedTableRowIds("prefFilterList", "FILRR"); +} - return sel_rows; +function getSelectedFeedCats() { + return getSelectedTableRowIds("prefFeedCatList", "FCATR"); } + function readSelectedFeeds() { if (!xmlhttp_ready(xmlhttp)) { @@ -597,6 +594,32 @@ function removeSelectedFeeds() { } +function removeSelectedFeedCats() { + + if (!xmlhttp_ready(xmlhttp)) { + printLockingError(); + return + } + + var sel_rows = getSelectedFeedCats(); + + if (sel_rows.length > 0) { + + notify("Removing selected categories..."); + + xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=removeCats&ids="+ + param_escape(sel_rows.toString()), true); + xmlhttp.onreadystatechange=feedlist_callback; + xmlhttp.send(null); + + } else { + + notify("Please select some feeds first."); + + } + +} + function feedEditCancel() { if (!xmlhttp_ready(xmlhttp)) { @@ -614,6 +637,23 @@ function feedEditCancel() { } +function feedCatEditCancel() { + + if (!xmlhttp_ready(xmlhttp)) { + printLockingError(); + return + } + + active_feed_cat = false; + + notify("Operation cancelled."); + + xmlhttp.open("GET", "backend.php?op=pref-feeds", true); + xmlhttp.onreadystatechange=feedlist_callback; + xmlhttp.send(null); + +} + function feedEditSave() { var feed = active_feed; @@ -627,6 +667,9 @@ function feedEditSave() { var title = document.getElementById("iedit_title").value; var upd_intl = document.getElementById("iedit_updintl").value; var purge_intl = document.getElementById("iedit_purgintl").value; + var fcat = document.getElementById("iedit_fcat"); + + var fcat_id = fcat[fcat.selectedIndex].id; // notify("Saving feed."); @@ -656,7 +699,8 @@ function feedEditSave() { xmlhttp.open("GET", "backend.php?op=pref-feeds&subop=editSave&id=" + feed + "&l=" + param_escape(link) + "&t=" + param_escape(title) + - "&ui=" + param_escape(upd_intl) + "&pi=" + param_escape(purge_intl), true); + "&ui=" + param_escape(upd_intl) + "&pi=" + param_escape(purge_intl) + + "&catid=" + param_escape(fcat_id), true); xmlhttp.onreadystatechange=feedlist_callback; xmlhttp.send(null); @@ -982,6 +1026,25 @@ function editSelectedFeed() { } +function editSelectedFeedCat() { + var rows = getSelectedFeedCats(); + + if (rows.length == 0) { + notify("No categories are selected."); + return; + } + + if (rows.length > 1) { + notify("Please select one category."); + return; + } + + notify(""); + + editFeedCat(rows[0]); + +} + function localPiggieFunction(enable) { if (enable) { piggie.style.display = "block"; diff --git a/schema/ttrss_schema_mysql.sql b/schema/ttrss_schema_mysql.sql index 7209b0c62..88c1f7afa 100644 --- a/schema/ttrss_schema_mysql.sql +++ b/schema/ttrss_schema_mysql.sql @@ -202,7 +202,7 @@ insert into ttrss_prefs (pref_name,type_id,def_value,short_desc,section_id,help_ insert into ttrss_prefs (pref_name,type_id,def_value,short_desc,section_id,help_text) values('USER_STYLESHEET_URL', 2, '', 'User stylesheet URL',2, 'Link to user stylesheet to override default style, disabled if empty.'); -insert into ttrss_prefs (pref_name,type_id,def_value,short_desc,section_id) values('ENABLE_FEED_CATS', 1, 'false', 'Enable feed categories',1); +insert into ttrss_prefs (pref_name,type_id,def_value,short_desc,section_id) values('ENABLE_FEED_CATS', 1, 'false', 'Enable feed categories',2); create table ttrss_user_prefs ( diff --git a/schema/ttrss_schema_pgsql.sql b/schema/ttrss_schema_pgsql.sql index 9bfdb171a..86dde5fca 100644 --- a/schema/ttrss_schema_pgsql.sql +++ b/schema/ttrss_schema_pgsql.sql @@ -186,7 +186,7 @@ insert into ttrss_prefs (pref_name,type_id,def_value,short_desc,section_id,help_ insert into ttrss_prefs (pref_name,type_id,def_value,short_desc,section_id,help_text) values('USER_STYLESHEET_URL', 2, '', 'User stylesheet URL',2, 'Link to user stylesheet to override default style, disabled if empty.'); -insert into ttrss_prefs (pref_name,type_id,def_value,short_desc,section_id) values('ENABLE_FEED_CATS', 1, 'false', 'Enable feed categories',1); +insert into ttrss_prefs (pref_name,type_id,def_value,short_desc,section_id) values('ENABLE_FEED_CATS', 1, 'false', 'Enable feed categories',2); create table ttrss_user_prefs ( owner_uid integer not null references ttrss_users(id) on delete cascade, diff --git a/tt-rss.css b/tt-rss.css index 56a63a565..43851439e 100644 --- a/tt-rss.css +++ b/tt-rss.css @@ -134,12 +134,32 @@ div.postReply div.postIcon { ul.feedList { list-style-type : none; + margin : 5px; + padding : 0px 0px 0px 10px; +} + +ul.feedList li.feedCat { margin : 0px; - padding : 10px; + padding : 3px 0px 3px 0px; +/* border-width : 0px 0px 1px 0px; + border-color : #f0f0f0; + border-style : solid; */ + color : #707070; +} + +ul.feedCatList { + list-style-type : none; + margin : 0px; + padding : 0px 0px 0px 10px; +} + +ul.feedCatList li { + margin : 0px; + padding : 0px 0px 0px 0px; } ul.feedList li { - margin : 2px; + margin : 0px; } li.oddSelected, li.evenSelected { @@ -245,7 +265,8 @@ a:hover { } #iedit_title, #iedit_link, #iedit_regexp, #iedit_descr, #iedit_expr, #iedit_updintl, -#iedit_purgintl, #iedit_ulogin, #iedit_ulevel, #iedit_match, #iedit_feed { +#iedit_purgintl, #iedit_ulogin, #iedit_ulevel, #iedit_match, #iedit_feed, +#iedit_fcat { width : 100%; padding-left : 2px; } @@ -393,7 +414,8 @@ input { table.prefFeedList tr.title td, table.prefFilterList tr.title td, table.headlinesList tr.title td, table.prefLabelList tr.title td, - table.prefPrefsList tr.title td { + table.prefPrefsList tr.title td, + table.prefFeedCatList tr.title td { font-weight : bold; border-width : 0px 0px 1px 0px; border-color : #f0f0f0; |