]> git.wh0rd.org Git - tt-rss.git/commitdiff
virtual feeds (labels) support
authorAndrew Dolgov <fox@bah.spb.su>
Thu, 8 Sep 2005 07:43:44 +0000 (08:43 +0100)
committerAndrew Dolgov <fox@bah.spb.su>
Thu, 8 Sep 2005 07:43:44 +0000 (08:43 +0100)
NEWS
backend.php
config.php-dist
images/label.png [new file with mode: 0644]
images/label.svg [new file with mode: 0644]
prefs.js
prefs.php
schema/ttrss_schema_mysql.sql
schema/ttrss_schema_pgsql.sql
tt-rss.css

diff --git a/NEWS b/NEWS
index 008ccf929b3144e447cd1864ba50cc8824453275..0a39a392151225fe7ae9355d57a6ae27d4fdbbe7 100644 (file)
--- 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)
 
index a16927cdd488823d7df3d621ffa01d654a0dd14a..8b39ce5f312a24c730918567e844662e68227c7b 100644 (file)
 
                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 *,
 
                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,
                        $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)) {
                        $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() 
                
                }
        }
 
+       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"];
index d5bcdc9b976771cbe29d16fb9e59864460957cee..bb110fe7a6580f5bf8c070d394cc272b132b164b 100644 (file)
        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 (file)
index 0000000..2d6b089
Binary files /dev/null and b/images/label.png differ
diff --git a/images/label.svg b/images/label.svg
new file mode 100644 (file)
index 0000000..d52b4b0
--- /dev/null
@@ -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>
index d95542178cf5eccabc323cdd3de9d5eb33ddd11d..2d04efedc82e96fc215f4c628c1eee03c73af9bd 100644 (file)
--- 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();
        }
 }
 
index 106488e93d3a4d4b5d69f4edfa4a16c8d5e7fe0b..7f21a60f08db4209f98d84d8fefd3c6474aaaa91 100644 (file)
--- a/prefs.php
+++ b/prefs.php
 
                </div>
 
+               <? if (ENABLE_LABELS) { ?>
+
+               <h2>Label Editor</h2>
+
+               <div class="expPane" id="labelConfPane">
+                       <a class="button" 
+                               href="javascript:expandPane('labelConfPane')">Expand section &gt;</a>
+
+               </div>
+
+               <? } ?>
+
        </td>
 </tr>
 <tr>
index 348cb24211c49608fadbf70df362f79df9b89d41..b7267e3b7a98dd767a8e9ace7af45848c0aced4c 100644 (file)
@@ -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');
 
index 95887acb316c372adcf369c4eb2ba2de689a05ed..0bb704483a7773f8c2c142c985caef17b3dbc206 100644 (file)
@@ -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');
+
index a7fc30d4f466c79e8b409ffa85cde73e936e1637..cb2fdc51b3aa81c710b6e1b91915ee4ad1523069 100644 (file)
@@ -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;
 }