Tutorial: Writing an embedded Compile Time script
This tutorial teaches you how to write simple Compile Time
scripts embedded in HTML or ASP page. It begins with "Hello
World!" and is good for both beginners and advanced
developers.
The corresponding sample is in the <ASPCDIR>\Samples\tutorials\embeded
(see the shortcut to the samples in the ASPC's group in the start
menu).
Introduction
HTML pages will be used in the tutorial. The same techniques
can be used with ASP pages as well.
If you want to follow the tutorial create a new project and
create the mentioned files or open the corresponding sample.
The first step in this tutorial may look like a "try to do
nothing writing some code" but they are the easiest way to
show the basics of the compile time scripting. After passing
through them you can see the other tutorials that deal with data
bases and once written provide powerful way to generate and
regenerate part or the entire site using templates. Thus
please excuse us if the "Hello World!" steps are a
little boring - there is no better way to show how one tool
works.
Step 1: Say "Hello World!"
Let name the first page a.htm. Set its processing
option to SSIToHTML. We will insert an embedded CTS in it
and produce simple output in the output file during the
compilation. What the embedded script looks like:
<html>
<body>
<p>
The first CTS script will write Hello World below
</p>
<p>
<font color="#FF0000">
<SCRIPT RUNAT=COMPILER LANGUAGE=VBSCript>
node("Class") = "Text"
node("Content") = "Hello World!"
</SCRIPT>
</font>
</p>
</body>
</html>
The CTS is placed in <SCRIPT> tag with attribute RUNAT
set to COMPILER (case insensetive). The syntax is similar to the
scripts in DHTML but RUNAT attribute specifies that the compiler
shall execute it.
What is the "node"? The script uses the node
object that is always available for the embedded compile time
scripts and represents the page node in which the script is
written. Thus the node object in this example represents
the entire <SCRIPT> tag.
ASPC translates the entire file in a tree of objects - Page
Object Model (POM). Thus the document parts are
represented as nodes in a tree. The node object above is
an alias for the document node containing the invoked script.
There are several node types, but we will concentrate on two of
them at this moment:
Text node - this is anything outside any ASPC special
tags or ASP tags.
CompileTimeScript (CTS) node - this is a node designated
in the page source with <SCRIPT RUNAT=Compiler>...</SCRIPT>
tag.
The above page will be presented to the script in it as a
chain (in this simple case the tree has no branches) of 3 nodes:
Text, CTS, Text. Thus in the above example
everything outside the SCRIPT tag in not interesting for the
compiler and is treated as some kind of text.
Nodes are collections of attributes and sub-nodes (sub-nodes
may appear only if CUSTOM tags are used - discussed later).
Every element of the collection can be accessed using nodeObject("name")
or nodeObject.Item("name") syntax (Item is the
default property of the nodes) or they could be enumerated as
collection.
All the nodes have common (and vital) attribute - Class.
It specifies the role of the node. After completing the
execution of any compile time scripts ASPC will cycle through
the page's tree and depending on the role of each node will
produce different output in the output file.
Thus the compile time script does
its work by inspecting and modifying the Page Object Model (the
document tree). Therefore we deal with two node types
in the above example - Text and CTS nodes. The script in the
<SCRIPT> tag "knows" the node it occupies in the
document through the node variable passed by the
compiler. Its Class attribute is initially "CompileTimeScript"
- e.g. node("Class") contains "CompileTimeScript"
when the script starts. During its execution the script can
change this attribute and thus change the node role - in this
case its own node role. In other words the script is able to
replace self with something else. The example sets the node("Class")
to "Text". That means the node role is changed
to Text node. After executing the script the compiler
will have a tree containing 3 Text nodes and it will generate 3
chunks of text sequentially in the output file.
The Content attribute is set to the string "Hello
World!" by the second script line:
node("Content") = "Hello World!"
The Content attribute is the second attribute
common for the most node types (except some special node types
not intended for the compile time scripts). It contains as a
string the node content. Thus initially the node("Content")
contains the source of the embedded script. After its execution
it contains "Hello World!".
And the output from the above code will be:
=== BEGIN ===
The first CTS script will write Hello World below
Hello World!
=== END ===
What will happen if the first line is removed - e.g. Class
not set to "Text"? The output will be:
=== BEGIN ===
The first CTS script will write Hello World below
=== END ===
The ASPC hides the nodes with class "CompileTimeScript"
thus it will reconstruct in the output file only the other two
nodes - the Text nodes only. And if the script should
produce output depending on a condition it needs to do something
only when the output is to be produced.
Conclusion: The CTS sees the processed page as tree of
objects representing the page parts. Although it looks similar
to the DHTML document model in ASPC page object model is limited
to the parts designated by the ASPC special tags only. The
script has direct access to the node it occupies. The script is
able to change the role and content of its own node and thus
modify the document tree. If the script does not change its own
node - the entire script tag will be omitted in the
output.
Step 2: Obtain information from the outer world using the
compiler variables.
The example in the previous step does nothing useful - we can
write this text ourselves in the page. Thus let's make it a bit
more useful.
Let change the <SCRIPT> like this:
<html>
<body>
<p>
The second CTS script will put compiler
variable defined in the project
settings below
</p>
<p>
<font color="#FF0000">
<SCRIPT RUNAT=COMPILER LANGUAGE=VBSCript>
node("Class") = "Text"
node("Content") = GlobalVariables("var1")
</SCRIPT>
</font>
</p>
</body>
</html>
What are the GlobalVariables? The compiler passes to
the embedded script a collection of variables defined by the
user in the "project settings" dialog (Button Compiler
variables). Every variable has a name and a string value.
Thus by changing the value in the project settings dialog the
user instructs the embedded script to produce different output.
And if we set the variable "var1" to the value
"Blah" the output will be:
=== BEGIN ===
The second CTS script will put compiler variable defined in
the project settings below
Blah
=== END ===
Well this is a bit more useful indeed. We can change some
little texts in all the pages in the project if they contain a
little simple script in the place where we want to put the
configured text. For example this could be the Title, or the
copyright note (if the year in it must be changed).
But what if we want to be able to specify something for a
specific file only? Then we can change the code to:
<html>
<body>
<p>
The third CTS script will put compiler
variable defined for the current file below
</p>
<p>
<font color="#FF0000">
<SCRIPT RUNAT=COMPILER LANGUAGE=VBSCript>
node("Class") = "Text"
node("Content") = Variables("var1")
</SCRIPT>
</font>
</p>
</body>
</html>
This will get the value of the variable specified in the File
options dialog (Button Compiler variables) for the selected
file.
And finally let us implement something that will produce more
output:
<html>
<body>
<p>
The forth CTS script will put compiler
variable defined for the current file below.
It will be repeated several times.
</p>
<p>
<font color="#FF0000">
<SCRIPT RUNAT=COMPILER LANGUAGE=VBSCript>
node("Class") = "Text"
Dim count, I
count = CInt(Variables("RepeatCount"))
node("Content") = ""
For I = 1 To count
node("Content") = node("Content") & Variables("var1") & "<BR>"
Next
</SCRIPT>
</font>
</p>
</body>
</html>
If we set in the File options dialog the RepeatCount
variable to 6 and var1 to "Hello World again!" the
output will be:
=== BEGIN ===
The forth CTS script will put compiler variable defined for
the current file below. It will be repeated several times.
Hello Wrold again!
Hello Wrold again!
Hello Wrold again!
Hello Wrold again!
Hello Wrold again!
Hello Wrold again!
=== END ===
Conclusion: By using the compiler variables named
values can be defined for the entire project (gloabal) and for
each file (local) in it. The global (project wide) variables are
available to the script through the GlobalVariables
collection and the local (file specific) variables are available
to the scrip through the Variables collection.
Step 3: Make something more useful - an embedded script
producing visual element.
Create a file named b.htm (or see the b.htm in the sample
project):
<html>
<body>
<p>
The CTS script will construct an image button below
</p>
<p>
<SCRIPT RUNAT=COMPILER LANGUAGE=VBSCript>
node("Class") = "Text"
Dim text
text = "<IMG SRC=""" & Variables("IMGOFF") & """ STYLE=""cursor:hand""" & _
" onMouseOver=""event.srcElement.src='" & Variables("IMGON") & "'"" " & _
" onMouseOut=""event.srcElement.src='" & Variables("IMGOFF") & "'""" & _
" onClick=""alert('" & Variables("Message") & "')"">"
node("Content") = text
</SCRIPT>
</p>
</body>
</html>
This will produce a button-like element that changes its image when the mouse
is over it and does something when clicked. In the sample all
the code is written inline (in the IMG tag's attributes), but
this could be easily changed to something more productive.
The script expect the compiler variables to specify the image
for "off" state and "on" state and the
message text to be shown when the image is clicked. Thus if some
of the dynamic elements of the site are generated this way they
all can be changed at once by changing a few variables. In the
sample project file specific variables are used - in real case
usage of global variables make more sense, because it will
affect all the pages in the project and not only one of them.
Well it looks ok but should we repeat all this code in
every page we create? Of course not! After testing a code
like above you are able to perform the next step - moving it in
a separate file and just refer it. Let create a file script1.vbs
in the same directory where the HTML file resides and put in
it:
node("Class") = "Text"
Dim text
text = "<IMG SRC=""" & Variables("IMGOFF") & """ STYLE=""cursor:hand""" & _
" onMouseOver=""event.srcElement.src='" & Variables("IMGON") & "'"" " & _
" onMouseOut=""event.srcElement.src='" & Variables("IMGOFF") & "'""" & _
" onClick=""alert('" & Variables("Message") & "')"">"
node("Content") = text
And change the script tag in the above HTML file to:
<SCRIPT RUNAT=COMPILER LANGUAGE=VBSCript SRC="Script1.vbs">
</SCRIPT>
(Corresponding file in the example project - c.htm).
This will produce the same result but now it is much easier
to put it in many pages. the script is loaded from the external
file and is one for all the pages referring it. Now a site with
many pages using this script will be a bit more easier.
A little digression: What really happens above? Is it
possible to use this SRC attribute that refers the script file,
but also put some code in the SCRIPT tag? The answer is
"yes". This feature could be very useful in some
phases of development when part of the code is common and other
part uses the common part as library.
(... tutorial text not finished yet
...)
|