Overview
SHA1 Hash: | ffe92f1a2f103efe35fa61d108a5ef060a50861e |
---|---|
Date: | 2008-02-13 19:50:27 |
User: | drh |
Comment: | The entire header, including the menu bar, is now generated by TH script. This allows the menu bar to be customized by editing the header script. |
Timelines: | ancestors | descendants | both | trunk |
Other Links: | files | ZIP archive | manifest |
Tags And Properties
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
Changes
[hide diffs]Modified src/style.c from [efdb67a174] to [da3e8aee87].
@@ -72,11 +72,10 @@ /* ** Draw the header. */ void style_header(const char *zTitle){ - const char *zLogInOut = "Login"; const char *zHeader = db_get("header", (char*)zDefaultHeader); login_check_credentials(); cgi_destination(CGI_HEADER); @@ -86,40 +85,12 @@ Th_InitVar("baseurl", g.zBaseURL); Th_InitVar("manifest_version", MANIFEST_VERSION); Th_InitVar("manifest_date", MANIFEST_DATE); if( g.zLogin ){ Th_InitVar("login", g.zLogin); - zLogInOut = "Logout"; } Th_Render(zHeader); - - /* Generate the main menu */ - @ <div class="mainmenu"> - @ <a href="%s(g.zBaseURL)/home">Home</a> - if( g.okHistory ){ - @ <a href="%s(g.zBaseURL)/dir">Files</a> - } - if( g.okRead ){ - @ <a href="%s(g.zBaseURL)/leaves">Leaves</a> - @ <a href="%s(g.zBaseURL)/timeline">Timeline</a> - @ <a href="%s(g.zBaseURL)/tagview">Tags</a> - } - if( g.okRdWiki ){ - @ <a href="%s(g.zBaseURL)/wiki">Wiki</a> - } -#if 0 - @ <font color="#888888">Search</font> - @ <font color="#888888">Ticket</font> - @ <font color="#888888">Reports</font> -#endif - if( g.okSetup ){ - @ <a href="%s(g.zBaseURL)/setup">Setup</a> - } - if( !g.noPswd ){ - @ <a href="%s(g.zBaseURL)/login">%s(zLogInOut)</a> - } - @ </div> cgi_destination(CGI_BODY); g.cgiPanic = 1; } /* @@ -162,31 +133,53 @@ ** The default page header. */ const char zDefaultHeader[] = @ <html> @ <head> -@ <title><th1>puts "$project_name: $title"</th1></title> +@ <title>$<project_name>: $<title></title> @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" @ href="$baseurl/timeline.rss"> @ <link rel="stylesheet" href="$baseurl/style.css" type="text/css" @ media="screen"> @ </head> @ <body> @ <div class="header"> @ <div class="logo"> @ <!-- <img src="logo.gif" alt="logo"><br></br> --> -@ <nobr><th1>puts $project_name</th1></nobr> +@ <nobr>$<project_name></nobr> @ </div> -@ <div class="title"><th1>puts $title</th1></div> +@ <div class="title">$<title></div> @ <div class="status"><nobr><th1> @ if {[info exists login]} { @ html "Logged in as <a href='$baseurl/my'>$login</a>" @ } else { @ puts "Not logged in" @ } @ </th1></nobr></div> @ </div> +@ <div class="mainmenu"><th1> +@ html "<a href='$baseurl/home'>Home</a>" +@ if {[hascap h]} { +@ html "<a href='$baseurl/dir'>Files</a>" +@ } +@ if {[hascap i]} { +@ html "<a href='$baseurl/leaves'>Leaves</a>" +@ html "<a href='$baseurl/timeline'>Timeline</a>" +@ html "<a href='$baseurl/tagview'>Tags</a>" +@ } +@ if {[hascap j]} { +@ html "<a href='$baseurl/wiki'>Wiki</a>" +@ } +@ if {[hascap s]} { +@ html "<a href='$baseurl/setup'>Setup</a>" +@ } +@ if {[info exists login]} { +@ html "<a href='$baseurl/login'>Login</a>" +@ } else { +@ html "<a href='$baseurl/login'>Logout</a>" +@ } +@ </th1></div> ; /* ** The default page footer */
Modified src/th_main.c from [7f63a6f888] to [9966e4d470].
@@ -84,18 +84,23 @@ /* ** Send text to the appropriate output: Either to the console ** or to the CGI reply buffer. */ -static void sendText(const char *z, int n){ +static void sendText(const char *z, int n, int encode){ if( enableOutput && n ){ if( n<0 ) n = strlen(z); + if( encode ){ + z = htmlize(z, n); + n = strlen(z); + } if( g.cgiPanic ){ cgi_append_content(z, n); }else{ fwrite(z, 1, n, stdout); } + if( encode ) free((char*)z); } } /* ** TH command: puts STRING @@ -111,25 +116,11 @@ int *argl ){ if( argc!=2 ){ return Th_WrongNumArgs(interp, "puts STRING"); } - if( enableOutput ){ - int size; - char *zOut; - if( pConvert ){ - zOut = htmlize((char*)argv[1], argl[1]); - size = strlen(zOut); - }else{ - zOut = (char*)argv[1]; - size = argl[1]; - } - sendText(zOut, size); - if( pConvert ){ - free(zOut); - } - } + sendText((char*)argv[1], argl[1], pConvert!=0); return TH_OK; } /* ** TH command: wiki STRING @@ -142,18 +133,37 @@ int argc, const unsigned char **argv, int *argl ){ if( argc!=2 ){ - return Th_WrongNumArgs(interp, "puts STRING"); + return Th_WrongNumArgs(interp, "wiki STRING"); } if( enableOutput ){ Blob src; blob_init(&src, (char*)argv[1], argl[1]); wiki_convert(&src, 0, WIKI_INLINE); blob_reset(&src); } + return TH_OK; +} + +/* +** TH command: hascap STRING +** +** Return true if the user has all of the capabilities listed in STRING. +*/ +static int hascapCmd( + Th_Interp *interp, + void *p, + int argc, + const unsigned char **argv, + int *argl +){ + if( argc!=2 ){ + return Th_WrongNumArgs(interp, "hascap STRING"); + } + Th_SetResultInt(interp, login_has_capability((char*)argv[1],argl[1])); return TH_OK; } /* ** Make sure the interpreter has been initialized. @@ -163,10 +173,11 @@ const char *zName; Th_CommandProc xProc; void *pContext; } aCommand[] = { {"enable_output", enableOutputCmd, 0}, + {"hascap", hascapCmd, 0}, {"html", putsCmd, 0}, {"puts", putsCmd, (void*)1}, {"wiki", wikiCmd, 0}, }; if( interp==0 ){ @@ -183,11 +194,11 @@ /* ** Initialize a variable in the interpreter. */ void Th_InitVar(const char *zName, const char *zValue){ initializeInterp(); - Th_SetVar(interp, zName, -1, zValue, strlen(zValue)); + Th_SetVar(interp, (uchar*)zName, -1, (uchar*)zValue, strlen(zValue)); } /* ** Return true if the string begins with the TH1 begin-script ** tag: <th1>. @@ -217,48 +228,72 @@ ** If string z[0...] contains a valid variable name, return ** the number of characters in that name. Otherwise, return 0. */ static int validVarName(const char *z){ int i = 0; + int inBracket = 0; + if( z[0]=='<' ){ + inBracket = 1; + z++; + } if( z[0]==':' && z[1]==':' && isalpha(z[2]) ){ z += 3; - i = 3; + i += 3; }else if( isalpha(z[0]) ){ z ++; - i = 1; + i += 1; }else{ return 0; } while( isalnum(z[0]) || z[0]=='_' ){ z++; i++; } + if( inBracket ){ + if( z[0]!='>' ) return 0; + i += 2; + } return i; } /* ** The z[] input contains text mixed with TH1 scripts. -** The TH1 scripts are contained within <th1>...</th1>. This routine -** processes the template and writes the results on either -** stdout or into CGI. +** The TH1 scripts are contained within <th1>...</th1>. +** TH1 variables are $aaa or $<aaa>. The first form of +** variable is literal. The second is run through htmlize +** before being inserted. +** +** This routine processes the template and writes the results +** on either stdout or into CGI. */ int Th_Render(const char *z){ int i = 0; int n; int rc = TH_OK; uchar *zResult; initializeInterp(); while( z[i] ){ if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){ - sendText(z, i); - rc = Th_GetVar(interp, &z[i+1], n); + const char *zVar; + int nVar; + sendText(z, i, 0); + if( z[i+1]=='<' ){ + /* Variables of the form $<aaa> */ + zVar = &z[i+2]; + nVar = n-2; + }else{ + /* Variables of the form $aaa */ + zVar = &z[i+1]; + nVar = n; + } + rc = Th_GetVar(interp, (uchar*)zVar, nVar); z += i+1+n; i = 0; - zResult = Th_GetResult(interp, &n); - sendText(zResult, n); + zResult = (uchar*)Th_GetResult(interp, &n); + sendText((char*)zResult, n, n>nVar); }else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){ - sendText(z, i); + sendText(z, i, 0); z += i+5; for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){} rc = Th_Eval(interp, 0, (const uchar*)z, i); if( rc!=SBS_OK ) break; z += i; @@ -267,16 +302,16 @@ }else{ i++; } } if( rc==TH_ERROR ){ - sendText("<hr><p><font color=\"red\"><b>ERROR: ", -1); - zResult = Th_GetResult(interp, &n); - sendText(zResult, n); - sendText("</b></font></p>", -1); + sendText("<hr><p><font color=\"red\"><b>ERROR: ", -1, 0); + zResult = (uchar*)Th_GetResult(interp, &n); + sendText((char*)zResult, n, 1); + sendText("</b></font></p>", -1, 0); }else{ - sendText(z, i); + sendText(z, i, 0); } return rc; } /*
Modified src/tktconfig.c from [c567cf64e8] to [60a45e0840].
@@ -33,60 +33,12 @@ ** There is considerable flexibility in how tickets are defined ** in fossil. Each repository can define its own ticket setup ** differently. Each repository has an instance of a file, like ** this one that defines how that repository deals with tickets. ** -** This file is in the form of a script in an exceedingly -** minimalist scripting language called "subscript". Here are -** the rules: -** -** SYNTAX -** -** * The script consists of a sequence of whitespace -** separated tokens. Whitespace is ignored, except -** as its role as a token separator. -** -** * Lines that begin with '#' are considered to be whitespace. -** -** * Text within matching {...} is consider to be a single "string" -** token, even if the text spans multiple lines and includes -** embedded whitespace. The outermost {...} are not part of -** the text of the token. -** -** * A token that begins with "/" is a string token. -** -** * A token that looks like a number is a string token. -** -** * Tokens that do not fall under the previous three rules -** are "verb" tokens. -** -** PROCESSING: -** -** * When a script is processed, the engine reads tokens -** one by one. -** -** * String tokens are pushed onto the stack. -** -** * Verb tokens which correspond to the names of variables -** cause the corresponding variable to be pushed onto the -** stack. -** -** * Verb tokens which correspond to procedures cause the -** procedures to run. The procedures might push or pull -** values from the stack. -** -** There are just a handful of verbs. For the purposes of this -** configuration script, there is only a single verb: "set". The -** "set" verb pops two arguments from the stack. The topmost is -** the name of a variable. The second element is the value. The -** "set" verb sets the value of the named variable. -** -** VALUE NAME set -** -** This configuration file just sets the values of various variables. -** Some of the variables have special meanings. The content of some -** of the variables are additional subscript scripts. +** This file is in the form of a script in TH1 - a minimalist +** TCL clone. */ /* @-comment: ** */ const char zDefaultTicketConfig[] = @ ############################################################################ @@ -95,11 +47,11 @@ @ # tkt_id, tkt_uuid, and tkt_mtime. tkt_id must be the integer primary @ # key and tkt_uuid and tkt_mtime must be unique. A configuration should @ # define addition columns as necessary. All columns should be in all @ # lower-case letters and should not begin with "tkt". @ # -@ { +@ set ticket_sql { @ CREATE TABLE ticket( @ -- Do not change any column that begins with tkt_ @ tkt_id INTEGER PRIMARY KEY, @ tkt_uuid TEXT, @ tkt_mtime DATE, @@ -115,26 +67,26 @@ @ comment TEXT, @ -- Do not alter this UNIQUE clause: @ UNIQUE(tkt_uuid, tkt_mtime) @ ); @ -- Add indices as desired -@ } /ticket_sql set +@ } @ @ ############################################################################ @ # You can define additional variables here. These variables will be @ # accessible to the page templates when they run. @ # -@ { +@ set type_choices { @ Code_Defect @ Build_Problem @ Documentation @ Feature_Request @ Incident -@ } /type_choices set -@ {Immediate High Medium Low Zero} /priority_choices set -@ {Critical Severe Important Minor Cosmetic} /severity_choices set -@ { +@ } +@ set priority_choices {Immediate High Medium Low Zero} +@ set severity_choices {Critical Severe Important Minor Cosmetic} +@ set resolution_choices { @ Open @ Fixed @ Rejected @ Unable_To_Reproduce @ Works_As_Designed @@ -141,68 +93,70 @@ @ External_Bug @ Not_A_Bug @ Duplicate @ Overcome_By_Events @ Drive_By_Patch -@ } /resolution_choices set -@ { +@ } +@ set status_choices { @ Open @ Verified @ In_Process @ Deferred @ Fixed @ Tested @ Closed -@ } /status_choices set -@ {one two three} /subsystem_choices set +@ } +@ set subsystem_choices {one two three} @ @ ########################################################################## @ # The "tktnew_template" variable is set to text which is a template for @ # the HTML of the "New Ticket" page. Within this template, text contained @ # within [...] is subscript. That subscript runs when the page is @ # rendered. @ # -@ { +@ set tktnew_template { @ <!-- load database field names not found in CGI with an empty string --> @ <!-- start a form --> -@ [{ -@ {Open} /status set -@ submit_ticket -@ } /submit exists if] +@ <th1> +@ if {[info exists submit]} { +@ set status Open +@ submit_ticket +@ } +@ </th1> @ <table cellpadding="5"> @ <tr> @ <td colspan="2"> @ Enter a one-line summary of the problem:<br> -@ <input type="text" name="title" size="60" value="[{} /title get html]"> +@ <input type="text" name="title" size="60" value="$<title>"> @ </td> @ </tr> @ @ <tr> @ <td align="right">Type: -@ [/type type_choices 1 combobox] +@ <th1>combobox type $type_choices 1</th1> @ </td> @ <td>What type of ticket is this?</td> @ </tr> @ @ <tr> @ <td align="right">Version: -@ <input type="text" name="foundin" size="20" value="[{} /foundin get html]"> +@ <input type="text" name="foundin" size="20" value="$<foundin>"> @ </td> @ <td>In what version or build number do you observer the problem?</td> @ </tr> @ @ <tr> @ <td align="right">Severity: -@ [/severity severity_choices 1 combobox] +@ <th1>comboboxy severity severity_choices 1</th1> @ </td> @ <td>How debilitating is the problem? How badly does the problem @ effect the operation of the product?</td> @ </tr> @ @ <tr> @ <td align="right">EMail: -@ <input type="text" name="contact" value="[{} /contact get html]" size="30"> +@ <input type="text" name="contact" value="$<contact>" size="30"> @ </td> @ <td>Not publically visible. Used by developers to contact you with @ questions.</td> @ </tr> @ @@ -211,23 +165,30 @@ @ Enter a detailed description of the problem. @ For code defects, be sure to provide details on exactly how @ the problem can be reproduced. Provide as much detail as @ possible. @ <br> -@ <textarea name="comment" cols="80" -@ rows="[{} /comment get linecount 50 max 10 min html]" -@ wrap="virtual" class="wikiedit">[{} /comment get html]</textarea><br> +@ <th1> +@ if {![info exists comment]} { +@ set nline 10 +@ } else { +@ set nline [linecount $comment] +@ if {$nline>50} {set nline 50} +@ } +@ </th1> +@ <textarea name="comment" cols="80" rows="$nline" +@ wrap="virtual" class="wikiedit">$<comment></textarea><br> @ <input type="submit" name="preview" value="Preview"> @ </tr> @ -@ [/preview exists enable_output] +@ <th1>enable_output [info exists preview]</th1> @ <tr><td colspan="2"> @ Description Preview:<br><hr> -@ [{} /comment get wiki] +@ <th1>wiki $comment</th1> @ <hr> @ </td></tr> -@ [1 enable_output] +@ <th1>enable_output 1</th1> @ @ <tr> @ <td align="right"> @ <input type="submit" name="submit" value="Submit"> @ </td> @@ -234,66 +195,65 @@ @ <td>After filling in the information above, press this button to create @ the new ticket</td> @ </tr> @ </table> @ <!-- end of form --> -@ } /tktnew_template set +@ } @ @ ########################################################################## @ # The template for the "edit ticket" page @ # @ # Then generated text is inserted inside a form which feeds back to itself. @ # All CGI parameters are loaded into variables. All database files are @ # loaded into variables if they have not previously been loaded by @ # CGI parameters. -@ { -@ [ -@ login /username get /username set -@ { -@ { -@ username login eq /samename set -@ { -@ "\n\n<hr><i>" login " added on " date ":</i><br>\n" -@ cmappnd 6 concat /comment append_field -@ } samename if -@ { -@ "\n\n<hr><i>" login " claiming to be " username " added on " date -@ "</i><br>\n" cmappnd 8 concat /comment append_field -@ } samename not if -@ } 0 {} /cmappnd get length lt if +@ set tktedit_template { +@ <th1> +@ if {![info exists username]} {set username $login} +@ if {[info exists submit]} { +@ if {[info exists $cmappnd] && [string length $cmappnd]>0} { +@ set ctxt "\n\n<hr><i>" +@ if {$username==$login} { +@ set usr "$ctxt[htmlize $login]" +@ } else { +@ set usr "[htmlize $login claimingn to be [htmlize $username]" +@ } +@ append_field comment \ +@ "\n\n<hr><i>$usr added on [date]:</i><br>\n$comment" +@ } @ submit_ticket -@ } /submit exists if -@ ] +@ } +@ </th1> @ <table cellpadding="5"> @ <tr><td align="right">Title:</td><td> -@ <input type="text" name="title" value="[title html]" size="60"> +@ <input type="text" name="title" value="$<title>" size="60"> @ </td></tr> @ <tr><td align="right">Status:</td><td> -@ [/status status_choices 1 combobox] +@ <th1>combobox status $status_choices 1</th1> @ </td></tr> @ <tr><td align="right">Type:</td><td> -@ [/type type_choices 1 combobox] +@ <th1>combobox type $type_choices 1</th1> @ </td></tr> @ <tr><td align="right">Severity:</td><td> -@ [/severity severity_choices 1 combobox] +@ <th1>combobox severity $severity_choices 1</th1> @ </td></tr> @ <tr><td align="right">Priority:</td><td> -@ [/priority priority_choices 1 combobox] +@ <th1>combobox priority $priority_choices 1</th1> @ </td></tr> @ <tr><td align="right">Resolution:</td><td> -@ [/resolution resolution_choices 1 combobox] +@ <th1>combobox resolution $resolution_choices 1</th1> @ </td></tr> @ <tr><td align="right">Subsystem:</td><td> -@ [/subsystem subsystem_choices 1 combobox] -@ </td></tr> -@ [/e hascap enable_output] +@ <th1>combobox subsystem $subsystem_choices 1</th1> +@ </td></tr> +@ <th1>enable_output [hascap e]</th1> @ <tr><td align="right">Contact:</td><td> -@ <input type="text" name="contact" size="40" value="[contact html]"> +@ <input type="text" name="contact" size="40" value="$<contact>"> @ </td></tr> -@ [1 enable_output] +@ <th1>enable_output 1</th1> @ <tr><td align="right">Version Found In:</td><td> -@ <input type="text" name="foundin" size="50" value="[foundin html]"> +@ <input type="text" name="foundin" size="50" value="$<foundin>"> @ </td></tr> @ <tr><td colspan="2"> @ @ [ @ 0 /eall get /eall set # eall means "edit all". default==no @@ -326,44 +286,44 @@ @ </table> @ } /tktedit_template set @ @ ########################################################################## @ # The template for the "view ticket" page -@ { +@ set tktview_template { @ <!-- load database fields automatically loaded into variables --> @ <table cellpadding="5"> @ <tr><td align="right">Title:</td><td> -@ [title html] +@ $<title> @ </td></tr> @ <tr><td align="right">Status:</td><td> -@ [status html] +@ $<status> @ </td></tr> @ <tr><td align="right">Type:</td><td> -@ [type html] +@ $<type> @ </td></tr> @ <tr><td align="right">Severity:</td><td> -@ [severity html] +@ $<severity> @ </td></tr> @ <tr><td align="right">Priority:</td><td> -@ [priority html] +@ $<priority> @ </td></tr> @ <tr><td align="right">Resolution:</td><td> -@ [priority html] +@ $<resolution> @ </td></tr> @ <tr><td align="right">Subsystem:</td><td> -@ [subsystem html] +@ $<subsystem> @ </td></tr> -@ [{e} hascap enable_output] +@ <th1>enable_output [hascap e]</th1> @ <tr><td align="right">Contact:</td><td> -@ [contact html] +@ $<contact> @ </td></tr> -@ [1 enable_output] +@ <th1>enable_output 1</th1> @ <tr><td align="right">Version Found In:</td><td> -@ [foundin html] +@ $<foundin> @ </td></tr> @ <tr><td colspan="2"> @ Description And Comments:<br> -@ [comment wiki] +@ <th1>wiki $comment</th1> @ </td></tr> @ </table> -@ } /tktview_template set +@ } ;