From 48f0adb02e8aacfc5850fd6ec2f15a9fb1af7561 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Thu, 8 Sep 2005 08:43:44 +0100 Subject: [PATCH] virtual feeds (labels) support --- NEWS | 3 +- backend.php | 199 +++++++++++++++++++++++++++++- config.php-dist | 5 + images/label.png | Bin 0 -> 712 bytes images/label.svg | 73 +++++++++++ prefs.js | 224 +++++++++++++++++++++++++++++++--- prefs.php | 12 ++ schema/ttrss_schema_mysql.sql | 11 ++ schema/ttrss_schema_pgsql.sql | 12 ++ tt-rss.css | 2 +- 10 files changed, 517 insertions(+), 24 deletions(-) create mode 100644 images/label.png create mode 100644 images/label.svg diff --git a/NEWS b/NEWS index 008ccf92..0a39a392 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ -v1.0.4 +v1.0.4 (Sep xx, 2005) - "Starred items" virtual feed + - Experimental support for Gmail-like labels v1.0.3.1 (Sep 07, 2005) diff --git a/backend.php b/backend.php index a16927cd..8b39ce5f 100644 --- a/backend.php +++ b/backend.php @@ -35,6 +35,23 @@ printFeedEntry(-1, "odd", "Starred articles", $num_starred, "images/mark_set.png"); + if (ENABLE_LABELS) { + + $result = db_query($link, "SELECT id,description FROM + ttrss_labels ORDER by description"); + + if (db_num_rows($result) > 0) { + print "

  • "; + } + + while ($line = db_fetch_assoc($result)) { + + printFeedEntry(-$line["id"]-11, + "odd", $line["description"], 0, "images/label.png"); + + } + } + print "

  • "; $result = db_query($link, "SELECT *, @@ -312,14 +329,26 @@ if ($feed >= 0) { $query_strategy_part = "feed_id = '$feed'"; - } else if ($feed == -1) { + } else if ($feed == -1) { // starred virtual feed $query_strategy_part = "marked = true"; + $vfeed_query_part = "(SELECT title FROM ttrss_feeds WHERE + id = feed_id) as feed_title,"; + } else if ($feed <= -10) { // labels + $label_id = -$feed - 11; + + $tmp_result = db_query($link, "SELECT sql_exp FROM ttrss_labels + WHERE id = '$label_id'"); + + $query_strategy_part = db_fetch_result($tmp_result, 0, "sql_exp"); + $vfeed_query_part = "(SELECT title FROM ttrss_feeds WHERE id = feed_id) as feed_title,"; } else { - $query_strategy_part = "id => 0"; // dumb + $query_strategy_part = "id > 0"; // dumb } + if ($feed < -10) error_reporting (0); + $result = db_query($link, "SELECT id,title,updated,unread,feed_id,marked,link,last_read, SUBSTRING(last_read,1,19) as last_read_noms, @@ -333,8 +362,16 @@ $query_strategy_part ORDER BY updated DESC $limit_query_part"); + if (!$result) { + print " + Could not display feed (query failed). Please check match syntax or local configuration."; + return; + } + $lnum = 0; - + + error_reporting (E_ERROR | E_WARNING | E_PARSE); + $num_unread = 0; while ($line = db_fetch_assoc($result)) { @@ -415,16 +452,20 @@ $result = db_query($link, "SELECT count(id) as unread FROM ttrss_entries WHERE feed_id = ttrss_feeds.id AND $query_strategy_part AND unread = true"); + + $unread = db_fetch_result($result, 0, "unread"); + } else if ($feed == -1) { $result = db_query($link, "SELECT count(id) as unread FROM ttrss_entries WHERE $query_strategy_part"); + $unread = db_fetch_result($result, 0, "unread"); + } else { - print "[viewfeed] feed type not implemented
    "; +// print "[viewfeed] feed type not implemented
    "; + $unread = 0; } - $unread = db_fetch_result($result, 0, "unread"); - // update unread/total counters and status for active feed in the feedlist // kludge, because iframe doesn't seem to support onload() @@ -828,6 +869,152 @@ } } + if ($op == "pref-labels") { + + $subop = $_GET["subop"]; + + if ($subop == "editSave") { + + $sql_exp = $_GET["s"]; + $descr = $_GET["d"]; + $label_id = db_escape_string($_GET["id"]); + +// print "$sql_exp : $descr : $label_id"; + + $result = db_query($link, "UPDATE ttrss_labels SET + sql_exp = '$sql_exp', + description = '$descr' + WHERE id = '$label_id'"); + } + + if ($subop == "remove") { + + if (!WEB_DEMO_MODE) { + + $ids = split(",", $_GET["ids"]); + + foreach ($ids as $id) { + db_query($link, "DELETE FROM ttrss_labels WHERE id = '$id'"); + + } + } + } + + if ($subop == "add") { + + if (!WEB_DEMO_MODE) { + + $exp = $_GET["exp"]; + + $result = db_query($link, + "INSERT INTO ttrss_labels (sql_exp,description) + VALUES ('$exp', '$exp')"); + } + } + + print " + "; + + print" +
    + Add label
    "; + + $result = db_query($link, "SELECT + id,sql_exp,description + FROM + ttrss_labels ORDER by description"); + + print "

    "; + + print " + + "; + + $lnum = 0; + + while ($line = db_fetch_assoc($result)) { + + $class = ($lnum % 2) ? "even" : "odd"; + + $label_id = $line["id"]; + $edit_label_id = $_GET["id"]; + + if ($subop == "edit" && $label_id != $edit_label_id) { + $class .= "Grayed"; + } + + print ""; + + $line["sql_exp"] = htmlspecialchars($line["sql_exp"]); + $line["description"] = htmlspecialchars($line["description"]); + + if (!$edit_label_id || $subop != "edit") { + + if (!$line["description"]) $line["description"] = "[No caption]"; + + print ""; + + print ""; + + print ""; + + } else if ($label_id != $edit_label_id) { + + if (!$line["description"]) $line["description"] = "[No description]"; + + print ""; + + print ""; + print ""; + + } else { + + print ""; + + print ""; + + print ""; + + } + + + print ""; + + ++$lnum; + } + + if ($lnum == 0) { + print ""; + } + + print "
    SelectSQL expressionCaption
    " . + $line["sql_exp"] . "" . + $line["description"] . "".$line["sql_exp"]."".$line["description"]."
    No labels defined.
    "; + + print "

    "; + + if ($subop == "edit") { + print "Edit label: + + "; + + } else { + + print " + Selection: + + "; + } + } + if ($op == "error") { print "

    "; $msg = $_GET["msg"]; diff --git a/config.php-dist b/config.php-dist index d5bcdc9b..bb110fe7 100644 --- a/config.php-dist +++ b/config.php-dist @@ -25,5 +25,10 @@ define(ENABLE_PREFS_CATCHUP_UNCATCHUP, false); // enable "Mark as read/unread" buttons in preferences dialog + define(ENABLE_LABELS, true); + // experimental support for virtual feeds or labels based on user + // crafted SQL queries. This feature is highly experimental and + // at this point not user friendly. Use with caution. + ?> diff --git a/images/label.png b/images/label.png new file mode 100644 index 0000000000000000000000000000000000000000..2d6b08949de78663d4eac1cdf06c9eba16ae6f5d GIT binary patch literal 712 zcmV;(0yq7MP)L zlfg?=Q5431_uiQ|&P=0HriGHBLShOD1ulXt7lQr+Epih@k09Z>Q+b;nm8%}Kum^>k zMB3#dgf>M{5E$epBany?)6qa3Y@Fx3ds{S#=(Orv9q#@3anAkj5ylw)NAh16zGq)4 zSMQhj+kx-dF+e+RpncEI0IR^+lJ5g>)NzBH@7WTNjvEvKVtZg3nDIS(0{9|?h{u$i z1}H{4Zj5R2J^K`J73e$A0lhd8yp!Q z-38pgeZvBp00FdFarLD4LR)g{SHZNLtQ7zY-?Ap1N{AP)=kwuCGyu#42KXu+Hwb|N zU_N2RCR0g^bjqTmwO%AE;v_5LbhOrsbjl)?v`AR7$r50|af46-IBqbiq!^My=>DGe zWL-_=f!D69sieQBJt>9IN{S)J4Mw39qwm>`O3AKBYmr^c{VOrDYdIpVg;KK1_v}Uh zRi&2C0M8HI#dv>jWrz$2t7mIr9NOjuIWGYl9olpR|twNN`ZAU-Xw}P0GhoVTg8o2DZ zL00TvCf~EK0gqxz&LFr1fZ=5^(tW^n#|<9u^_N?wdL_l!t&#D5CFPuwa_&zp#(?_$ u=5m0E!O@4q0EMvV7s8?sP&%8~Z~hI>2lxzw1b86;0000 + + + + + + + + image/svg+xml + + + + + + + + diff --git a/prefs.js b/prefs.js index d9554217..2d04efed 100644 --- a/prefs.js +++ b/prefs.js @@ -7,6 +7,7 @@ var xmlhttp = false; var active_feed = false; var active_filter = false; +var active_label = false; /*@cc_on @*/ /*@if (@_jscript_version >= 5) @@ -68,6 +69,26 @@ function filterlist_callback() { } } +function labellist_callback() { + var container = document.getElementById('labelConfPane'); + if (xmlhttp.readyState == 4) { + container.innerHTML=xmlhttp.responseText; + + if (active_filter) { + var row = document.getElementById("LILRR-" + active_label); + if (row) { + if (!row.className.match("Selected")) { + row.className = row.className + "Selected"; + } + } + var checkbox = document.getElementById("LICHK-" + active_label); + + if (checkbox) { + checkbox.checked = true; + } + } + } +} function notify_callback() { var container = document.getElementById('notify'); if (xmlhttp.readyState == 4) { @@ -105,6 +126,31 @@ function toggleSelectRow(sender) { } } +function addLabel() { + + if (!xmlhttp_ready(xmlhttp)) { + printLockingError(); + return + } + + var sqlexp = document.getElementById("ladd_expr"); + + if (sqlexp.value.length == 0) { + notify("Missing SQL expression."); + } else { + notify("Adding label..."); + + xmlhttp.open("GET", "backend.php?op=pref-labels&subop=add&exp=" + + param_escape(sqlexp.value), true); + + xmlhttp.onreadystatechange=labellist_callback; + xmlhttp.send(null); + + sqlexp.value = ""; + } + +} + function addFilter() { if (!xmlhttp_ready(xmlhttp)) { @@ -132,6 +178,7 @@ function addFilter() { } } + function addFeed() { if (!xmlhttp_ready(xmlhttp)) { @@ -157,6 +204,22 @@ function addFeed() { } +function editLabel(id) { + + if (!xmlhttp_ready(xmlhttp)) { + printLockingError(); + return + } + + active_label = id; + + xmlhttp.open("GET", "backend.php?op=pref-labels&subop=edit&id=" + + param_escape(id), true); + xmlhttp.onreadystatechange=labellist_callback; + xmlhttp.send(null); + +} + function editFilter(id) { if (!xmlhttp_ready(xmlhttp)) { @@ -191,6 +254,23 @@ function editFeed(feed) { } +function getSelectedLabels() { + + var content = document.getElementById("prefLabelList"); + + 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("LILRR-", ""); + sel_rows.push(row_id); + } + } + + return sel_rows; +} + + function getSelectedFilters() { var content = document.getElementById("prefFilterList"); @@ -273,6 +353,53 @@ function unreadSelectedFeeds() { } } +function removeSelectedLabels() { + + if (!xmlhttp_ready(xmlhttp)) { + printLockingError(); + return + } + + var sel_rows = getSelectedLabels(); + + if (sel_rows.length > 0) { + + notify("Removing selected labels..."); + + xmlhttp.open("GET", "backend.php?op=pref-labels&subop=remove&ids="+ + param_escape(sel_rows.toString()), true); + xmlhttp.onreadystatechange=labellist_callback; + xmlhttp.send(null); + + } else { + notify("Please select some labels first."); + } +} + +function removeSelectedFilters() { + + if (!xmlhttp_ready(xmlhttp)) { + printLockingError(); + return + } + + var sel_rows = getSelectedFilters(); + + if (sel_rows.length > 0) { + + notify("Removing selected filters..."); + + xmlhttp.open("GET", "backend.php?op=pref-filters&subop=remove&ids="+ + param_escape(sel_rows.toString()), true); + xmlhttp.onreadystatechange=filterlist_callback; + xmlhttp.send(null); + + } else { + notify("Please select some filters first."); + } +} + + function removeSelectedFeeds() { if (!xmlhttp_ready(xmlhttp)) { @@ -349,6 +476,24 @@ function feedEditSave() { } +function labelEditCancel() { + + if (!xmlhttp_ready(xmlhttp)) { + printLockingError(); + return + } + + active_label = false; + + notify("Operation cancelled."); + + xmlhttp.open("GET", "backend.php?op=pref-labels", true); + xmlhttp.onreadystatechange=labellist_callback; + xmlhttp.send(null); + +} + + function filterEditCancel() { if (!xmlhttp_ready(xmlhttp)) { @@ -366,6 +511,41 @@ function filterEditCancel() { } +function labelEditSave() { + + var label = active_label; + + if (!xmlhttp_ready(xmlhttp)) { + printLockingError(); + return + } + + var sqlexp = document.getElementById("iedit_expr").value; + var descr = document.getElementById("iedit_descr").value; + +// notify("Saving label " + sqlexp + ": " + descr); + + if (sqlexp.length == 0) { + notify("SQL expression cannot be blank."); + return; + } + + if (descr.length == 0) { + notify("Caption cannot be blank."); + return; + } + + active_label = false; + + xmlhttp.open("GET", "backend.php?op=pref-labels&subop=editSave&id=" + + label + "&s=" + param_escape(sqlexp) + "&d=" + param_escape(descr), + true); + + xmlhttp.onreadystatechange=labellist_callback; + xmlhttp.send(null); + +} + function filterEditSave() { var filter = active_filter; @@ -399,27 +579,21 @@ function filterEditSave() { } -function removeSelectedFilters() { +function editSelectedLabel() { + var rows = getSelectedLabels(); - if (!xmlhttp_ready(xmlhttp)) { - printLockingError(); - return + if (rows.length == 0) { + notify("No labels are selected."); + return; } - var sel_rows = getSelectedFilters(); - - if (sel_rows.length > 0) { - - notify("Removing selected filters..."); + if (rows.length > 1) { + notify("Please select one label."); + return; + } - xmlhttp.open("GET", "backend.php?op=pref-filters&subop=remove&ids="+ - param_escape(sel_rows.toString()), true); - xmlhttp.onreadystatechange=filterlist_callback; - xmlhttp.send(null); + editLabel(rows[0]); - } else { - notify("Please select some filters first."); - } } @@ -496,6 +670,22 @@ function updateFilterList() { } +function updateLabelList() { + + if (!xmlhttp_ready(xmlhttp)) { + printLockingError(); + return + } + + document.getElementById("labelConfPane").innerHTML = "Loading labels, please wait..."; + + xmlhttp.open("GET", "backend.php?op=pref-labels", true); + xmlhttp.onreadystatechange=labellist_callback; + xmlhttp.send(null); + +} + + function expandPane(id) { var container; @@ -506,6 +696,8 @@ function expandPane(id) { updateFeedList(); } else if (id == "filterConfPane") { updateFilterList(); + } else if (id == "labelConfPane") { + updateLabelList(); } } diff --git a/prefs.php b/prefs.php index 106488e9..7f21a60f 100644 --- a/prefs.php +++ b/prefs.php @@ -60,6 +60,18 @@
    + + +

    Label Editor

    + +
    + Expand section > + +
    + + + diff --git a/schema/ttrss_schema_mysql.sql b/schema/ttrss_schema_mysql.sql index 348cb242..b7267e3b 100644 --- a/schema/ttrss_schema_mysql.sql +++ b/schema/ttrss_schema_mysql.sql @@ -60,4 +60,15 @@ create table ttrss_filters (id integer primary key auto_increment, reg_exp varchar(250) not null, description varchar(250) not null default '') TYPE=InnoDB; +drop table ttrss_labels; + +create table ttrss_labels (id integer primary key auto increment, + sql_exp varchar(250) not null, + description varchar(250) not null); + +insert into ttrss_labels (sql_exp,description) values ('title = \'Interesting Topic\'', + 'Example Label'); + +insert into ttrss_labels (sql_exp,description) values ('unread = true', + 'Unread articles'); diff --git a/schema/ttrss_schema_pgsql.sql b/schema/ttrss_schema_pgsql.sql index 95887acb..0bb70448 100644 --- a/schema/ttrss_schema_pgsql.sql +++ b/schema/ttrss_schema_pgsql.sql @@ -59,3 +59,15 @@ create table ttrss_filters (id serial primary key, reg_exp varchar(250) not null, description varchar(250) not null default ''); +drop table ttrss_labels; + +create table ttrss_labels (id serial primary key, + sql_exp varchar(250) not null, + description varchar(250) not null); + +insert into ttrss_labels (sql_exp,description) values ('title = \'Interesting Topic\'', + 'Example Label'); + +insert into ttrss_labels (sql_exp,description) values ('unread = true', + 'Unread articles'); + diff --git a/tt-rss.css b/tt-rss.css index a7fc30d4..cb2fdc51 100644 --- a/tt-rss.css +++ b/tt-rss.css @@ -204,7 +204,7 @@ a:hover { opacity : 0.8; } -#iedit_title, #iedit_link, #iedit_regexp, #iedit_descr { +#iedit_title, #iedit_link, #iedit_regexp, #iedit_descr, #iedit_expr { width : 100%; padding-left : 2px; } -- 2.39.5