diff options
author | Andrew Dolgov <[email protected]> | 2005-09-08 08:43:44 +0100 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2005-09-08 08:43:44 +0100 |
commit | 48f0adb02e8aacfc5850fd6ec2f15a9fb1af7561 (patch) | |
tree | 54e2415464a16c4f5fc094869fce93cc0bc613db | |
parent | 7bb699de1c568c23c1f102f4b9396d8294dfc242 (diff) |
virtual feeds (labels) support
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | backend.php | 199 | ||||
-rw-r--r-- | config.php-dist | 5 | ||||
-rw-r--r-- | images/label.png | bin | 0 -> 712 bytes | |||
-rw-r--r-- | images/label.svg | 73 | ||||
-rw-r--r-- | prefs.js | 224 | ||||
-rw-r--r-- | prefs.php | 12 | ||||
-rw-r--r-- | schema/ttrss_schema_mysql.sql | 11 | ||||
-rw-r--r-- | schema/ttrss_schema_pgsql.sql | 12 | ||||
-rw-r--r-- | tt-rss.css | 2 |
10 files changed, 517 insertions, 24 deletions
@@ -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 a16927cdd..8b39ce5f3 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 "<li><hr></li>"; + } + + while ($line = db_fetch_assoc($result)) { + + printFeedEntry(-$line["id"]-11, + "odd", $line["description"], 0, "images/label.png"); + + } + } + print "<li><hr></li>"; $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 "<tr><td colspan='4' align='center'> + Could not display feed (query failed). Please check match syntax or local configuration.</td></tr>"; + 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<br>"; +// print "[viewfeed] feed type not implemented<br>"; + $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 "<table class=\"prefAddFeed\"><tr> + <td><input id=\"ladd_expr\"></td>"; + + print"<td colspan=\"4\" align=\"right\"> + <a class=\"button\" href=\"javascript:addLabel()\">Add label</a></td></tr> + </table>"; + + $result = db_query($link, "SELECT + id,sql_exp,description + FROM + ttrss_labels ORDER by description"); + + print "<p><table width=\"100%\" class=\"prefLabelList\" id=\"prefLabelList\">"; + + print "<tr class=\"title\"> + <td width=\"5%\">Select</td><td width=\"40%\">SQL expression</td> + <td width=\"40%\">Caption</td></tr>"; + + $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 "<tr class=\"$class\" id=\"LILRR-$label_id\">"; + + $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 "<td><input onclick='toggleSelectRow(this);' + type=\"checkbox\" id=\"LICHK-".$line["id"]."\"></td>"; + + print "<td><a href=\"javascript:editLabel($label_id);\">" . + $line["sql_exp"] . "</td>"; + + print "<td><a href=\"javascript:editLabel($label_id);\">" . + $line["description"] . "</td>"; + + } else if ($label_id != $edit_label_id) { + + if (!$line["description"]) $line["description"] = "[No description]"; + + print "<td><input disabled=\"true\" type=\"checkbox\" + id=\"LICHK-".$line["id"]."\"></td>"; + + print "<td>".$line["sql_exp"]."</td>"; + print "<td>".$line["description"]."</td>"; + + } else { + + print "<td><input disabled=\"true\" type=\"checkbox\"></td>"; + + print "<td><input id=\"iedit_expr\" value=\"".$line["sql_exp"]. + "\"></td>"; + + print "<td><input id=\"iedit_descr\" value=\"".$line["description"]. + "\"></td>"; + + } + + + print "</tr>"; + + ++$lnum; + } + + if ($lnum == 0) { + print "<tr><td colspan=\"4\" align=\"center\">No labels defined.</td></tr>"; + } + + print "</table>"; + + print "<p>"; + + if ($subop == "edit") { + print "Edit label: + <input type=\"submit\" class=\"button\" + onclick=\"javascript:labelEditCancel()\" value=\"Cancel\"> + <input type=\"submit\" class=\"button\" + onclick=\"javascript:labelEditSave()\" value=\"Save\">"; + + } else { + + print " + Selection: + <input type=\"submit\" class=\"button\" + onclick=\"javascript:editSelectedLabel()\" value=\"Edit\"> + <input type=\"submit\" class=\"button\" + onclick=\"javascript:removeSelectedLabels()\" value=\"Remove\">"; + } + } + if ($op == "error") { print "<div width=\"100%\" align='center'>"; $msg = $_GET["msg"]; diff --git a/config.php-dist b/config.php-dist index d5bcdc9b9..bb110fe7a 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 Binary files differnew file mode 100644 index 000000000..2d6b08949 --- /dev/null +++ b/images/label.png diff --git a/images/label.svg b/images/label.svg new file mode 100644 index 000000000..d52b4b0eb --- /dev/null +++ b/images/label.svg @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16.000000px" + height="16.000000px" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.42" + sodipodi:docbase="/home/fox/public_html/testbox/tt-rss/images" + sodipodi:docname="label.svg" + inkscape:export-filename="/home/fox/public_html/testbox/tt-rss/images/label.png" + inkscape:export-xdpi="90.000000" + inkscape:export-ydpi="90.000000"> + <defs + id="defs4" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0000000" + inkscape:pageshadow="2" + inkscape:zoom="44.800000" + inkscape:cx="12.795341" + inkscape:cy="5.5747613" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="1600" + inkscape:window-height="1131" + inkscape:window-x="0" + inkscape:window-y="25" + showguides="true" + inkscape:guide-bbox="true" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <path + sodipodi:type="star" + style="opacity:1.0000000;fill:#fde4a8;fill-opacity:1.0000000;stroke:#8e8267;stroke-width:0.99999940;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-opacity:1.0000000" + id="path1306" + sodipodi:sides="13" + sodipodi:cx="7.3551731" + sodipodi:cy="1.6684607" + sodipodi:r1="4.0159702" + sodipodi:r2="6.3745561" + sodipodi:arg1="0.78539816" + sodipodi:arg2="1.0270591" + inkscape:flatsided="false" + inkscape:rounded="0.0000000" + inkscape:randomized="0.0000000" + d="M 10.194893,4.5081805 L 10.652972,7.1236863 L 8.5499365,5.5025913 L 7.7400595,8.0313867 L 6.6312743,5.6186490 L 4.7389739,7.4814175 L 4.8784485,4.8297662 L 2.3372280,5.5997699 L 3.6930105,3.3166663 L 1.0850329,2.8175068 L 3.3465298,1.4259825 L 1.2692514,-0.22798895 L 3.9183810,-0.40915252 L 2.8476811,-2.8390309 L 5.2775598,-1.7683314 L 5.4587230,-4.4174609 L 7.1126948,-2.3401826 L 8.5042187,-4.6016796 L 9.0033787,-1.9937019 L 11.286482,-3.3494846 L 10.516479,-0.80826392 L 13.168130,-0.94773892 L 11.305361,0.94456185 L 13.718099,2.0533466 L 11.189304,2.8632241 L 12.810399,4.9662594 L 10.194893,4.5081805 z " + transform="matrix(-0.707107,-0.707107,0.707107,-0.707107,12.02111,14.98939)" /> + </g> +</svg> @@ -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(); } } @@ -60,6 +60,18 @@ </div> + <? if (ENABLE_LABELS) { ?> + + <h2>Label Editor</h2> + + <div class="expPane" id="labelConfPane"> + <a class="button" + href="javascript:expandPane('labelConfPane')">Expand section ></a> + + </div> + + <? } ?> + </td> </tr> <tr> diff --git a/schema/ttrss_schema_mysql.sql b/schema/ttrss_schema_mysql.sql index 348cb2421..b7267e3b7 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 95887acb3..0bb704483 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 a7fc30d4f..cb2fdc51b 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; } |