Table of Contents
Gila
(pronounced Hila) is the default view-engine in Chameleon
framework. In this section, Gila
's syntax and rules are explained.
Gila
(pronounced Hila) is the default view-engine in Chameleon
framework. In this section, Gila
's syntax and rules are explained.
<%=...%>
notation is used to write a T-SQL expression, literal, value or variable.
Example:
Hello <%='World!'%>
Output:
Hello World!
Note: In order to counter XSS exploitation, by default Gila
HTML encodes inline outputs.
Example:
<%='10 > 2'%>
Output:
10 > 2
In case we explicitly want to write raw inline output without them being html encoded, we can use <%#=...%>
notation.
Example:
<%#='<b>'%>
Hello World!
<%#='</b>'%>
Output:
<b>
Hello World
</b>
Other than <%= ... %> and <%#= ... %>, there are a few other inline output notations that could be handy when working with web content. They are listed in the following table.
Notation | Function | Example | Output |
---|---|---|---|
<%= ...%>
|
Html encode |
<%='<b>'%>
|
<b>
|
<%#=...%>
|
Raw or Plain write |
<%#='<b>'%>
|
<b>
|
<%~=...%>
|
Html decode |
<%~='<b>'%>
|
<b>
|
<%!=...%>
|
Full Url encode |
<%!='john doe'%>
|
john%20doe
|
<%?=...%>
|
Url encode (only portion of given string is encoded that is located after question mark ) |
<%?='http://a.com/?name=john doe'%>
|
http://a.com/?name=john%20doe
|
<%^=...%>
|
Full Url decode |
<%^='john%20doe'%>
|
john doe
|
<%&=...%>
|
Url decode (only portion of given string is decoded that is located after question mark ) |
<%^='http://a.com/?name=john%20doe'%>
|
http://a.com/?name=john doe
|
<%$= ...%>
|
generate md5 in base64 format |
<%$='hello'%>
|
XUFAKrxLKna5cZ2REBfFkg==
|
<%:=...%>
|
base64 encode |
<%:='hello world'%>
|
aGVsbG8gd29ybGQ=
|
<%.=...%>
|
base64 decode |
<%.='aGVsbG8gd29ybGQ='%>
|
hello world
|
Custom T-SQL blocks could be placed inside <%
and %>
.
Example:
<%
declare @name varchar(10)
set @name = 'Gila'
%>
Hello from <%=@name%>!
Output:
Hello from Gila!
In a Gila block code, all T-SQL statements can be used. In the next example, a while
statement is used to generate a list of numbers.
<% declare @i int = 0 %>
<ul>
<%
while @i < 5
begin
%>
<li><%=@i%></li>
<% set @i = @i + 1
end %>
</ul>
Output:
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
We can comment a Gila
block code using <%** ... **%>
notation. Anything put inside <%**
and **%>
is ignored during view compilation.
<%**
this is a comment
**%>
Note: By default, comments are not reflected in generated compiled code. However, using Gila
configuration we can ask Gila
to reflect comments in output. Gila
configuration is described.
Gila
views can receive a single model parameter. This enables developer to make his views parametric and make their content dependent on the given argument.
The name of the model parameter is @model
. This is a reserved name and developers should not define another variable with this name.
The data type of model parameter is nvarchar(max)
. It is developer's choice whatever data he passes to a view and what he/she does with it. In order to pass multiple arguments to a view/template we can pass XML or JSON format.
When rendering a view using chameleon.RenderView
we can specify its model as the third parameter of this stored procedure.
Example:
Suppose we have a view named 'my-view' in chameleon.Views
table with the following content.
Welcome <%=@model%>
We can render 'my-view' using chameleon.RenderView
this way:
declare @result nvarchar(max)
exec [chameleon].[RenderView]
@context_id = 0,
@name = 'my-view',
@model = 'John',
@result out
print @result
After rendering the view, the following output will be printed.
Welcome John
Example: As it was said, if we wan to pass multiple values, we can use JSON format.
<%
declare @name varchar(50)
declare @age varchar(5)
select
@name = [name],
@age = [age]
from openjson(@model)
with
(
[name] varchar(50) '$.name',
[age] varchar(5) '$.age'
)
%>
My name is <%=@name%>. I am <%=@age%> years old.
Now, we can render a view:
declare @result nvarchar(max)
exec [chameleon].[RenderView]
@context_id = 0,
@name = 'my-view',
@model = ' {"name": "John", "age": 32 }',
@result out
print @result
Output:
My name is John. I am 32 years old.
Partial views are views that do not have a template and are invoked by another view. In order to invoke a partial view, the <%* partial-view-name(@partial-view-model)%>
notation is used.
Example:
Suppose we have a view named 'product-item' in chameleon.Views
table as below that is designed to show a summary box for a product.
<%
declare @id int,
@title varchar(100),
@description varchar(200),
@price int,
@image varchar(250)
select
@id = [id],
@title = [title],
@description = [description],
@price = [price],
@image = [image]
from openjson(@model)
with
(
[id] int '$.id',
[title] varchar(100) '$.title',
[description] varchar(200) '$.description',
[price] int '$.price',
[image] varchar(250) '$.image'
)
%>
<div class="card" style="width: 18rem;">
<img src="<%=@image%>" class="card-img-top" alt="<%=@title%>">
<div class="card-body">
<h5 class="card-title"><%=@title%></h5>
<h4 class=""><%=@price%></h4>
<p class="card-text"><%=@description%></p>
<a href="/product/<%=@id%>" class="btn btn-primary">View</a>
</div>
</div>
We recieve product data through the @model
parameter in JSON format. Then, we deserialize JSON using openjson
and access product's properties. After that, we put the fiels inside placeholders in the view.
Having this partial view, we can then create a view named like 'product-top-10' that shows list of top 10 products in a dbo.Products
table (ordered by [rate]
) using the 'product-item' partial view.
<%
declare cx cursor for select top 10 id from dbo.Products order by [rate]
declare @id int
declare @product_json varchar(1000)
open cx
fetch next from cx into @id
while @@FETCH_STATUS = 0
begin
set @product_json =
(
select
[id],
[title],
[description],
[price],
[image]
from dbo.Products
where id = @id
for json path, WITHOUT_ARRAY_WRAPPER
)
%>
<%*product-item(@product_json)%>
<%
fetch next from cx into @id
end
close cx
deallocate cx
%>
Here, we used cursors to iterate over products. Cursors are resource-intensive. Here is a cursor-free implementation that achieves the same result using while
statement.
<%
declare @all varchar(max)
declare @product_json varchar(1000)
declare @i int = 0
set @all =
(
select top 10
[id],
[title],
[description],
[price],
[image]
from dbo.Products for json path
order by [rate]
)
while @i >= 0
begin
select @product_json = [value] from openjson(@all) where [key] = @i
if @product_json is null
break
%>
<%*product-item(@product_json)%>
<%
set @i = @i + 1
set @product_json = null
end
%>
We can specify a parent view as a template for a view using <%@ ...%>
notation. Between <%@
and %>
name of the master template is placed. All views should be defined in chameleon.Views
table. The template name that is put between <%@
and %>
is white-space trimmed (its left and right white-spaces are trimmed).
Example:
Suppose we defined a view named layout
in chameleon.Views
as below:
<html>
<head>
<title>Chameleon</title>
</head>
<body>
<%# body #%>
</body>
</html>
We can then create a view like 'about' that uses the 'layout' template.
<%@ lauout %>
Welcome to Chameleon!
Here is the outut when 'about' view is rendered:
<html>
<head>
<title>Chameleon</title>
</head>
<body>
Welcome to Chameleon!
</body>
</html>
All the content of the child view is placed inside <%# body #%>
in the parent view or template (i.e. 'layout' view here).
When using templates, we can define sections whose content will be specified by child views. Sections are defined using <%#
and #%>
notation in parent views. Then, the child view, should put its content between <%# section-name(start) #%>
and <%# section-name(end) #%>
.
Here is an example:
Suppose we have a view named 'layout' in chameleon.Views
with the following content.
<html>
<head>
<title>Chameleon</title>
<%# header #%>
</head>
<body>
<%# body #%>
<%# footer #%>
</body>
</html>
Now, we can define a view like 'home' this way:
<%@ lauout %>
Welcome to my humble personal website!
My Recent Photos
...
<%# header(start) #%>
<link href="/plugins/carousel.css" rel="stylesheet" type="text/css" >
<%# header(end) #%>
<%# footer(start) #%>
<script src="/plugins/carousel.js"></script>
<%# footer(end) #%>
Here is the output when 'home' view is rendered.
<html>
<head>
<title>Chameleon</title>
<link href="/plugins/carousel.css" rel="stylesheet" type="text/css" >
</head>
<body>
Welcome to my humble personal website!
My Recent Photos
...
<script src="/plugins/carousel.js"></script>
</body>
</html>
Note 1: start
and end
are reserved keywords. No other keyword is allowed.
Note 2: All sections are optional. If a child view does not specify content for a section, no error is raised.
Note 3: When executing views, child views are executed first, then their parent template.
Views can interact each other using view data. View data is stored in a table named chameleon._viewData
. Adding or reading a view data item is as simple as insert/select
on chameleon._viewData
. Pay attention that, in order to separate view data and preventing view data collision, using context_id
is necessary.
-- Adding a view data item named 'title'
insert into chameleon._viewData([context_id], [name], [value])
values (@context_id, 'title', 'Mywebsite: Home page')
-- Reading a view data item
declare @title varchar(100)
select @title = [value] from chameleon._viewData where [context_id] = @context_id and [name] = 'title'
Note: @context_id
is automatically passed to a view when it is being rendered by chameleon.RenderView
.
There is a helper SPROC named [chameleon].[ViewData.SetValue]
and a UDF function named [chameleon].[ViewData.GetValue]
that facilitate getting/setting view data items. Here is the signature of [chameleon].[ViewData.SetValue]
stored procedure:
create or alter procedure [chameleon].[ViewData.SetValue]
(
@context_id int,
@name nvarchar(300),
@value nvarchar(max),
@overwriteExisting bit
)
@context_id
: context_id of current web request.@name
: name of the view data item@value
: value of view data item@overwriteExisting
: whether or not to overwrite the view item if it already exists.And here is the signature of [chameleon].[ViewData.GetValue]
function.
create or alter function [chameleon].[ViewData.GetValue]
(
@context_id int,
@name nvarchar(300),
@default nvarchar(max)
)
Example:
-- Adding a view data item named 'title'
exec chameleon.[ViewData.SetValue](@context_id, 'title', 'Mywebsite: Home page', 1)
-- Reading a view data item
declare @title varchar(100)
set @title = chameleon.[ViewData.GetValue](@context_id, 'title', '')
Using view data, it is easy to put setting title of the page in a 'layout' view and let child views specify its value.
Example: 'layout' view:
<html>
<head>
<title><%=chameleon.[ViewData.GetValue](@context_id, 'title', '')</title>
<%# header #%>
</head>
<body>
<%# body #%>
<%# footer #%>
</body>
</html>
'home' view:
<%@ lauout %>
<%
exec chameleon.[ViewData.SetValue](@context_id, 'title', 'Mywebsite: Home Page', 1)
%>
...
Here is the output when 'home' view is rendered.
<html>
<head>
<title>Mywebsite: Home Page</title>
</head>
...
Note: As setting title of a web page is a frequent task, an explicit stored procedure and function for getting/setting 'title' are already defined. So, the above example could be simplified this way:
'layout' view:
<html>
<head>
<title><%=chameleon.[ViewData.GetTitle](@context_id, '')</title>
<%# header #%>
</head>
<body>
<%# body #%>
<%# footer #%>
</body>
</html>
'home' view:
<%@ lauout %>
<%
exec chameleon.[ViewData.SetTitle](@context_id, 'Mywebsite: Home Page')
%>
...
There are other view data getter functions that help getting a view data and casting it to a specific type. Here are the list of these view data get helpers.
chameleon.ViewData.GetBoolean
chameleon.ViewData.GetByte
chameleon.ViewData.GetDate
chameleon.ViewData.GetDateTime
chameleon.ViewData.GetDateTime2
chameleon.ViewData.GetFloat
chameleon.ViewData.GetInt16
chameleon.ViewData.GetInt32
chameleon.ViewData.GetInt64
chameleon.ViewData.GetMoney
chameleon.ViewData.GetTime
Parameters of all of these function are the same as chameleon.[ViewData.GetValue]
with the difference that their @default
parameter is of data type that they are returning.
Gila
view engine has a few configuration options that can be customized.
By default when chm.GilaCompile
is invoked, it refers to a settings key named Chamaleon.ViewEngine.Gila
in chameleon.Settings
table. The setting is expected to be in JSON format. GilaCompile
tries to deserialize given JSON setting into a GilaViewEngineConfig
which is defined in Chameleon.Core
. List of properties of this class is as follows:
Property | Type | Description | Default |
---|---|---|---|
ParamsPrefix
|
string
|
This prefix is added before the name of variables that Gila uses in the T-SQL code it generates. By default it equals to two underscore __ . |
__
|
IncludeComments
|
bool
|
This setting reflects comments of Gila syntax in the generated T-SQL. By default it is false . |
false
|
SkipExcessiveNewLines
|
bool
|
When this setting is true Gila ignores content that are equal to a newline (\n , \r , \n\r , \r\n ). By default it is true . |
true
|
SectionsTable
|
This setting specifies name of the sections table into which section contents will be inserted. |
chameleon._sections
|
For example, in order to reflect comments into the generated compiled content of a view, we can use the following value for Chamaleon.ViewEngine.Gila
setting.
{ "IncludeComments": true }
Gila
's rules can be summarized in the following code:
<%@ main-layout %>
<%**
comment
**%>
<%
...
set @a = [value] from openjson(@model)
%>
..
Hello <%='ali'%> HtmlEncode
Bold Tag is <%#='<b>'%> Raw Write
Bold Tag is <%~='<b>'%> HtmlDecode
<%!='ali reza'%> FullUrlEncode
<%?='http://a.b/?name=ali reza'%> UrlEncode
<%$='...'%> md5
<%^='ali%20reza'%> FullUrlDecode
<%&='http://...'%> UrlDecode
<%:='...'%> base64Encode
<%.='...'%> base64Decode
<%*=products(@model)%> Rendering Partial-Views
<%#header(start)#%> Using Sections
<%#header(end)#%>