Date:  04/13/2004 03:05:27 PM Msg ID:  001961
From:  David Hempy Thread:  001959
Subject:  Re: Server.Execute, html_out, buffering...
Ahhh...I had overlooked the Response.OutputBuffer property.  I can use that to grab the output of the Executed .fwx file.
 
I've written IncludeFwx(), which executes a .fwx file, and gets the output back to the browser appropriately, whether called from a .fwx file or a .prg file.  

Some bits of this are specific to our site's structure, but if anyone needs to use this, I'm sure they'll figure out which parts to twiddle for their site.
 
Thanks for pointing me toward the Response.OutputBuffer property.  You've saved the day yet again, support team.
 
function PageHead(m.courseid)
 return IncludeFwx('pagehead.fwx')
endfunc
 
function PageHeader()
 return IncludeFwx('pageheader.fwx')
endfunc
 
function PageFooter()
 return IncludeFwx('pagefooter.fwx')
endfunc
 
function IncludeFwx(m.filename)
  && This function executes a .fwx file and returns its output.
  && If called from a .fwx file, Server.Execute() writes response output directly.
  && If called from a .prg file, caller must capture returned content and output it, such as with Response.Write or html_out.
  
 local m.template_fname
  && Look in the current course's template directory, then generic directories:
 m.template_fname = FindFileAllPaths(m.filename) 
  
 if (empty (m.template_fname))
  return "<p>Could not find template [<tt>" + m.filename + "</tt>]</p>" +CRLF
 else
  local m.buffer_state, m.existing_content, m.included_content
  m.buffer_state = Response.Buffer
  Response.Buffer = .T.
  m.existing_content = Response.OutputBuffer
  
  if not (m.fwx_file) && m.fwx_file is a global variable I set in fw_enter, based on the URL.
   && For .fwx files, don't mess with Response.OutputBuffer. 
   && Otherwise, (for .prg files using html_out) prevent any change to Response.OutputBuffer. 
   Response.OutputBuffer = ''
  endif
  
  Server.Execute(m.template_fname)
  m.included_content = Response.OutputBuffer
  
  if not (m.fwx_file) 
   && For .fwx files, don't mess with Response.OutputBuffer. 
   && Otherwise, (for .prg files using html_out) prevent any change to Response.OutputBuffer. 
   Response.OutputBuffer = m.existing_content
  endif
  
  Response.Buffer = m.buffer_state  && Leave it like you found it.
  
  return Server.ToString(m.included_content) && shouldn't need ToString(), but might save face some day.
 endif
endfunc
 
 
I've tested this from .fwx scripts and legacy .prg scripts emplying html_out.  I've tested each with Buffering on and off.  It works in our environment for all four cases.
 
Do you see any red flags in what I'm doing here?  Any suggestions of safer tests/actions?
 
Regarding your suggestion of using MergeTxt() to slurp in old-style templates...that is fine, (we've done that for many uses over the years) but I'm eager to tap into the rich programming features the .fwx files have to really enhance what these components can do.  I'm extremely happy you pointed me toward this solution.  Thank you!
 
-dave
 
 

--
David Hempy
Internet Database Administrator
Kentucky Educational Television
(859)258-7164  -  (800)333-9764

Sent by FoxWeb Support on 04/12/2004 06:38:10 PM:
The discrepancy between your FWX and legacy PRG scripts is not due to the fact that they are different file types, but rather due to the different methods they use to send results back to the browser.  Your old PRG files use the html_out variable to send data to the browser, while your new FWX files either include HTML text outside the code delimiters, or utilize Response.Write.  You can only use one of these techniques during a particular request.  To understand this, you should first understand how FoxWeb 2.X processes outbound data:
 
FWX files are not processed in real time by FoxWeb.  What happens instead, is that they are converted to regular PRG and FXP files the first time they are requested (or after they are modified).  HTML code blocks in FWX files (blocks outside <% and %> delimiters), are actually converted to FoxPro code that calls the Response.Write method.  From this you can see that your statement that "These three functions do not ... call Response.Write() directly" is incorrect.  Any FWX file containing HTML code blocks, causes calls to Response.Write, even if the original FWX code does not contain such calls.
 
If buffering is disabled, then calls to Response.Write result in data being sent out to the client immediately.  If on the other hand buffering is enabled, FoxWeb accumulates output in the Response.OutputBuffer property until the end of the request (or until Response.Flush is called).
 
After execution of the script is completed, FoxWeb runs the following pseudo code:
 
If html_out is not empty and no data has already been sent out
    Send out content of html_out
Else
    Response.Flush
End If
 
 
The above pseudo code explains why you are getting different behavior depending on the buffering setting.  If Response.Buffer is .F. (or if you called Response.Flush in your script), then data will have already been sent out, so the content of html_out is simply ignored.  If on the other hand buffering is enabled, html_out is sent to the browser and the content of Response.OutputBuffer is ignored.
 
As you can see from the above, there's no way to mix use of the Response object (or HTML blocks in FWX files) and the html_out variable in the same request.  This actually holds true for all other objects that utilize the Response object, such as the Session and Auth objects.
 
You can still share common headers and footers, but you will have to modify the files that contain this content.  Instead of creating FWX files, you should place your content in text files that can be read via FILETOSTR and sent to the browser via html_out, or Response.Write as necessary.  These files can even contain expressions, that get processed with the MergeTxt function:
 
First the FWXHead function, which gets called by FWX files:
 
Response.Write(MergeTxt(FILETOSTR('head.txt')))
 
...and the PRGHead function, which gets called by old-style PRG files:
 
html_out = 'Content-Type: Text/html' + CHR(10) + CHR(10) ;
    + MergeTxt(FILETOSTR('head.txt'))
 
The corresponding header and footer functions will be similar, with the difference that the PRG versions will add content to html_out instead of sending the content type:
 
html_out = html_out + MergeTxt(FILETOSTR('header.txt'))
 
Obviously, if your txt files don't contain any dynamic expressions, you don't need to process their content with MergeTxt:
 
html_out = html_out + FILETOSTR('header.txt')
 
And finally, if you want to be able to edit your text files in an HTML editor, or open them in a web browser, you can give them an 'htm' extension instead of 'txt'.  It really doesn't matter what the extension of the file is, because FILETOSTR simply reads its content.

FoxWeb Support Team
support@foxweb.com email

Sent by David Hempy on 04/12/2004 04:03:21 PM:
I've trying to use .fwx scripts as page components like headers, nav bars, and footers...much like you would use server side includes in a static environment.  I am using Server.Execute() to invoke those sub-scripts.
 
This works very well in this .fwx page:
 
 
This yields very tidy source files for our authors to work with, with very little program code for them to monkey with:
 
<html>
<head>
 <title>Sample .FWX file for Distance Learning</title>
 <% PageHead() %>
</head>
<body>
<% PageHeader() %>

 <h2>Welcome back, <%= login.username %>.</h2>
   ...etc...

<% PageFooter() %>
</body>
</html>
 
 
PageHead(), PageHeader(), and PageFooter() are little more than calls to Server.Execute('head.fwx'), Server.Execute('header.fwx'), and Server.Execute('footer.fwx').  header.fwx has some dynamic code in it, for example displaying the user's name and current lesson number.
 
These three functions do not return anything or call Response.Write() directly...Server.Execute does all that.  As I said, this works perfectly from a .FWX file.
 
The problem arises when I try to use the same approach in my legacy FoxWeb templates, called from .PRG programs, ultimately writing to html_out. 
 
In this case, if I have Buffer Output on, I don't get any of the output of the .FWX scripts.  Server.Execute() returns .T.
 
If I turn Buffer Output off, I only get the output from the several .FWX scripts...the output I leave in html_out is disregarded.
 
 
It seems what I really need is for Server.Execute() to return the output of the .FWX script.  Either that or maybe a property such as Server.ExecutedOutput or something that returns the output of the last Server.Execute().  Does such a thing exist?  That would solve my problem 100%.
 
Or is there another way of accomplishing this?  My main goal is that one single file is used as the header for all my pages, both new .fwx files and legacy .prg files.
 
I would'nt even mind writing a function named FWXHeader() to be called from .fwx scripts, and another named PRGHeader() to be called from .prg programs, where the two use different ways of getting the output back to the browser.  However, it is highly desirable (almost critical, really) that the output generated by each actually originate from the same .fwx file.
 
Any suggestions?
 
-dave
 
 
ps.  As a side note, I'm surprised that the behavior varies so greatly with Buffering On vs. Off...but that is not a great concern for the issue at hand.
 
 

--
David Hempy
Internet Database Administrator
Kentucky Educational Television
(859)258-7164  -  (800)333-9764