Check-in [ca833ff86f]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added the /srchsetup page for configuring the /search screen.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ca833ff86f0a6a7e00477cf88fb88176f75c6fdb
User & Date: drh 2015-02-02 00:17:39.481
Context
2015-02-02
01:32
Add support for searching tickets. This is still a full-scan search. check-in: e2230a446b user: drh tags: trunk
00:17
Added the /srchsetup page for configuring the /search screen. check-in: ca833ff86f user: drh tags: trunk
2015-02-01
21:21
Minor refactoring and general cleanup of the "fossil setting" logic. check-in: 32f8da0ce7 user: drh tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/search.c.
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
static void search_stext_sqlfunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  Blob txt;
  const char *zType = (const char*)sqlite3_value_text(argv[0]);
  const char *zArg1 = (const char*)sqlite3_value_text(argv[1]);
  const char *zArg2 = (const char*)sqlite3_value_text(argv[2]);
  search_stext(zType[0], zArg1, zArg2, &txt);
  sqlite3_result_text(context, blob_materialize(&txt), -1, fossil_free);
}

/*
** Encode a string for use as a query parameter in a URL
*/
static void search_urlencode_sqlfunc(







|
|
|







422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
static void search_stext_sqlfunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  Blob txt;
  const char *zType = (const char*)sqlite3_value_text(argv[0]);
  int rid = sqlite3_value_int(argv[1]);
  const char *zName = (const char*)sqlite3_value_text(argv[2]);
  search_stext(zType[0], rid, zName, &txt);
  sqlite3_result_text(context, blob_materialize(&txt), -1, fossil_free);
}

/*
** Encode a string for use as a query parameter in a URL
*/
static void search_urlencode_sqlfunc(
554
555
556
557
558
559
560





561
562
563

564





565
566
567
568



569
570
571
572
573
574
575
576
577
578
579
580



581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596

597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
** Other pending enhancements:
**    *   Search tickets
**    *   Search wiki
*/
void search_page(void){
  const char *zPattern = PD("s","");
  Stmt q;





  const char *zSrchEnable = "dwc";

  login_check_credentials();

  if( !g.perm.Read ){ login_needed(); return; }





  style_header("Search");
  @ <form method="GET" action="search"><center>
  @ <input type="text" name="s" size="40" value="%h(zPattern)">
  @ <input type="submit" value="Search">



  @ </center></form>
  while( fossil_isspace(zPattern[0]) ) zPattern++;
  if( zPattern[0] ){
    search_sql_setup(g.db);
    add_content_sql_commands(g.db);
    search_init(zPattern, "<b>", "</b>", " ... ",
            SRCHFLG_STATIC|SRCHFLG_HTML|SRCHFLG_SCORE);
    db_multi_exec(
      "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
      "CREATE TEMP TABLE x(label TEXT,url TEXT,date TEXT,snip TEXT);"
    );
    if( strchr(zSrchEnable, 'd') ){



      db_multi_exec(
        "INSERT INTO x(label,url,date,snip)"
        "  SELECT printf('Document: %%s',foci.filename),"
        "         printf('%R/doc/trunk/%%s',foci.filename),"
        "         (SELECT datetime(event.mtime) FROM event"
        "            WHERE objid=symbolic_name_to_rid('trunk')),"
        "         snippet(stext('d',blob.rid,foci.filename))"
        "    FROM foci CROSS JOIN blob"
        "   WHERE checkinID=symbolic_name_to_rid('trunk')"
        "     AND blob.uuid=foci.uuid"
        "     AND (filename GLOB '*.wiki' OR"
        "          filename GLOB '*.md' OR"
        "          filename GLOB '*.txt' OR"
        "          filename GLOB '*.html');"
      );
    }

    if( strchr(zSrchEnable, 'w') ){
      db_multi_exec(
        "WITH wiki(name,rid,mtime) AS ("
        "  SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
        "    FROM tag, tagxref"
        "   WHERE tag.tagname GLOB 'wiki-*'"
        "     AND tagxref.tagid=tag.tagid"
        "   GROUP BY 1"
        ")"
        "INSERT INTO x(label,url,date,snip)"
        "  SELECT printf('Wiki: %%s',name),"
        "         printf('%R/wiki?name=%%s',urlencode(name)),"
        "         datetime(mtime),"
        "         snippet(stext('w',rid,name))"
        "    FROM wiki;"
      );
    }
    if( strchr(zSrchEnable, 'c') ){
      db_multi_exec(
        "WITH ckin(uuid,rid,mtime) AS ("
        "  SELECT blob.uuid, event.objid, event.mtime"
        "    FROM event, blob"
        "   WHERE event.type='ci'"
        "     AND blob.rid=event.objid"
        ")"
        "INSERT INTO x(label,url,date,snip)"
        "  SELECT printf('Check-in [%%.10s] on %%s',uuid,datetime(mtime)),"
        "         printf('%R/timeline?c=%%s&n=8&y=ci',uuid),"
        "         datetime(mtime),"
        "         snippet(stext('c',rid,NULL))"
        "    FROM ckin;"
      );
    }
    db_prepare(&q, "SELECT url, substr(snip,9), label"
                   "   FROM x WHERE snip IS NOT NULL"
                   " ORDER BY substr(snip,1,9) DESC, date DESC;");
    @ <ol>
    while( db_step(&q)==SQLITE_ROW ){
      const char *zUrl = db_column_text(&q, 0);
      const char *zSnippet = db_column_text(&q, 1);
      const char *zLabel = db_column_text(&q, 2);
      @ <li><p>%s(href("%s",zUrl))%h(zLabel)</a><br>%s(zSnippet)</li>
    }







>
>
>
>
>
|


>
|
>
>
>
>
>


|
|
>
>
>











|
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
<
<
|
|
>
|
















|

















|







554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609


610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
** Other pending enhancements:
**    *   Search tickets
**    *   Search wiki
*/
void search_page(void){
  const char *zPattern = PD("s","");
  Stmt q;
  int okCheckin;
  int okDoc;
  int okTicket;
  int okWiki;
  int allOff;
  const char *zDisable;

  login_check_credentials();
  okCheckin = g.perm.Read && db_get_boolean("search-ci",0);
  okDoc = g.perm.Read && db_get_boolean("search-doc",0);
  okTicket = g.perm.RdTkt && db_get_boolean("search-tkt",0);
  okWiki = g.perm.RdWiki && db_get_boolean("search-wiki",0);
  allOff = (okCheckin + okDoc + okTicket + okWiki == 0);
  zDisable = allOff ? " disabled" : "";
  zPattern = allOff ? "" : PD("s","");
  style_header("Search");
  @ <form method="GET" action="search"><center>
  @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable)>
  @ <input type="submit" value="Search"%s(zDisable)>
  if( allOff ){
    @ <p class="generalError">Search is disabled</p>
  }
  @ </center></form>
  while( fossil_isspace(zPattern[0]) ) zPattern++;
  if( zPattern[0] ){
    search_sql_setup(g.db);
    add_content_sql_commands(g.db);
    search_init(zPattern, "<b>", "</b>", " ... ",
            SRCHFLG_STATIC|SRCHFLG_HTML|SRCHFLG_SCORE);
    db_multi_exec(
      "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
      "CREATE TEMP TABLE x(label TEXT,url TEXT,date TEXT,snip TEXT);"
    );
    if( okDoc ){
      char *zDocGlob = db_get("doc-glob","");
      char *zDocBr = db_get("doc-branch","trunk");
      if( zDocGlob && zDocGlob[0] && zDocBr && zDocBr[0] ){
        db_multi_exec(
          "INSERT INTO x(label,url,date,snip)"
          "  SELECT printf('Document: %%s',foci.filename),"
          "         printf('%R/doc/%T/%%s',foci.filename),"
          "         (SELECT datetime(event.mtime) FROM event"
          "            WHERE objid=symbolic_name_to_rid('trunk')),"
          "         snippet(stext('d',blob.rid,foci.filename))"
          "    FROM foci CROSS JOIN blob"
          "   WHERE checkinID=symbolic_name_to_rid('trunk')"
          "     AND blob.uuid=foci.uuid"
          "     AND %z",
          zDocBr, glob_expr("foci.filename", zDocGlob)


        );
      }
    }
    if( okWiki ){
      db_multi_exec(
        "WITH wiki(name,rid,mtime) AS ("
        "  SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
        "    FROM tag, tagxref"
        "   WHERE tag.tagname GLOB 'wiki-*'"
        "     AND tagxref.tagid=tag.tagid"
        "   GROUP BY 1"
        ")"
        "INSERT INTO x(label,url,date,snip)"
        "  SELECT printf('Wiki: %%s',name),"
        "         printf('%R/wiki?name=%%s',urlencode(name)),"
        "         datetime(mtime),"
        "         snippet(stext('w',rid,name))"
        "    FROM wiki;"
      );
    }
    if( okCheckin ){
      db_multi_exec(
        "WITH ckin(uuid,rid,mtime) AS ("
        "  SELECT blob.uuid, event.objid, event.mtime"
        "    FROM event, blob"
        "   WHERE event.type='ci'"
        "     AND blob.rid=event.objid"
        ")"
        "INSERT INTO x(label,url,date,snip)"
        "  SELECT printf('Check-in [%%.10s] on %%s',uuid,datetime(mtime)),"
        "         printf('%R/timeline?c=%%s&n=8&y=ci',uuid),"
        "         datetime(mtime),"
        "         snippet(stext('c',rid,NULL))"
        "    FROM ckin;"
      );
    }
    db_prepare(&q, "SELECT url, substr(snip,9), label"
                   "   FROM x WHERE snip IS NOT NULL"
                   " ORDER BY substr(snip,1,8) DESC, date DESC;");
    @ <ol>
    while( db_step(&q)==SQLITE_ROW ){
      const char *zUrl = db_column_text(&q, 0);
      const char *zSnippet = db_column_text(&q, 1);
      const char *zLabel = db_column_text(&q, 2);
      @ <li><p>%s(href("%s",zUrl))%h(zLabel)</a><br>%s(zSnippet)</li>
    }
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
}

/*
** Return "search text" - a reduced version of a document appropriate for
** full text search and/or for constructing a search result snippet.
**
**    cType:            d      Embedded documentation
**                      s      Source code listing
**                      w      Wiki page
**                      c      Check-in comment
**                      t      Ticket text
**                      e      Event/Blog text
**                      k      Diff of a wiki
**                      f      Diff of a checkin
**
**   zArg1, zArg2:      Description of the document, depending on cType.
*/
void search_stext(
  char cType,            /* Type of document */
  const char *zArg1,     /* First parameter */
  const char *zArg2,     /* Second parameter */
  Blob *pOut             /* OUT: Initialize to the search text */
){
  blob_init(pOut, 0, 0);
  switch( cType ){
    case 'd':     /* Doc.     zArg1: RID of the file.  zArg2: Filename */
    case 's': {   /* Source.  zArg1: RID of the file.  zArg2: Filename */
      int rid = atoi(zArg1);
      Blob doc;
      content_get(rid, &doc);
      blob_to_utf8_no_bom(&doc, 0);
      get_stext_by_mimetype(&doc, mimetype_from_name(zArg2), pOut);
      blob_reset(&doc);
      break;
    }
    case 'w': {   /* Wiki.    zArg1: RID of the page.  zArg2: Page name */
      int rid = atoi(zArg1);
      Manifest *pWiki = manifest_get(rid, CFTYPE_WIKI,0);
      Blob wiki;
      if( pWiki==0 ) break;
      blob_init(&wiki, pWiki->zWiki, -1);
      get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
                            pOut);
      blob_reset(&wiki);
      manifest_destroy(pWiki);
      break;
    }
    case 'c': {   /* Ckeckin:  zArg1: RID of the checkin.  zArg2: Not used */
      int rid = atoi(zArg1);
      static Stmt q;
      db_static_prepare(&q,
         "SELECT coalesce(ecomment,comment)"
         "  ||' (user: '||coalesce(euser,user,'?')"
         "  ||', tags: '||"
         "  (SELECT group_concat(substr(tag.tagname,5),',')"
         "     FROM tag, tagxref"







<



|
|
|

|



|
|




|
<
<



|



|
<










|
<







690
691
692
693
694
695
696

697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714


715
716
717
718
719
720
721
722

723
724
725
726
727
728
729
730
731
732
733

734
735
736
737
738
739
740
}

/*
** Return "search text" - a reduced version of a document appropriate for
** full text search and/or for constructing a search result snippet.
**
**    cType:            d      Embedded documentation

**                      w      Wiki page
**                      c      Check-in comment
**                      t      Ticket text
**
**    rid               The RID of an artifact that defines the object
**                      being searched.
**
**    zName             Name of the object being searched.
*/
void search_stext(
  char cType,            /* Type of document */
  int rid,               /* BLOB.RID or TAG.TAGID value for document */
  const char *zName,     /* Name of the document */
  Blob *pOut             /* OUT: Initialize to the search text */
){
  blob_init(pOut, 0, 0);
  switch( cType ){
    case 'd': {   /* Documents */


      Blob doc;
      content_get(rid, &doc);
      blob_to_utf8_no_bom(&doc, 0);
      get_stext_by_mimetype(&doc, mimetype_from_name(zName), pOut);
      blob_reset(&doc);
      break;
    }
    case 'w': {   /* Wiki */

      Manifest *pWiki = manifest_get(rid, CFTYPE_WIKI,0);
      Blob wiki;
      if( pWiki==0 ) break;
      blob_init(&wiki, pWiki->zWiki, -1);
      get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
                            pOut);
      blob_reset(&wiki);
      manifest_destroy(pWiki);
      break;
    }
    case 'c': {   /* Ckeck-in Comments */

      static Stmt q;
      db_static_prepare(&q,
         "SELECT coalesce(ecomment,comment)"
         "  ||' (user: '||coalesce(euser,user,'?')"
         "  ||', tags: '||"
         "  (SELECT group_concat(substr(tag.tagname,5),',')"
         "     FROM tag, tagxref"
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
      db_reset(&q);
      break;
    }
  }
}

/*
** The arguments cType,zArg1,zArg2 define an object that can be searched
** for.  Return a URL (relative to the root of the Fossil project) that
** will jump to that document.  
**
** Space to hold the returned string is obtained from mprintf() and should
** be freed by the caller using fossil_free() or the equivalent.
*/
char *search_url(
  char cType,            /* Type of document */
  const char *zArg1,     /* First parameter */
  const char *zArg2      /* Second parameter */
){
  char *zUrl = 0;
  switch( cType ){
    case 'd': {   /* Doc.     zArg1: RID of the file.  zArg2: Filename */
    case 's':     /* Source.  zArg1: RID of the file.  zArg2: Filename */
      zUrl = db_text(0,
         "SELECT printf('/doc/%%s%%s', substr(blob.uuid,20), %Q)"
         "  FROM mlink, blob"
         " WHERE mlink.fid=%d AND mlink.mid=blob.rid",
         zArg2, atoi(zArg1));
      break;
    }
    case 'w': {   /* Wiki.    zArg1: RID of the page.  zArg2: Page name */
      char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",atoi(zArg1));
      zUrl = mprintf("/wiki?id=%z&name=%t", zId, zArg2);
      break;
    }     
    case 'c': {   /* Ckeckin:  zArg1: RID of the checkin.  zArg2: Not used */
      char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",atoi(zArg1));
      zUrl = mprintf("/info/%z", zId);
      break;
    }
  }
  return zUrl;
}	

/*
** COMMAND: test-search-stext
**
** Usage: fossil test-search-stext TYPE ARG1 ARG2
*/
void test_search_stext(void){
  Blob out;
  char *zUrl;
  db_find_and_open_repository(0,0);
  if( g.argc!=5 ) usage("TYPE ARG1 ARG2");
  search_stext(g.argv[2][0], g.argv[3], g.argv[4], &out);
  zUrl = search_url(g.argv[2][0], g.argv[3], g.argv[4]);
  fossil_print("%s\n%z\n",blob_str(&out),zUrl);
  blob_reset(&out);
}







|








|
|



|
<




|


|
|
|


|
|





|










|
|
|



750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771

772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
      db_reset(&q);
      break;
    }
  }
}

/*
** The arguments cType,rid,zName define an object that can be searched
** for.  Return a URL (relative to the root of the Fossil project) that
** will jump to that document.  
**
** Space to hold the returned string is obtained from mprintf() and should
** be freed by the caller using fossil_free() or the equivalent.
*/
char *search_url(
  char cType,            /* Type of document */
  int rid,               /* BLOB.RID or TAG.TAGID for the object */
  const char *zName      /* Name of the object */
){
  char *zUrl = 0;
  switch( cType ){
    case 'd': {   /* Documents */

      zUrl = db_text(0,
         "SELECT printf('/doc/%%s%%s', substr(blob.uuid,20), %Q)"
         "  FROM mlink, blob"
         " WHERE mlink.fid=%d AND mlink.mid=blob.rid",
         zName, rid);
      break;
    }
    case 'w': {   /* Wiki */
      char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
      zUrl = mprintf("/wiki?id=%z&name=%t", zId, zName);
      break;
    }     
    case 'c': {   /* Ckeck-in Comment */
      char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
      zUrl = mprintf("/info/%z", zId);
      break;
    }
  }
  return zUrl;
}

/*
** COMMAND: test-search-stext
**
** Usage: fossil test-search-stext TYPE ARG1 ARG2
*/
void test_search_stext(void){
  Blob out;
  char *zUrl;
  db_find_and_open_repository(0,0);
  if( g.argc!=5 ) usage("TYPE RID NAME");
  search_stext(g.argv[2][0], atoi(g.argv[3]), g.argv[4], &out);
  zUrl = search_url(g.argv[2][0], atoi(g.argv[3]), g.argv[4]);
  fossil_print("%s\n%z\n",blob_str(&out),zUrl);
  blob_reset(&out);
}
Changes to src/setup.c.
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90


91
92
93
94
95
96
97
  ** if it does not. */
  if( !cgi_header_contains("<base href=") ){
    @ <p class="generalError"><b>Configuration Error:</b> Please add
    @ <tt>&lt;base href="$secureurl/$current_page"&gt;</tt> after
    @ <tt>&lt;head&gt;</tt> in the <a href="setup_header">HTML header</a>!</p>
  }

  @ <table border="0" cellspacing="7">
  setup_menu_entry("Users", "setup_ulist",
    "Grant privileges to individual users.");
  setup_menu_entry("Access", "setup_access",
    "Control access settings.");
  setup_menu_entry("Configuration", "setup_config",
    "Configure the WWW components of the repository");
  setup_menu_entry("Settings", "setup_settings",
    "Web interface to the \"fossil settings\" command");
  setup_menu_entry("Timeline", "setup_timeline",
    "Timeline display preferences");
  setup_menu_entry("Login-Group", "setup_login_group",
    "Manage single sign-on between this repository and others"
    " on the same server");
  setup_menu_entry("Tickets", "tktsetup",
    "Configure the trouble-ticketing system for this repository");


  setup_menu_entry("Transfers", "xfersetup",
    "Configure the transfer system for this repository");
  setup_menu_entry("Skins", "setup_skin",
    "Select from a menu of prepackaged \"skins\" for the web interface");
  setup_menu_entry("CSS", "setup_editcss",
    "Edit the Cascading Style Sheet used by all pages of this repository");
  setup_menu_entry("Header", "setup_header",







|















>
>







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  ** if it does not. */
  if( !cgi_header_contains("<base href=") ){
    @ <p class="generalError"><b>Configuration Error:</b> Please add
    @ <tt>&lt;base href="$secureurl/$current_page"&gt;</tt> after
    @ <tt>&lt;head&gt;</tt> in the <a href="setup_header">HTML header</a>!</p>
  }

  @ <table border="0" cellspacing="3">
  setup_menu_entry("Users", "setup_ulist",
    "Grant privileges to individual users.");
  setup_menu_entry("Access", "setup_access",
    "Control access settings.");
  setup_menu_entry("Configuration", "setup_config",
    "Configure the WWW components of the repository");
  setup_menu_entry("Settings", "setup_settings",
    "Web interface to the \"fossil settings\" command");
  setup_menu_entry("Timeline", "setup_timeline",
    "Timeline display preferences");
  setup_menu_entry("Login-Group", "setup_login_group",
    "Manage single sign-on between this repository and others"
    " on the same server");
  setup_menu_entry("Tickets", "tktsetup",
    "Configure the trouble-ticketing system for this repository");
  setup_menu_entry("Search","srchsetup",
    "Configure the built-in search engine");
  setup_menu_entry("Transfers", "xfersetup",
    "Configure the transfer system for this repository");
  setup_menu_entry("Skins", "setup_skin",
    "Select from a menu of prepackaged \"skins\" for the web interface");
  setup_menu_entry("CSS", "setup_editcss",
    "Edit the Cascading Style Sheet used by all pages of this repository");
  setup_menu_entry("Header", "setup_header",
2153
2154
2155
2156
2157
2158
2159




















































  }
  @ </tbody></table>
  if(limit>0 && counter<limit){
    @ <div>%d(counter) entries shown.</div>
  }
  style_footer();
}



























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
  }
  @ </tbody></table>
  if(limit>0 && counter<limit){
    @ <div>%d(counter) entries shown.</div>
  }
  style_footer();
}

/*
** WEBPAGE: srchsetup
**
** Configure the search engine.
*/
void page_srchsetup(){
  login_check_credentials();
  if( !g.perm.Setup && !g.perm.Admin ){
    login_needed();
  }
  style_header("Search Configuration");
  @ <form action="%s(g.zTop)/srchsetup" method="post"><div>
  login_insert_csrf_secret();
  @ <div style="text-align:center;font-weight:bold;">
  @ Server-specific settings that affect the 
  @ <a href="%R/help?cmd=/search">/search</a> webpage.
  @ </div>
  @ <hr />
  textarea_attribute("Document Glob List", 3, 35, "doc-glob", "dg", "", 0);
  @ <p>The "Document Glob List" is a comma- or newline-separated list 
  @ of GLOB expressions that identify all documents within the source
  @ tree that are to be searched when "Document Search" is enabled.
  @ Some examples:
  @ <table border=0 cellpadding=2 align=center>
  @ <tr><td>*.wiki,*.html,*.md,*.txt<td style="width: 4x;">
  @ <td>Search all wiki, HTML, Markdown, and Text files</tr>
  @ <tr><td>doc/*.md,*/README.txt,README.txt<td>
  @ <td>Search all Markdown files in the doc/ subfolder and all README.txt
  @ files.</tr>
  @ <tr><td>*<td><td>Search all checked-in files</tr>
  @ <tr><td><i>(blank)</i><td>
  @ <td>Search nothing. (Disables document search).</tr>
  @ </table>
  @ <hr />
  entry_attribute("Document Branch", 20, "doc-branch", "db", "trunk", 0);
  @ <p>When searching documents, use the versions of the files found at the
  @ type of the "Document Branch" branch.  Recommended value: "trunk".
  @ Document search is disabled if blank.
  @ <hr/>
  onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0);
  @ <br>
  onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
  @ <br>
  onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
  @ <br>
  onoff_attribute("Search Wiki","search-wiki", "sw", 0, 0);
  @ <hr/>
  @ <p><input type="submit"  name="submit" value="Apply Changes" /></p>
  @ </div></form>
  style_footer();
}