optimized for speed - OK for nodes, but 4000+ persons is still one second per keystro...
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Wed, 25 Feb 2009 19:40:42 +0000 (19:40 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Wed, 25 Feb 2009 19:40:42 +0000 (19:40 +0000)
planetlab/css/plc_style.css
planetlab/persons/persons.php
plekit/linetabs/linetabs.css
plekit/linetabs/linetabs.js
plekit/php/linetabs.php
plekit/php/table.php
plekit/table/table.css
plekit/table/table.js

index 5d3e791..670d252 100644 (file)
@@ -39,7 +39,7 @@ body {
 *.plc-warning a:visited { text-decoration: none; color:white }
 *.plc-warning a:hover { text-decoration: none; color:black }
 
-/* separator below the minitabs area */
-p.plc-minitabs {
+/* separator below the linetabs area */
+p.plc-linetabs {
     height:15px;
 }
index ca4cb78..ccc4219 100644 (file)
@@ -127,7 +127,7 @@ foreach ($sites as $site) {
 // --------------------
 drupal_set_title($title);
 
-//plekit_linetabs($tabs);
+plekit_linetabs($tabs);
 
 if ( ! $persons ) {
   drupal_set_message ('No account found');
index fe364ae..8f44090 100644 (file)
@@ -1,12 +1,12 @@
 /* $Id$ */
 
-div.minitabs {
+div.linetabs {
     padding: 20px;
     margin: 8px 0;
     width:80%;
     margin:8px auto;
 }
-div.minitabs>ul {
+div.linetabs>ul {
     width: 100%;
     float: left;
     font-size: small;  /* could be specified at a higher level */
@@ -18,7 +18,7 @@ div.minitabs>ul {
     z-index:2;
 }
 
-input.minitabs-submit {
+input.linetabs-submit {
     font-family: verdana, sans-serif;
     font-size: 14px;
     text-align: center;
@@ -29,7 +29,7 @@ input.minitabs-submit {
     /*padding-bottom: 6px;*/
     border-bottom: 0px;
 }    
-div.minitabs>ul>li {
+div.linetabs>ul>li {
     float: left;
     margin: 0;
     padding: 0 8px 0 8px;
@@ -38,7 +38,7 @@ div.minitabs>ul>li {
     position:relative;
 }
 
-div.minitabs>ul>li input.minitabs-submit {
+div.linetabs>ul>li input.linetabs-submit {
     float: left;
     font-size: 85%;
     line-height: 20px;
@@ -49,14 +49,14 @@ div.minitabs>ul>li input.minitabs-submit {
     color: #9c9;  
 }
 
-div.minitabs>ul>li input.active {
+div.linetabs>ul>li input.active {
     /* border-bottom: 4px solid #696; */
     /* padding-bottom: 2px; */
     /* color when mouse is on button */
     color: #696;
 }
 
-#minitabs-sliding {
+#linetabs-sliding {
     position: absolute;
     z-index: 1;
     font-size: 85%;
index 5e89f0f..8ecf5eb 100644 (file)
@@ -1,7 +1,7 @@
 /*
   $Id$
  
-  Animated miniTabs by frequency decoder (http://www.frequency-decoder.com/)
+  Animated linetabs by frequency decoder (http://www.frequency-decoder.com/)
  
   Based on an idea by Rob L Glazebrook (http://www.rootarcana.com/test/smartmini/) itself
   derived from the original idea of Stephen Clark (http://www.sgclark.com/sandbox/minislide/)
@@ -14,7 +14,7 @@
 */
 
 /* class */
-function minitabs () {
+function linetabs () {
   this.currentTab = 0;
   this.activeTab = 0;
   this.destX = 0;
@@ -28,12 +28,12 @@ function minitabs () {
   this.aHeight = 0;
 }
 
-minitabs.prototype.init = function (div) {
+linetabs.prototype.init = function (div) {
   this.ul      = div.down('ul');
   /* the array of <li>'s */
   this.li_s    = this.ul.select('li');
   /* the array of active <input>'s - without any hidden one */
-  this.input_s = this.ul.select('input.minitabs-submit');
+  this.input_s = this.ul.select('input.linetabs-submit');
   
   /* attach event handlers */
   this.li_s.each ( function (li) { 
@@ -47,12 +47,12 @@ minitabs.prototype.init = function (div) {
            elem = elem.previousSibling;
            if (elem.tagName && elem.tagName == "LI") pos++;
          }
-         minitabs_namespace.the_minitabs(elem).initSlide(pos,true);
+         linetabs_namespace.the_linetabs(elem).initSlide(pos,true);
        } )
        } );
   
   this.ul.observe('mouseout', function (event) {
-      var mt = minitabs_namespace.the_minitabs(event.element());
+      var mt = linetabs_namespace.the_linetabs(event.element());
       mt.initSlide(mt.currentTab,true);
       mt.setActive (mt.activeTab,false);
     });
@@ -65,7 +65,7 @@ minitabs.prototype.init = function (div) {
   /* create slice object */
   this.slideObj    = this.ul.parentNode.appendChild(document.createElement("div"));
   this.slideObj.appendChild(document.createTextNode(String.fromCharCode(160)));
-  this.slideObj.id = "minitabs-sliding";
+  this.slideObj.id = "linetabs-sliding";
   
     /* position it */
   this.setSlidingTop();
@@ -79,7 +79,7 @@ minitabs.prototype.init = function (div) {
     
 };
 
-minitabs.prototype.initSlide = function (pos, force) {
+linetabs.prototype.initSlide = function (pos, force) {
   
   if(!force && pos == this.activeTab) return;
   this.setActive (this.activeTab,false);
@@ -88,15 +88,15 @@ minitabs.prototype.initSlide = function (pos, force) {
   this.initAnim();
 };
  
-minitabs.prototype.setActive = function (pos,active) {
-  var input=this.li_s[pos].select('input.minitabs-submit')[0];
+linetabs.prototype.setActive = function (pos,active) {
+  var input=this.li_s[pos].select('input.linetabs-submit')[0];
   if (active)
     input.addClassName('active');
   else
     input.removeClassName('active');
 };
   
-minitabs.prototype.setSlidingTop = function () {
+linetabs.prototype.setSlidingTop = function () {
   var delta=0;
   /* up 5px for firefox */
   /*window.console.log('agent=' + navigator.userAgent);*/
@@ -105,9 +105,9 @@ minitabs.prototype.setSlidingTop = function () {
                              + this.input_s[this.activeTab].offsetTop + delta ) + "px";
 };
   
-minitabs.prototype.initAnim = function() {
+linetabs.prototype.initAnim = function() {
   /* search for the input with type != hidden */
-  var input=this.li_s[this.activeTab].select('input.minitabs-submit')[0];
+  var input=this.li_s[this.activeTab].select('input.linetabs-submit')[0];
   this.destX = parseInt(this.li_s[this.activeTab].offsetLeft + input.offsetLeft 
                        + this.ul.offsetLeft);
   this.destW = parseInt(input.offsetWidth);
@@ -121,7 +121,7 @@ minitabs.prototype.initAnim = function() {
   this.setSlidingTop();
 };
   
-minitabs.prototype.slideIt = function() {
+linetabs.prototype.slideIt = function() {
   
   // Has the browser text size changed?
   var active_li = this.li_s[this.activeTab];
@@ -144,12 +144,12 @@ minitabs.prototype.slideIt = function() {
   }
 };
   
-minitabs.prototype.animate = function(t,b,c,d) {
+linetabs.prototype.animate = function(t,b,c,d) {
   if ((t/=d/2) < 1) return c/2*t*t + b;
   return -c/2 * ((--t)*(t-2) - 1) + b;
 };
 
-minitabs.prototype.submit = function (message) {
+linetabs.prototype.submit = function (message) {
   /* save activeTab before confirmation; some browsers - firefox - send mouseout during confirm .. */
   var submitTab = this.activeTab;
   /* ask for confirmation if message is not empty */
@@ -161,48 +161,48 @@ minitabs.prototype.submit = function (message) {
 }
   
 // globals
-var minitabs_namespace = {
+var linetabs_namespace = {
  init: function () {
-    $$('div.minitabs').each (function (div) {   
+    $$('div.linetabs').each (function (div) {   
        /* create instance and attach it to the <div> element */
-       div.minitabs = new minitabs ();
-       div.minitabs.init(div);
+       div.linetabs = new linetabs ();
+       div.linetabs.init(div);
       } ) ;
     
     var intervalMethod = function () {
-      $$('div.minitabs').each (function (div) {
-         minitabs_namespace.the_minitabs(div).slideIt();
+      $$('div.linetabs').each (function (div) {
+         linetabs_namespace.the_linetabs(div).slideIt();
        } ) ;
     } ;
-    minitabs_namespace.animInterval = setInterval(intervalMethod,10);
+    linetabs_namespace.animInterval = setInterval(intervalMethod,10);
   },
  
  cleanUp: function() {
-    clearInterval(minitabs_namespace.animInterval);
-    minitabs_namespace.animInterval = null;
+    clearInterval(linetabs_namespace.animInterval);
+    linetabs_namespace.animInterval = null;
   },
  
  resize: function (e) {
-    $$('div.minitabs').each ( function (div) { 
-       var mt = div.minitabs; 
+    $$('div.linetabs').each ( function (div) { 
+       var mt = div.linetabs; 
        mt.initSlide(mt.activeTab,true);
       } );
   },
 
  submit: function (id,message) {
-    $(id).minitabs.submit(message);
+    $(id).linetabs.submit(message);
   },
 
- // find the enclosing minitabs object
- the_minitabs: function (elem) {
-    if (elem.match('div.minitabs')) 
-      return elem.minitabs;
+ // find the enclosing linetabs object
+ the_linetabs: function (elem) {
+    if (elem.match('div.linetabs')) 
+      return elem.linetabs;
     else 
-      return elem.up('div.minitabs').minitabs;
+      return elem.up('div.linetabs').linetabs;
   }
  
 };
  
-window.onload   = minitabs_namespace.init;
-window.onunload = minitabs_namespace.cleanUp;
-window.onresize = minitabs_namespace.resize;
+window.onload   = linetabs_namespace.init;
+window.onunload = linetabs_namespace.cleanUp;
+window.onresize = linetabs_namespace.resize;
index 3e89eab..41f211e 100644 (file)
@@ -47,9 +47,9 @@ drupal_set_html_head('
 
 function plekit_linetabs ($array, $id=NULL) {
   // need id to pass to the onclick function attached to the input buttons
-  $id="minitabs";
+  $id="linetabs";
   if (! $id) $id .= '-' + $id;
-  print "<div id='$id' class='minitabs'>";
+  print "<div id='$id' class='linetabs'>";
   print "<ul>";
   foreach ($array as $label=>$todo) {
     // in case we have a simple string, rewrite it as an array
@@ -77,7 +77,7 @@ function plekit_linetabs ($array, $id=NULL) {
     if ( $values ) foreach ($values as $key=>$value) {
        print "<input type=hidden name='$key' value='$value' />";
       }
-    $tracer="class=minitabs-submit";
+    $tracer="class=linetabs-submit";
     // image and its companions 'height' 
     if ($todo['image']) {
       $type='type=image src="' . $todo['image'] . '"';
@@ -89,7 +89,7 @@ function plekit_linetabs ($array, $id=NULL) {
     print "<span title='$bubble'>";
     $message="";
     if ($todo['confirm']) $message=$todo['confirm'] . " ?";
-    print "<input $tracer $type onclick='minitabs_namespace.submit(\"$id\",\"$message\")' />";
+    print "<input $tracer $type onclick='linetabs_namespace.submit(\"$id\",\"$message\")' />";
     print "</span>";
     print "</form></li>\n";
   }
index 65ea41a..4072d2e 100644 (file)
@@ -2,6 +2,8 @@
 
   // $Id$
 
+require_once 'prototype.php';
+
 drupal_set_html_head('
 <script type="text/javascript" src="/plekit/tablesort/tablesort.js"></script>
 <script type="text/javascript" src="/plekit/tablesort/customsort.js"></script>
@@ -86,11 +88,11 @@ class PlekitTable {
   // instantiate paginator callback
     print <<< EOF
 <script type="text/javascript"> 
-function $paginator (opts) { plc_table_paginator (opts,"$this->table_id"); }
+function $paginator (opts) { plekit_table_paginator (opts,"$this->table_id"); }
 </script>
 <br/>
 <table id="$this->table_id" cellpadding="0" cellspacing="0" border="0" 
-class="plc_table sortable-onload-$this->column_sort rowstyle-alt colstyle-alt no-arrow $classname">
+class="plekit_table sortable-onload-$this->column_sort rowstyle-alt colstyle-alt no-arrow $classname">
 <thead>
 EOF;
 
@@ -110,7 +112,7 @@ EOF;
       $class="sortable";
       if ( ! empty($type)) $class .= "-sort" . $type;
     }
-    printf ('<th class="%s plc_table">%s</th>',$class,$label);
+    printf ('<th class="%s plekit_table">%s</th>',$class,$label);
   }
 
   print <<< EOF
@@ -138,11 +140,11 @@ EOF;
     $result= <<< EOF
 <tr class=pagesize_area><td class=pagesize_area colspan=$width><form class='pagesize'>
    <input class='pagesize_input' type='text' id="$pagesize_text_id" value=$this->pagesize 
-      onkeyup='plc_pagesize_set("$this->table_id","$pagesize_text_id", $this->pagesize);' 
+      onkeyup='plekit_pagesize_set("$this->table_id","$pagesize_text_id", $this->pagesize);' 
       size=3 maxlength=3 /> 
   <label class='pagesize_label'> items/page </label>   
   <img class='table_reset' src="/planetlab/icons/clear.png" 
-      onmousedown='plc_pagesize_reset("$this->table_id","$pagesize_text_id",$this->pagesize_def);' />
+      onmousedown='plekit_pagesize_reset("$this->table_id","$pagesize_text_id",$this->pagesize_def);' />
 </form></td></tr>
 EOF;
     return $result;
@@ -158,14 +160,14 @@ EOF;
 <tr class=search_area><td class=search_area colspan=$width><form class='table_search'>
    <label class='table_search_label'> Search </label> 
    <input class='table_search_input' type='text' id='$search_text_id'
-      onkeyup='plc_table_filter("$this->table_id","$search_text_id","$search_and_id");'
+      onkeyup='plekit_table_filter("$this->table_id","$search_text_id","$search_and_id");'
       size=$this->search_width maxlength=256 />
    <label>and</label>
    <input id='$search_and_id' class='table_search_and' 
       type='checkbox' checked='checked' 
-      onchange='plc_table_filter("$this->table_id","$search_text_id","$search_and_id");' />
+      onchange='plekit_table_filter("$this->table_id","$search_text_id","$search_and_id");' />
    <img class='table_reset' src="/planetlab/icons/clear.png" 
-      onmousedown='plc_table_filter_reset("$this->table_id","$search_text_id","$search_and_id");'>
+      onmousedown='plekit_table_filter_reset("$this->table_id","$search_text_id","$search_and_id");'>
 </form></td></tr>
 EOF;
     return $result;
@@ -203,7 +205,7 @@ EOF;
     if (! $notes)
       return "";
     $result = "";
-    $result .= "<p class='plc_table_note'> <span class='plc_table_note_title'>Notes</span>\n";
+    $result .= "<p class='plekit_table_note'> <span class='plekit_table_note_title'>Notes</span>\n";
     foreach ($notes as $note) 
       $result .= "<br/>$note\n";
     $result .= "</p>";
index b2f23f5..34bc799 100644 (file)
@@ -1,19 +1,19 @@
 /* $Id$ */
-table.plc_table {
+table.plekit_table {
     width: auto;
     padding: 0;
     margin: 0 auto 1.5em auto;
     border-collapse:collapse;
 }
-table.plc_table>thead>tr, table.plc_table>tbody>tr {
+table.plekit_table>thead>tr, table.plekit_table>tbody>tr {
     border-left: 1px solid #C1DAD7; 
 }    
 /* remove border for search/pagesize area */
-table.plc_table>thead>tr.pagesize_area, table.plc_table>thead>tr.search_area {
+table.plekit_table>thead>tr.pagesize_area, table.plekit_table>thead>tr.search_area {
     border-left: 0px;
 }    
 
-th.plc_table {
+th.plekit_table {
     font: bold 10px/22px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
     color: #4f6b72;
     border-right: 1px solid #C1DAD7;
@@ -26,12 +26,12 @@ th.plc_table {
     background: #CAE8EA url(/plekit/icons/tablesort-header.jpg) no-repeat;
     vertical-align:middle;
 }
-table.plc_table>tbody>tr>td, table.plc_table textarea, table.plc_table input [type="text"] {
+table.plekit_table>tbody>tr>td, table.plekit_table textarea, table.plekit_table input [type="text"] {
     font: normal 11px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
     border-right: 1px solid #C1DAD7;
     border-bottom: 1px solid #C1DAD7;
 }
-table.plc_table>tbody>tr>td {
+table.plekit_table>tbody>tr>td {
     padding: 6px 12px 6px 12px;
     color: #4f6b72;
 }
@@ -78,15 +78,15 @@ tr.alt {
 tr[class="alt"]>td {
     background: #F5FAFA url(/plekit/icons/tablesort-td-alt.jpg) no-repeat;
 }
-table.plc_table>tbody>tr>td [class~="alt"] {
+table.plekit_table>tbody>tr>td [class~="alt"] {
     background: #edf3f3 url(/plekit/icons/tablesort-col-alt.jpg) no-repeat !important;
 }
 /* Poor old Internet Explorer won't see the next two rules either as it doesn't get :first-child */
-table.plc_table>tbody>tr.alt>td:first-child {
+table.plekit_table>tbody>tr.alt>td:first-child {
     background: #F5FAFA url(/plekit/icons/tablesort-bullet2.gif) no-repeat;
     font-weight:bold;
 }
-table.plc_table>tbody>tr>td:first-child {
+table.plekit_table>tbody>tr>td:first-child {
     background: #fff url(/plekit/icons/tablesort-bullet1.gif) no-repeat;
     font-weight:bold;
 }
@@ -220,13 +220,13 @@ tr.invisibleRow {
 p.paginationText {
     font-style:oblique;
 }
-p.plc_table_note {
+p.plekit_table_note {
     font-style:oblique;
     font-size:0.6em;
     font-family: georgia;
     text-align: center;
 }
-span.plc_table_note_title {
+span.plekit_table_note_title {
     font-weight:bold;
     font-size:1.5em;
     font-family: georgia;
@@ -238,4 +238,8 @@ ul.fdtablePaginater {display:inline-block;}
 mul.fdtablePaginater {display:inline;}
 ul.fdtablePaginater li {float:left;}
 ul.fdtablePaginater {text-align:center;}
-/*table.plc_table { border-bottom:1px solid #C1DAD7; }*/
+/*table.plekit_table { border-bottom:1px solid #C1DAD7; }*/
+
+.table_search_input:focus {
+    background-color: #888;
+}
index 6fa8ca1..5851acd 100644 (file)
@@ -1,24 +1,24 @@
 /* $Id$ */
 
 /* when a table gets paginated, displays context info */
-function plc_table_paginator (opts,tablename) {
+function plekit_table_paginator (opts,table_id) {
 
   if(!("currentPage" in opts)) { return; }
     
   var p = document.createElement('p');
-  var t = document.getElementById(tablename+'-fdtablePaginaterWrapTop');
-  var b = document.getElementById(tablename+'-fdtablePaginaterWrapBottom');
+  var table=$(table_id);
+  var t = $(table_id+'-fdtablePaginaterWrapTop');
+  var b = $(table_id+'-fdtablePaginaterWrapBottom');
 
   /* when there's no visible entry, the pagination code removes the wrappers */
   if ( (!t) || (!b) ) return;
 
   /* get how many entries are matching:
      opts.visibleRows only holds the contents of the current page
-     so we store the number of matching entries in the tbody's 'matching' attribute
+     so we store the number of matching entries in the table 'matching' attribute
   */
   var totalMatches = opts.totalRows;
-  var tbody=document.getElementById(tablename).getElementsByTagName("tbody")[0];
-  var matching=tbody['matching'];
+  var matching=table['matching'];
   if (matching) totalMatches = matching;
 
   var label;
@@ -44,7 +44,7 @@ function plc_table_paginator (opts,tablename) {
 
 
 /* locates a table from its id and alters the classname to reflect new table size */
-function plc_pagesize_set (table_id,size_id,def_size) {
+function plekit_pagesize_set (table_id,size_id,def_size) {
   var table=document.getElementById(table_id);
   var size_area=document.getElementById(size_id);
   if ( ! size_area.value ) {
@@ -55,7 +55,7 @@ function plc_pagesize_set (table_id,size_id,def_size) {
   tablePaginater.init(table_id);
 }
 
-function plc_pagesize_reset(table_id, size_id, size) {
+function plekit_pagesize_reset(table_id, size_id, size) {
   var table=document.getElementById(table_id);
   var size_area=document.getElementById(size_id);
   size_area.value=size;
@@ -64,7 +64,7 @@ function plc_pagesize_reset(table_id, size_id, size) {
 }
   
 /* set or clear the ' invisibleRow' in the tr's classname, according to visible */
-function plc_table_row_visible (row,visible) {
+function plekit_table_row_visible (row,visible) {
   var cn=row.className;
   /* clear */
   cn=cn.replace(" invisibleRow","");
@@ -72,33 +72,50 @@ function plc_table_row_visible (row,visible) {
   row.className=cn;
 }
 
-// from a cell, extract visible text by removing <> and cache in 'plc_text' attribute
-var re_brackets = new RegExp ('<[^>]*>','g');
-
-function plc_table_cell_text (cell) {
-  if (cell['plc_text']) return cell['plc_text'];
-  var text = cell.innerHTML;
-  // remove what's between <>
-  text = text.replace(re_brackets,'');
-  cell['plc_text'] = text;
+// Working around MSIE...
+if ('undefined' == typeof Node)
+    Node = { ELEMENT_NODE: 1, TEXT_NODE: 3 };
+
+// Extract actual text from a DOM node (remove internal tags and so on)
+function getInnerText(node) {
+       var result = '';
+       if (Node.TEXT_NODE == node.nodeType)
+               return node.nodeValue;
+       if (Node.ELEMENT_NODE != node.nodeType)
+               return '';
+       for (var index = 0; index < node.childNodes.length; ++index)
+               result += getInnerText(node.childNodes.item(index));
+       return result;
+} // getInnerText
+
+// cache in the <tr> node the concatenation of the innerTexts of its cells
+function plekit_tr_text (tr) {
+  // if cached, use it
+  if (tr['text_to_match']) return tr['text_to_match'];
+  // otherwise compute it
+  var text="";
+  var cells=tr.cells;
+  for (var i=0; i<cells.length; i++) 
+    text += getInnerText(cells[i]) + " ";
+  text = text.strip().toLowerCase();
+  tr['text_to_match'] = text;
   return text;
 }
 
 /* scan the table, and mark as visible 
    the rows that match (either AND or OR the patterns) */
-function plc_table_filter (table_id,pattern_id,and_id) {
-  var tbody = document.getElementById(table_id).getElementsByTagName("tbody")[0];
-  var rows=tbody.rows;
-  var pattern_area = document.getElementById(pattern_id);
+function plekit_table_filter (table_id,pattern_id,and_id) {
+  var table=$(table_id);
+  var css='#'+table_id+'>tbody';
+  var rows = $$(css)[0].rows;
+  var pattern_area = $(pattern_id);
   var pattern_text = pattern_area.value;
-  var row_index, row, cells, cell_index, cell, visible;
   var matching_entries=0;
-  var and_button=document.getElementById(and_id);
+  var and_button=$(and_id);
   var and_if_true=and_button.checked;
 
-  // remove whitespaces at the beginning and end
-  pattern_text = pattern_text.replace(/[ \t]+$/,"");
-  pattern_text = pattern_text.replace(/^[ \t]+/,"");
+  // canonicalize white spaces 
+  pattern_text = pattern_text.replace(/^\s+/, '').replace(/\s+$/, '').replace(/\s+/g,' ');
   
   if (pattern_text.indexOf ("&") != -1) {
     pattern_text = pattern_text.replace(/&/," ");
@@ -115,17 +132,30 @@ function plc_table_filter (table_id,pattern_id,and_id) {
   var match_attempts=0;
   var start=(new Date).getTime();
 
-  // re compile all patterns - ignore case
-  var pattern_texts = pattern_text.split(" ");
+  // if we're running with the same pattern
+  var previous_pattern=table['previous_pattern'];
+  var previous_mode=table['previous_mode'];
+  if ( (previous_pattern == pattern_text) && (previous_mode == and_if_true) ) {
+    window.console.log ('no change in pattern');
+    return;
+  }
+
+  // re compile all patterns 
+  var pattern_texts = pattern_text.strip().split(" ");
+  var searches=new Array();
   var patterns=new Array();
   for (var i=0; i < pattern_texts.length; i++) {
-    window.console.log ('compiled ' + i + '-th pattern = <' + pattern_texts[i] + '>');
+    window.console.log ('compiled ' + i + '-th pattern = [' + pattern_texts[i] + ']');
+    // ignore case
+    searches[i]=pattern_texts[i].toLowerCase();
     patterns[i]=new RegExp(pattern_texts[i],"i");
   }
 
-  // scan rows
-  for (row_index = 0; row=rows[row_index]; row_index++) {
-      cells=row.cells;
+  // scan rows, elaborate 'visible'
+  window.console.log ('we have ' + rows.length + ' rows');
+  for (var row_index = 0; row_index < rows.length ; row_index++) {
+    var tr=rows[row_index];
+    var visible=false;
     
     /*empty pattern */
     if (patterns.length == 0) {
@@ -133,50 +163,65 @@ function plc_table_filter (table_id,pattern_id,and_id) {
     } else if (and_if_true) {
       /* AND mode: all patterns must match */
       visible=true;
-      for (i in patterns) {
-       var matched=false;
-       var pattern=patterns[i];
-       for (cell_index = 0; cell=cells[cell_index]; cell_index++) {
-         var against=plc_table_cell_text (cell);
-         match_attempts++;
-         if ( against.match(pattern)) {
-           matched=true;
-           break;        
-         }
+      var against=plekit_tr_text (tr);
+      for (var search_index=0; search_index<searches.length; search_index++) {
+       var search=searches[search_index];
+       match_attempts++;
+       if ( against.search(search) < 0) {
+         visible=false;
+         break;          
        }
-       if ( ! matched ) visible=false;
       }
     } else {
       /* OR mode: any match is good enough */
       visible=false;
-      for (cell_index = 0; cell=cells[cell_index]; cell_index++) {
-       var against = cell.plc_table_cell_text(cell);
-       for (i in patterns) {
-         pattern=patterns[i];
-         match_attempts++;
-         if (against.match(pattern)) {
-           visible=true;
-           // alert ('OR matched! p='+pattern+' c='+cell.innerHTML);
-           break;
-         }
+      var against = plekit_tr_text(tr);
+      for (var search_index=0; search_index < searches.length; search_index++) {
+       var search=searches[search_index];
+       match_attempts++;
+       if (against.search(search) >= 0) {
+         visible=true;
+         break;
        }
       }
     }
-    plc_table_row_visible(row,visible);
+
+    plekit_table_row_visible(tr,visible);
     if (visible) matching_entries +=1;
   }
+  // save for next run
+  table['previous_pattern']=pattern_text;
+  table['previous_mode']=and_if_true;
+  
   var end=(new Date).getTime();
-  var ms=end-start;
-  window.console.log ("plc_table_filter: " + 
-                     match_attempts + " matches - " +
-                     matching_entries + " lines - " + ms + " ms");
-  tbody['matching']=matching_entries;
-  tbody['match_attempts']=match_attempts;
+  var match_ms=end-start;
+
+  // optimize useless calls to init, by comparing # of matching entries
+  var previous_matching=table['previous_matching'];
+  if (matching_entries == previous_matching) {
+    window.console.log ('same # of matching entries - skipped redisplay');
+    window.console.log ("plekit_table_filter: " + 
+                       match_attempts + " matches - " +
+                       matching_entries + " lines - " 
+                       + "match=" + match_ms + " ms");
+    return;
+  }
+  
+  table['matching']=matching_entries;
+  table['match_attempts']=match_attempts;
   tablePaginater.init(table_id);
+  var end2=(new Date).getTime();
+  var paginate_ms=end2-end;
+  window.console.log ("plekit_table_filter: " + 
+                     match_attempts + " matches - " +
+                     matching_entries + " lines - " 
+                     + "match=" + match_ms + " ms - "
+                     + "paginate=" + paginate_ms + " ms");
+  
 }
 
-function plc_table_filter_reset (table_id, pattern_id,and_id) {
+function plekit_table_filter_reset (table_id, pattern_id,and_id) {
   /* reset pattern */
   document.getElementById(pattern_id).value="";
-  plc_table_filter (table_id, pattern_id,and_id);
+  plekit_table_filter (table_id, pattern_id,and_id);
 }