Commit 8796a741d6f1a84190eb9a3446fab9a6bb4f448d

Authored by Brad Shuttleworth
1 parent b9e8879e

saved searches complete, + title support.


git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@4583 c91229c3-7414-0410-bfa2-8a42b809f60b
lib/browse/Criteria.inc
... ... @@ -157,8 +157,16 @@ class BrowseCriterion {
157 157 return "<tr><td>" . $this->headerDisplay() . ": </td><td>" . $this->searchWidget($aRequest) . "</td></tr>\n";
158 158 }
159 159  
160   - function searchWidget ($aRequest) {
161   - return "<input type=\"text\" size=\"50\" name=\"" . $this->getWidgetBase() . "\" />";
  160 + function searchWidget ($aRequest, $aPreValue = null) {
  161 + if ($aPreValue != null) {
  162 + // !#@&)*( (*&!@# *(&@!(*&!@#
  163 + $k = array_keys($aPreValue);
  164 + $k = $k[0];
  165 + $preval = $aPreValue[$k];
  166 + return "<input type=\"text\" size=\"50\" name=\"" . $this->getWidgetBase() . "\" value=\"" . $preval . "\"/>";
  167 + } else {
  168 + return "<input type=\"text\" size=\"50\" name=\"" . $this->getWidgetBase() . "\" />";
  169 + }
162 170 }
163 171  
164 172 function getWidgetBase () {
... ... @@ -255,12 +263,21 @@ class CreatorCriterion extends BrowseCriterion {
255 263 function folderDisplay($oFolder) {
256 264 return $this->documentDisplay($oFolder);
257 265 }
258   - function searchWidget ($aRequest) {
  266 + function searchWidget ($aRequest, $aPreValue = null) {
  267 + $preval = null;
  268 + if ($aPreValue != null) {
  269 + // !#@&)*( (*&!@# *(&@!(*&!@#
  270 + $k = array_keys($aPreValue);
  271 + $k = $k[0];
  272 + $preval = $aPreValue[$k];
  273 + }
259 274 $sRet = "<select size=\"1\" name=\"" . $this->getWidgetBase() . "\">\n";
260 275 $aUsers = User::getList();/*ok*/
261 276 $sRet .= "<option value=\"-1\">None</option>\n";
262 277 foreach ($aUsers as $oUser) {
263   - $sRet .= "<option value=\"" . $oUser->getID() . "\">" . $oUser->getName() . "</option>\n";
  278 + $sSelStr = '';
  279 + if ($preval == $oUser->getId()) { $sSelStr = ' selected="true"'; }
  280 + $sRet .= "<option value=\"" . $oUser->getID() . "\"" . $sSelStr . ">" . $oUser->getName() . "</option>\n";
264 281 }
265 282 $sRet .= "</select>\n";
266 283 return $sRet;
... ... @@ -274,15 +291,10 @@ class DateCreatedCriterion extends BrowseCriterion {
274 291 function getName() {
275 292 return "created";
276 293 }
277   - function searchWidget ($aRequest) {
  294 + function searchWidget ($aRequest, $aPreValue = null) {
278 295 global $default;
279 296  
280   - // this is not ideal, but we don't actually have access to the
281   - // dispatcher's oPage object.
282   -
283   - // even worse, we may _not_ have the items we want.
284   -
285   - global $main;
  297 + // IMPORTANT: this requires the presence of kt3-calendar.js
286 298  
287 299 $sStartWidget = $this->getWidgetBase() . "_start";
288 300 $sEndWidget = $this->getWidgetBase() . "_end";
... ... @@ -292,8 +304,8 @@ class DateCreatedCriterion extends BrowseCriterion {
292 304 $sToRender .= " &nbsp; Before date: <input type=\"text\" size=\"10\" name=\"" . $sEndWidget . "\" />";
293 305 $sToRender .= "&nbsp;&nbsp;<a href=\"javascript:show_calendar('MainForm." . $sEndWidget . "',null,null,'YYYY-MM-DD', false);\" onmouseover=\"window.status='Date Picker';return true;\" onmouseout=\"window.status='';return true;\"><img src=\"$default->graphicsUrl/calendar/calendar.gif\" name=\"imgCalendar\" width=\"34\" height=\"21\" border=\"0\" alt=\"\"></a>";
294 306 */
295   - $sToRender = 'After Date: <span class="kt_calendar_holder"><strong class="kt_calendar_datetext">No Date Selected</strong><input type="hidden" name="' . $sStartWidget . '" class="kt_calendar_value" /> <input type="button" onclick="init_kt_calendar(this);" value="select"></span> &mdash; ';
296   - $sToRender .= 'Before Date: <span class="kt_calendar_holder"><strong class="kt_calendar_datetext">No Date Selected</strong><input type="hidden" name="' . $sEndWidget . '" class="kt_calendar_value" /> <input type="button" onclick="init_kt_calendar(this);" value="select"></span><br />';
  307 + $sToRender = 'After Date: <span class="kt_calendar_holder"><strong class="kt_calendar_datetext">' . $aPreValue[$sStartWidget] . '</strong><input type="hidden" name="' . $sStartWidget . '" class="kt_calendar_value" value="' . $aPreValue[$sStartWidget] . '"/> <input type="button" onclick="init_kt_calendar(this);" value="select"></span> &mdash; ';
  308 + $sToRender .= 'Before Date: <span class="kt_calendar_holder"><strong class="kt_calendar_datetext">' . $aPreValue[$sStartWidget] . '</strong><input type="hidden" name="' . $sEndWidget . '" class="kt_calendar_value" value="' . $aPreValue[$sEndWidget] . '"/> <input type="button" onclick="init_kt_calendar(this);" value="select"></span><br />';
297 309 return $sToRender;
298 310 }
299 311 function searchSQL ($aRequest) {
... ... @@ -338,12 +350,21 @@ class DocumentTypeCriterion extends BrowseCriterion {
338 350 }
339 351 return "&nbsp;";
340 352 }
341   - function searchWidget ($aRequest) {
  353 + function searchWidget ($aRequest, $aPreValue = null) {
  354 + $preval = null;
  355 + if ($aPreValue != null) {
  356 + // !#@&)*( (*&!@# *(&@!(*&!@#
  357 + $k = array_keys($aPreValue);
  358 + $k = $k[0];
  359 + $preval = $aPreValue[$k];
  360 + }
342 361 $sRet = "<select size=\"1\" name=\"" . $this->getWidgetBase() . "\">\n";
343 362 $aUsers = DocumentType::getList();/*ok*/
344 363 $sRet .= "<option value=\"-1\">None</option>\n";
345 364 foreach ($aUsers as $oUser) {
346   - $sRet .= "<option value=\"" . $oUser->getID() . "\">" . $oUser->getName() . "</option>\n";
  365 + $sSelStr = '';
  366 + if ($preval == $oUser->getId()) { $sSelStr = ' selected="true"'; }
  367 + $sRet .= "<option value=\"" . $oUser->getID() . "\"" . $sSelStr . ">" . $oUser->getName() . "</option>\n";
347 368 }
348 369 $sRet .= "</select>\n";
349 370 return $sRet;
... ... @@ -392,10 +413,17 @@ class GenericMetadataCriterion extends BrowseCriterion {
392 413 return $this->aLookup['field'];
393 414 }
394 415  
395   - function searchWidget ($aRequest) {
  416 + function searchWidget ($aRequest, $aPreValue = null) {
  417 + $preval = null;
  418 + if ($aPreValue != null) {
  419 + // !#@&)*( (*&!@# *(&@!(*&!@#
  420 + $k = array_keys($aPreValue);
  421 + $k = $k[0];
  422 + $preval = $aPreValue[$k];
  423 + }
396 424 // If there's no lookup, just use the standard text input
397 425 if ($this->oField->getHasLookup() == false) {
398   - return parent::searchWidget($aRequest);
  426 + return parent::searchWidget($aRequest, $aPreValue);
399 427 }
400 428  
401 429 $sRet = "<select size=\"1\" name=\"" . $this->getWidgetBase() . "\">\n";
... ... @@ -403,7 +431,9 @@ class GenericMetadataCriterion extends BrowseCriterion {
403 431 $aMetaData = MetaData::getList($aSearch);/*ok*/
404 432 $sRet .= "<option value=\"-1\">None</option>\n";
405 433 foreach ($aMetaData as $oMetaData) {
406   - $sRet .= "<option value=\"" . $oMetaData->getName() . "\">" . $oMetaData->getName() . "</option>\n";
  434 + $sSelStr = '';
  435 + if ($preval == $oMetaData->getName()) { $sSelStr = ' selected="true"'; }
  436 + $sRet .= "<option value=\"" . $oMetaData->getName() . "\" " . $sSelStr . ">" . $oMetaData->getName() . "</option>\n";
407 437 }
408 438 $sRet .= "</select>\n";
409 439 return $sRet;
... ... @@ -498,13 +528,23 @@ class WorkflowStateCriterion extends BrowseCriterion {
498 528 return "INNER JOIN $default->workflow_documents_table AS WD ON D.id = WD.document_id";
499 529 }
500 530  
501   - function searchWidget ($aRequest) {
  531 + function searchWidget ($aRequest, $aPreValue = null) {
  532 + $preval = null;
  533 + if ($aPreValue != null) {
  534 + // !#@&)*( (*&!@# *(&@!(*&!@#
  535 + $k = array_keys($aPreValue);
  536 + $k = $k[0];
  537 + $preval = $aPreValue[$k];
  538 + }
  539 +
502 540 $sRet = "<select size=\"1\" name=\"" . $this->getWidgetBase() . "\">\n";
503 541 $aStates = KTWorkflowState::getList("ORDER BY workflow_id");
504 542 $sRet .= "<option value=\"-1\">None</option>\n";
505 543 foreach ($aStates as $oState) {
506 544 $oWorkflow =& KTWorkflow::get($oState->getWorkflowId());
507   - $sRet .= "<option value=\"" . $oState->getId() . "\">" . $oWorkflow->getName() . " - " . $oState->getName() . "</option>\n";
  545 + $sSelStr = '';
  546 + if ($preval == $oState->getId()) { $sSelStr = ' selected="true"'; }
  547 + $sRet .= "<option value=\"" . $oState->getId() . "\"" . $sSelStr . ">" . $oWorkflow->getName() . " - " . $oState->getName() . "</option>\n";
508 548 }
509 549 $sRet .= "</select>\n";
510 550 return $sRet;
... ...
plugins/ktcore/KTCorePlugin.php
... ... @@ -120,7 +120,7 @@ class KTCorePlugin extends KTPlugin {
120 120 $this->registerAdminPage("savedsearch", 'KTSavedSearchDispatcher', 'misc',
121 121 _('Saved searches'),
122 122 _('Manage saved searches - searches available by default to all users.'),
123   - 'admin/manageHelp.php', null);
  123 + 'admin/savedSearch.php', null);
124 124  
125 125 // plugins
126 126 $this->registerAdminPage("plugins", 'KTPluginDispatcher', 'plugins',
... ...
plugins/ktcore/admin/savedSearch.php
... ... @@ -9,10 +9,16 @@ require_once(KT_LIB_DIR . &quot;/search/savedsearch.inc.php&quot;);
9 9 class KTSavedSearchDispatcher extends KTStandardDispatcher {
10 10 var $bAutomaticTransaction = true;
11 11  
  12 + function check() {
  13 + $this->oPage->setTitle(_('Manage Saved Searches'));
  14 + return true;
  15 + }
  16 +
12 17 function do_main() {
13 18 $oTemplate =& $this->oValidator->validateTemplate('ktcore/search/administration/savedsearches');
14 19 $oTemplate->setData(array(
15 20 'saved_searches' => KTSavedSearch::getList(),
  21 + 'context' => $this,
16 22 ));
17 23 return $oTemplate->render();
18 24 }
... ... @@ -27,6 +33,8 @@ class KTSavedSearchDispatcher extends KTStandardDispatcher {
27 33 "title" => _("Create a new condition"),
28 34 "aCriteria" => $aCriteria,
29 35 "searchButton" => _("Save"),
  36 + 'context' => $this,
  37 + "sNameTitle" => _('New Stored Search'),
30 38 );
31 39 return $oTemplate->render($aTemplateData);
32 40 }
... ... @@ -34,10 +42,92 @@ class KTSavedSearchDispatcher extends KTStandardDispatcher {
34 42 function do_view() {
35 43  
36 44 }
  45 +
  46 + function do_edit() {
  47 + $id = KTUtil::arrayGet($_REQUEST, 'fSavedSearchId');
  48 + $oSearch = KTSavedSearch::get($id);
  49 +
  50 + if (PEAR::isError($oSearch) || ($oSearch == false)) {
  51 + $this->errorRedirectToMain('No Such search');
  52 + }
  53 +
  54 + $aSearch = $oSearch->getSearch();
  55 +
  56 +
  57 + $oTemplating = new KTTemplating;
  58 + $oTemplate = $oTemplating->loadTemplate("ktcore/boolean_search_edit");
  59 +
  60 + $aCriteria = Criteria::getAllCriteria();
  61 +
  62 + // we need to help out here, since it gets unpleasant inside the template.
  63 + foreach ($aSearch['subgroup'] as $isg => $as) {
  64 + $aSubgroup =& $aSearch['subgroup'][$isg];
  65 + foreach ($aSubgroup['values'] as $iv => $t) {
  66 + $datavars =& $aSubgroup['values'][$iv];
  67 + $datavars['typename'] = $aCriteria[$datavars['type']]->sDisplay;
  68 + $datavars['widgetval'] = $aCriteria[$datavars['type']]->searchWidget(null, $datavars['data']);
  69 + }
  70 + }
  71 +
  72 + //$s = '<pre>';
  73 + //$s .= print_r($aSearch, true);
  74 + //$s .= '</pre>';
  75 + //print $s;
  76 +
  77 + $aTemplateData = array(
  78 + "title" => _("Edit an existing condition"),
  79 + "aCriteria" => $aCriteria,
  80 + "searchButton" => _("Update Saved Search"),
  81 + 'aSearch' => $aSearch,
  82 + 'context' => $this,
  83 + 'iSearchId' => $oSearch->getId(),
  84 + 'old_name' => $oSearch->getName(),
  85 + 'sNameTitle' => _('Edit Search'),
  86 + );
  87 + return $oTemplate->render($aTemplateData);
  88 +
  89 + //return $s;
  90 + }
  91 +
  92 + // XXX: Rename to do_save
  93 + function do_updateSearch() {
  94 + $id = KTUtil::arrayGet($_REQUEST, 'fSavedSearchId');
  95 + $sName = KTUtil::arrayGet($_REQUEST, 'name');
  96 + $oSearch = KTSavedSearch::get($id);
  97 +
  98 + if (PEAR::isError($oSearch) || ($oSearch == false)) {
  99 + $this->errorRedirectToMain('No Such search');
  100 + }
  101 +
  102 +
  103 + $datavars = KTUtil::arrayGet($_REQUEST, 'boolean_search');
  104 + if (!is_array($datavars)) {
  105 + $datavars = unserialize($datavars);
  106 + }
  107 +
  108 + if (empty($datavars)) {
  109 + $this->errorRedirectToMain(_('You need to have at least 1 condition.'));
  110 + }
  111 +
  112 + //$sName = "Neil's saved search";
  113 + if (!empty($sName)) {
  114 + $oSearch->setName($sName);
  115 + }
  116 +
  117 + $oSearch->setSearch($datavars);
  118 + $res = $oSearch->update();
  119 +
  120 + $this->oValidator->notError($res, array(
  121 + 'redirect_to' => 'main',
  122 + 'message' => _('Search not saved'),
  123 + ));
  124 + $this->successRedirectToMain(_('Search saved'));
  125 + }
37 126  
38 127 // XXX: Rename to do_save
39 128 function do_performSearch() {
40 129 $datavars = KTUtil::arrayGet($_REQUEST, 'boolean_search');
  130 + $sName = KTUtil::arrayGet($_REQUEST, 'name');
41 131 if (!is_array($datavars)) {
42 132 $datavars = unserialize($datavars);
43 133 }
... ... @@ -46,7 +136,6 @@ class KTSavedSearchDispatcher extends KTStandardDispatcher {
46 136 $this->errorRedirectToMain(_('You need to have at least 1 condition.'));
47 137 }
48 138  
49   - $sName = "Neil's saved search";
50 139 $sNamespace = KTUtil::nameToLocalNamespace('Saved searches', $sName);
51 140  
52 141 $oSearch = KTSavedSearch::createFromArray(array(
... ... @@ -66,7 +155,7 @@ class KTSavedSearchDispatcher extends KTStandardDispatcher {
66 155 }
67 156 }
68 157  
69   -$oDispatcher = new KTSavedSearchDispatcher();
70   -$oDispatcher->dispatch();
  158 +//$oDispatcher = new KTSavedSearchDispatcher();
  159 +//$oDispatcher->dispatch();
71 160  
72 161 ?>
... ...
resources/js/constructed_search_postprocess.js 0 โ†’ 100644
  1 +/* Constructed Search Postprocessing.
  2 + *
  3 + * In order to make everything as seamless as possible, we do a
  4 + * JS based postprocess on the boolean_search pages.
  5 + *
  6 + * This needs to do two things:
  7 + * - adjust all the input.name elements.
  8 + * - push the autoIncrement vars so we don't have modification conflicts.
  9 + */
  10 +
  11 +
  12 +// expects a table row in canonical format, ready for var-modification.
  13 +function processRow(tablerow, parent_table) {
  14 + var inputs = tablerow.getElementsByTagName('INPUT');
  15 +
  16 + // unfortunate note: if we have > 1 items, we are dealing with a "real" row.
  17 + // (1 since select != input, and <input type=button>.
  18 + // (not == 2 since we can have arbitrary other items...
  19 +
  20 + if (inputs.length > 1) { // is a "predefined" row.
  21 + autoIndexCriteria.push(0);
  22 + var crit_id = autoIndexCriteria.length;
  23 + var table_id = getBooleanGroupId(parent_table);
  24 +
  25 + // we also need "SELECT" items.
  26 +
  27 + var selects = tablerow.getElementsByTagName('SELECT');
  28 +
  29 + if (inputs[0].name != '') {
  30 + alert('invalid output.');
  31 + return null;
  32 + } else {
  33 + inputs[0].name = 'boolean_search[subgroup]['+table_id+'][values]['+crit_id+'][type]';
  34 + }
  35 +
  36 + // different from constructed_search: remove the _initial_ INPUT type="hidden, and the button.
  37 + for (var i=1; i<inputs.length-1; i++) {
  38 + var obj = inputs[i];
  39 + obj.name = "boolean_search[subgroup]["+table_id+"][values]["+crit_id+"][data]["+obj.name+"]";
  40 + }
  41 +
  42 + for (var i=0; i<selects.length; i++) {
  43 + var obj = selects[i];
  44 + obj.name = "boolean_search[subgroup]["+table_id+"][values]["+crit_id+"][data]["+obj.name+"]";
  45 + }
  46 + }
  47 +
  48 +}
  49 +
  50 +
  51 +function processSavedSearch() {
  52 + var boolGroups = getElementsByTagAndClassName('TABLE','advanced-search-form');
  53 + for (var i=0; i<boolGroups.length; i++) {
  54 + var boolBody = boolGroups[i].getElementsByTagName('TBODY')[0]; // must be 1.
  55 + var boolRows = boolBody.getElementsByTagName('TR');
  56 + for (var j=0; j<boolRows.length; j++) {
  57 + processRow(boolRows[j], boolGroups[i]);
  58 + }
  59 + }
  60 +}
  61 +
  62 +addLoadEvent(processSavedSearch);
0 63 \ No newline at end of file
... ...
templates/ktcore/boolean_search_edit.smarty 0 โ†’ 100644
  1 +{$context->oPage->requireJSResource("thirdpartyjs/MochiKit/Base.js")}
  2 +{$context->oPage->requireJSResource("thirdpartyjs/MochiKit/DateTime.js")}
  3 +{$context->oPage->requireJSResource("thirdpartyjs/MochiKit/Iter.js")}
  4 +{$context->oPage->requireJSResource("thirdpartyjs/MochiKit/DOM.js")}
  5 +{$context->oPage->requireJSResource("thirdpartyjs/MochiKit/Async.js")}
  6 +{$context->oPage->requireJSResource("resources/js/taillog.js")}
  7 +{$context->oPage->requireJSResource("resources/js/constructed_search.js")}
  8 +{$context->oPage->requireJSResource("resources/js/constructed_search_postprocess.js")}
  9 +
  10 +{$context->oPage->requireJSResource("resources/js/kt3calendar.js")}
  11 +{$context->oPage->requireJSResource("thirdpartyjs/jscalendar-1.0/calendar.js")}
  12 +{$context->oPage->requireJSResource("thirdpartyjs/jscalendar-1.0/lang/calendar-en.js")}
  13 +{$context->oPage->requireJSResource("thirdpartyjs/jscalendar-1.0/calendar-setup.js")}
  14 +
  15 +{$context->oPage->requireCSSResource("thirdpartyjs/jscalendar-1.0/calendar-system.css")}
  16 +
  17 +{capture assign=sJS}
  18 +{literal}
  19 +function testStartup() {
  20 + simpleLog('INFO','Log initialised.');
  21 +}
  22 +
  23 +addLoadEvent(testStartup);
  24 +{/literal}
  25 +{/capture}
  26 +{$context->oPage->requireJSStandalone($sJS)}
  27 +
  28 +{capture assign=sCSS}
  29 +{literal}
  30 +fieldset { border: 1px dotted #999; }
  31 +legend { border: 1px dotted #999;}
  32 +
  33 +.helpText { color: #666; }
  34 +
  35 +/* logging support */
  36 +#brad-log thead th { border-bottom: 1px solid black; }
  37 +#brad-log {font-size: smaller; }
  38 +#brad-log .severity-INFO { color: blue; font-weight: bold; }
  39 +#brad-log .severity-DEBUG { color: green; font-weight: bold; }
  40 +#brad-log .severity-ERROR { color: red; font-weight: bold; }
  41 +#brad-log .explanation { font-family: monospace; white-space: pre; }
  42 +{/literal}
  43 +{/capture}
  44 +{$context->oPage->requireCSSStandalone($sCSS)}
  45 +
  46 +<!-- this is bad, but we really don't need a roundtrip -->
  47 +<div style="display: none" id="search-criteria-container">
  48 + <select name="querytype">
  49 + {foreach item=oCriteria from=$aCriteria}
  50 + <option value="{$oCriteria->getID()}">{$oCriteria->headerDisplay()}</option>
  51 + {/foreach}
  52 + </select>
  53 +</div>
  54 +
  55 +{capture assign=defaulttitle}
  56 +{i18n}Boolean Search{/i18n}
  57 +{/capture}
  58 +<h2>{$title|default:$defaulttitle}</h2>
  59 +
  60 +<form method="POST">
  61 + <input type="hidden" name="action" value="updateSearch" />
  62 + <input type="hidden" name="fSavedSearchId" value="{$iSearchId}" />
  63 +{if $sNameTitle}
  64 + {$sNameTitle}: <input type="text" name="name" value="{$old_name}" /> <br />
  65 +{/if}
  66 +
  67 +{capture assign=options}
  68 +<select name="boolean_search[join]"><option value="AND" {if ($aSearch.join == 'AND')} selected="true"{/if}>all</option><option value="OR" {if ($aSearch.join == 'OR')} selected="true"{/if}>any</option></select>
  69 +{/capture}
  70 +
  71 + <p class="helpText">{i18n arg_options=$options}Return items which match &nbsp;#options# of the <strong>criteria groups</strong> specified.{/i18n}</p>
  72 +
  73 + {foreach item=aSubgroup from=$aSearch.subgroup}
  74 +
  75 + <fieldset>
  76 + <legend>{i18n}Criteria Group{/i18n}</legend>
  77 +
  78 + {capture assign=options}
  79 + <select name="boolean_search[subgroup][0][join]"><option value="AND"{if ($aSubgroup.join == 'AND')} selected="true"{/if}>all</option><option value="OR"{if ($aSubgroup.join == 'OR')} selected="true"{/if}>any</option></select>
  80 + {/capture}
  81 +
  82 + <p class="helpText">{i18n arg_options=$options}Return items which match &nbsp;#options# of the criteria specified.{/i18n}</p>
  83 +
  84 + <table class="advanced-search-form">
  85 + <thead>
  86 + <tr>
  87 + <th>{i18n}Criteria{/i18n}</th>
  88 + <th>{i18n}Values{/i18n}</th>
  89 + <th>&nbsp;</th>
  90 + </tr>
  91 + </thead>
  92 +
  93 + <tbody>
  94 +
  95 + {foreach item=oSearchCriteria from=$aSubgroup.values}
  96 + <tr>
  97 + <td>
  98 + {$oSearchCriteria.typename} <input type="hidden" name="" value="{$oSearchCriteria.type}"/>
  99 + </td>
  100 + <td>
  101 + {$oSearchCriteria.widgetval}
  102 + </td>
  103 + <td>
  104 + <input type="button" value="Remove" onclick="removeCriteria(this)"/>
  105 + </td>
  106 + </tr>
  107 + {/foreach}
  108 +
  109 + <tr>
  110 + <td><select name="querytype">
  111 + {foreach item=oCriteria from=$aCriteria}
  112 + <option value="{$oCriteria->getID()}">{$oCriteria->headerDisplay()}</option>
  113 + {/foreach}
  114 + </select>
  115 + </td>
  116 + <td><p class="helpText">{i18n}first select a type of query{/i18n}</p></td>
  117 + <td><input type="button" value="{i18n}Add{/i18n}" onclick="addNewCriteria(this);" /></td>
  118 + </tr>
  119 + </tbody>
  120 + </table>
  121 +
  122 + </fieldset>
  123 +
  124 + {/foreach}
  125 +
  126 + <div class="form_actions">
  127 +
  128 + <input type="button" value="{i18n}add another set of criteria{/i18n}" onclick="addBooleanGroup(this)" />
  129 +
  130 +
  131 +{capture assign=defaultsubmit}
  132 +{i18n}Search{/i18n}
  133 +{/capture}
  134 + <input type="submit" name="submit" value="{$searchButton|default:$defaultsubmit}" />
  135 + </div>
  136 +</form>
  137 +
  138 +<!--
  139 +<table id="brad-log" width="100%">
  140 +<thead>
  141 + <tr>
  142 + <th width="10%">Severity</th>
  143 + <th width="10%">Time</th>
  144 + <th>Entry</th>
  145 + </tr>
  146 +</thead>
  147 +<tbody>
  148 +
  149 +</tbody>
  150 +</table>
  151 +-->
  152 +
... ...