Fossil

Check-in [3ad9a5e210]
Login

Check-in [3ad9a5e210]

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

Overview
Comment:TH1 script now used to render the header and footer of each page.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3ad9a5e210489adea0ad0717af051e947a8b41ab
User & Date: drh 2008-02-13 18:18:50.000
Context
2008-02-13
19:50
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. ... (check-in: ffe92f1a2f user: drh tags: trunk)
18:18
TH1 script now used to render the header and footer of each page. ... (check-in: 3ad9a5e210 user: drh tags: trunk)
16:21
Create the interface between TH1 and the rest of fossil. Subscript is still being used, though. This is a preparatory step toward cutting over to TH1. ... (check-in: 13e16c824a user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/style.c.
66
67
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
100
101
102
103
104
105
106
107
108
*/
static int submenuCompare(const void *a, const void *b){
  const struct Submenu *A = (const struct Submenu*)a;
  const struct Submenu *B = (const struct Submenu*)b;
  return strcmp(A->zLabel, B->zLabel);
}

/*
** The Subscript interpreter used to render header and footer.
*/
static struct Subscript *pInterp;

/*
** Draw the header.
*/
void style_header(const char *zTitle){
  const char *zLogInOut = "Login";
  const char *zHeader = db_get("header", (char*)zDefaultHeader);  
  login_check_credentials();
  
  if( pInterp ) return;
  cgi_destination(CGI_HEADER);

  /* Generate the header up through the main menu */
  pInterp = SbS_Create();
  SbS_Store(pInterp, "project_name",
                     db_get("project-name","Unnamed Fossil Project"), 0);
  SbS_Store(pInterp, "title", zTitle, 0);
  SbS_Store(pInterp, "baseurl", g.zBaseURL, 0);
  SbS_Store(pInterp, "manifest_version", MANIFEST_VERSION, 0);
  SbS_Store(pInterp, "manifest_date", MANIFEST_DATE, 0);
  if( g.zLogin ){
    SbS_Store(pInterp, "login", g.zLogin, 0);
    zLogInOut = "Logout";
  }
  SbS_Render(pInterp, 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>
  }







<
<
<
<
<








<



<
<
|
|
|
|
|

|


|







66
67
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
100
*/
static int submenuCompare(const void *a, const void *b){
  const struct Submenu *A = (const struct Submenu*)a;
  const struct Submenu *B = (const struct Submenu*)b;
  return strcmp(A->zLabel, B->zLabel);
}






/*
** 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);

  /* Generate the header up through the main menu */


  Th_InitVar("project_name", db_get("project-name","Unnamed Fossil Project"));
  Th_InitVar("title", zTitle);
  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>
  }
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

/*
** Draw the footer at the bottom of the page.
*/
void style_footer(void){
  const char *zFooter;
  
  if( pInterp==0 ) return;

  /* Go back and put the submenu at the top of the page.  We delay the
  ** creation of the submenu until the end so that we can add elements
  ** to the submenu while generating page text.
  */
  if( nSubmenu>0 ){
    int i;
    cgi_destination(CGI_HEADER);







<
<







124
125
126
127
128
129
130


131
132
133
134
135
136
137

/*
** Draw the footer at the bottom of the page.
*/
void style_footer(void){
  const char *zFooter;
  


  /* Go back and put the submenu at the top of the page.  We delay the
  ** creation of the submenu until the end so that we can add elements
  ** to the submenu while generating page text.
  */
  if( nSubmenu>0 ){
    int i;
    cgi_destination(CGI_HEADER);
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
  }

  /* Put the footer at the bottom of the page.
  */
  @ <div class="content">
  zFooter = db_get("footer", (char*)zDefaultFooter);
  @ </div>
  SbS_Render(pInterp, zFooter);
  SbS_Destroy(pInterp);
  pInterp = 0;
}

/* @-comment: // */
/*
** The default page header.
*/
const char zDefaultHeader[] = 
@ <html>
@ <head>
@ <title>[project_name html]: [title html]</title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@       href="[baseurl puts]/timeline.rss">
@ <link rel="stylesheet" href="[baseurl puts]/style.css" type="text/css"
@       media="screen">
@ </head>
@ <body>
@ <div class="header">
@   <div class="logo">
@     <!-- <img src="logo.gif" alt="logo"><br></br> -->
@     <nobr>[project_name html]</nobr>
@   </div>
@   <div class="title">[title html]</div>
@   <div class="status"><nobr>

@     [/login exists enable_output]     Logged in as
@      <a href='[baseurl puts]/my'>[0 /login get html]</a>
@     [/login exists not enable_output] Not logged in
@     [1 enable_output]
@   </nobr></div>
@ </div>
;

/*
** The default page footer
*/
const char zDefaultFooter[] = 
@ <div class="footer">
@ Fossil version [manifest_version puts] [manifest_date puts]
@ </div>
@ </body></html>
;

/*
** The default Cascading Style Sheet.
*/







|
<
<









|

|
|






|

|
|
>
|
|
|
|
|








|







150
151
152
153
154
155
156
157


158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  }

  /* Put the footer at the bottom of the page.
  */
  @ <div class="content">
  zFooter = db_get("footer", (char*)zDefaultFooter);
  @ </div>
  Th_Render(zFooter);


}

/* @-comment: // */
/*
** The default page header.
*/
const char zDefaultHeader[] = 
@ <html>
@ <head>
@ <title><th1>puts "$project_name: $title"</th1></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>
@   </div>
@   <div class="title"><th1>puts $title</th1></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>
;

/*
** The default page footer
*/
const char zDefaultFooter[] = 
@ <div class="footer">
@ Fossil version $manifest_version $manifest_date
@ </div>
@ </body></html>
;

/*
** The default Cascading Style Sheet.
*/
Changes to src/th_main.c.
175
176
177
178
179
180
181








182
183
184
185
186
187
188
    th_register_language(interp);       /* Basic scripting commands. */
    for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
      Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc,
                       aCommand[i].pContext, 0);
    }
  }
}









/*
** Return true if the string begins with the TH1 begin-script
** tag:  <th1>.
*/
static int isBeginScriptTag(const char *z){
  return z[0]=='<'







>
>
>
>
>
>
>
>







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
    th_register_language(interp);       /* Basic scripting commands. */
    for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
      Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc,
                       aCommand[i].pContext, 0);
    }
  }
}

/*
** Initialize a variable in the interpreter.
*/
void Th_InitVar(const char *zName, const char *zValue){
  initializeInterp();
  Th_SetVar(interp, zName, -1, zValue, strlen(zValue));
}

/*
** Return true if the string begins with the TH1 begin-script
** tag:  <th1>.
*/
static int isBeginScriptTag(const char *z){
  return z[0]=='<'
200
201
202
203
204
205
206






















207
208
209
210
211
212
213
214
215

216

217
218







219
220
221
222
223
224
225
226
227
228
229
230
231
232
233

234
235
236
237
238
239
240
241
  return z[0]=='<'
      && z[1]=='/'
      && (z[2]=='t' || z[2]=='T')
      && (z[3]=='h' || z[3]=='H')
      && z[4]=='1'
      && z[5]=='>';
}























/*
** 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.
*/
int Th_Render(const char *z){
  int i = 0;

  int rc = TH_OK;

  initializeInterp();
  while( z[i] ){







    if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
      sendText(z, i);
      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;
      if( z[0] ){ z += 6; }
      i = 0;
    }else{
      i++;
    }
  }
  if( rc==TH_ERROR ){
    sendText("<hr><p><font color=\"red\"><b>ERROR: ", -1);

    /* sendText(SbS_GetErrorMessage(p), -1); */
    sendText("</b></font></p>", -1);
  }else{
    sendText(z, i);
  }
  return rc;
}








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>









>

>


>
>
>
>
>
>
>
|














>
|







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  return z[0]=='<'
      && z[1]=='/'
      && (z[2]=='t' || z[2]=='T')
      && (z[3]=='h' || z[3]=='H')
      && z[4]=='1'
      && z[5]=='>';
}

/*
** 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;
  if( z[0]==':' && z[1]==':' && isalpha(z[2]) ){
    z += 3;
    i = 3;
  }else if( isalpha(z[0]) ){
    z ++;
    i = 1;
  }else{
    return 0;
  }
  while( isalnum(z[0]) || z[0]=='_' ){
    z++;
    i++;
  }
  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.
*/
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);
      z += i+1+n;
      i = 0;
      zResult = Th_GetResult(interp, &n);
      sendText(zResult, n);
    }else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
      sendText(z, i);
      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;
      if( z[0] ){ z += 6; }
      i = 0;
    }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);
  }else{
    sendText(z, i);
  }
  return rc;
}