Building an Application -- WIKI Edition

By

November 26, 2008

Starting Small

Create the Tables

To get started, begin with the notion that the Wiki is nothing more than a single table with a few columns tracking the Content.To begin, lets assume we will need the following columns: WikiID - the primary key of the table, which will be stored as an integer, and will be autonumbered. Title - the visually provided title for the topic, stored as a string with a maximum length of 255. Topic - the physical reference topic value to be used when linking between topics. The syntax of this will be discussed later. This will be a string with a character length of 50. Content - the content of the wiki article, stored as a string with an unlimited length. To create the table, execute the following code:

CREATE TABLE [OWS_Wiki](
	[WikiID] [int] IDENTITY(1,1) NOT NULL,
	[Title] [nvarchar](255) NULL,
	[Topic] [nvarchar](50) NULL,
	[Content] [ntext] NULL
)

Create the View

Now with the table in place, create a new Open Web Studio configuration and get busy building. Click New on the Ribbon, starting the initial template. Click the General tab and give the configuration a name, like "My Wiki". Press Save.

Topic Variable

To start, we will assume that the topic which is to be viewed will be a variable value provided in the Querystring. This will be consumed without our queries throughout the project, and is best created as a global query variable high up in our code tree. Expand the Region - OnLoad, followed by Region - Query Variables - each of which are simply place holders, logically organizing the code structure. Feel free to clear out the current members of this region, as they are place holders used to demonstrate what actions should appear within this section by default. With the Region - Query Variables selected - click the Actions tab on the ribbon, and then choose the Variable action. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Variable Type - Source - Topic Target - @Topic Target Left - ' Target Right - ' Empty Target - NULL Security - Escape Single Quotes, Escape HTML Symbols, Escape code tags ONCE This means that a variable from the QueryString with the name "Topic" will be utilized by our queries. Whenever "@Topic" appears in our queries, it will be replaced with the value from the QueryString with a single quote appearing to the left and right side of the value. If this variable is not present in the QueryString, or it is has a lenght of zero - NULL will be the resulting value assigned to @Topic. Finally - the resulting value will escape single quotes, html symbols and script syntax.

View Template

Now that the variable is in place, a template and query must be provided for viewing the contents of our table. Expand the Region - OnRender, with Region - OnRender selected, click the Template Action from the Actions tab on the Ribbon. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Template - Query Content - Select * from OWS_Wiki where Topic=@Topic This will act as our Template Query, meaning that the physical output of our Open Web Studio configuration will be bound to the query provided above. Notice that it is consuming the variable we created in the previous step. Next, click the Template Action from the Actions tab on the Ribbon. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Template - Detail Content -
<h1>[Title]</h1><br />[Content]
This will act as our complete template, which will be bound the the Query provided in the previous step. The output of this is simple, just a header with the value of the Title column from our query, followed by a line break and then the Content column of our table.

Create the Editor

Publishing at this time will provide a very rudimentary view for our Wiki content. Before we go down the road of viewing and testing the content - we definitely need a way to create content! This simple interface will extend a bit of the logic we already have in place, and provide a very easy interface for conducting both the Add and Edit operations. Keep in mind as you follow along that the logic used here is the standard approach that you should take for most of your configurations.

Modify the View

First, modify the View template from the previous step by double clicking on the previously added Detail Template. We will be adding two links with a bit of formatting to the top of the View so that you can easily Edit the current topic or jump to a new topic. With the last line being the original line from the previous step, the content line will now read:
<div>
	<a href="?topic=[topic,q]&action=edit">edit</a>
	&nbsp;|&nbsp;
	<a href="#" onclick="var ntopic = prompt('What topic would you like?'); if (typeof ntopic != 'undefined') 

{window.location='?topic='+ntopic.replace(/[^w]+/g,'_');} return false;">To jump to another topic, click here.</a>
</div>
<hr />
<h1>[Title]</h1><br />[Content]
Now, let's disect this content a bit and describe exactly what it provided. First, a div tag is provided to break up the physical logic of the layout. Next, an anchor tag edit was added. Now, when we click on the Edit link, the current topic, from the querystring, will be posted back to the server, along with another variable, called "action" with the value "edit". In the next step we will provide the handling for this interaction - yeilding an edit form for adding and editing records in the system. Finally, we added a simple javascript prompt window. When clicked, the user will get the message "What topic would you like?", and following a provided value and "Ok", the window will post back to the server with the topic set to the provided topic value - stripped of any whitespace or symbolic characters and instead replacing them with a single underscore. Press Save, and continue with the editing.

Consuming the QueryString Parameter - Action

To begin consuming the incoming querystring parameter "action", first let's review the exact utilization of this parameter. While it is not something specific to Open Web Studio, as it can truly be named anything, the structure which will be provided here is the standard practice for most interaction, regardless of whether ajax is utilized or not. The basic runtime will be the result of a set of If conditions, each of which will operate on the incoming condition of the querystring parameter "Action". The default condition, or Else, will be the general detail output which we have already created. To build your logic, start by adding an If condition from the Actions tab on the Ribbon. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Condition Type - Standard Left Condition - [action,q] Comparison - = Right Condition - edit Therefore, whenever the Querystring Parameter "action" has the value of "edit", this tree section will be executed. Next, at the same level in the tree as our If condition, we need to add an "Else" condition. Add an Else condition from the Actions tab on the Ribbon. There are not any properties provided for "Else", but it is the default behaviour whenever the previous If conditions are not met. Now, move the current Query Template and Detail Template which were created in the previous step into the Else condition. Select the If condition, "If [action,q]=edit", and add a new Template Action from the Ribbon. This query is actually exactly the same as the detail query, we are operating off the topic from the querystring, as was anticipated. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Template - Query Content - Select * from OWS_Wiki where Topic=@Topic Next, click the Template Action from the Actions tab on the Ribbon. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Template - Detail Content -
<input id="frmWiki" name="frmWiki" type="hidden" value="[wikiid]"/>
<table width="100%" cellspacing="0" cellpadding="0">
<tr>
	<td width="50" class="SubHead">Title</td>
	<td width="100%">
		<input id="frmTitle" name="frmTitle" style="width:100%;" value="[COALESCE,title,,{ENCODEHTML}]"/>
	</td>
</tr>
<tr>
	<td width="50" class="SubHead">Topic</td>
	<td width="100%">
		<input id="frmTopic" name="frmTopic" style="width:100%;" value="[COALESCE,topic,,{ENCODEHTML}]"/>
	</td>
</tr>
<tr>
	<td colspan="2">
		{TEXTEDITOR,frmContent,Content,,100%,400}
	</td>
</tr>
<tr>
	<td colspan="2" align="center">
		<button onclick="document.forms[0].submit();">Save</button><button onclick="history.go(-1);">Cancel</button>
     	</td>
</tr>
</table>
Now, let's digest this a bit, as you can see we consumed a few different type of tokens here. First, we provided an Input element named "frmWiki". Pay close attention throughout this developement that both the name and id are always provided for form elements. The explanation for this is fairly simple - the name attribute is the specific reference of the variable when it is consumed by the server, while the id is the attribute that is the specific reference for the object by the javascript on the client. Even when the configuration doesn't require any javascript, it is always best practice to provide both - especially with OWS. The "frmWiki" element is set to be a hidden element on the form, which will hide it from view, but it will be received when you press Save. The purpose of this, even though we have "topic" in the querystring is a bit of a match-up constraint. We are simply going to use this to verify that the current topic being edited matches the anticipated topic value which is received by the querystring. Below the hidden input element containing the primary key of the record, a simple card view style edit form is provided. The first row contains the Title input element, a text field with a width that will span with horizontal length of the page. It's value is the Title column retrieved from our Query. The COALESCE token has been used here to provide a quick inline formatting of our value, encoding any HTML formatting contained within it so that characters like less-than and greater-than will appear in plain text. Again, this is a standard practice. The next line in the table contains the Topic input element, which follows the exact same behaviour as title. Following this is the row containing the Content of our topic. This content is contained within the Content column, and is provided visually within a Rich Text Editor by employingthe TEXTEDITOR token. The parameters of this are very basic. The first is the name/id of the element as it will appear in the Form, the next two parameters are the name and source of the value to be displayed within the editor. In this case the Content column, and the default source which is the Query result. The last two parameters are the Width and Height of the editor, in this assignment 100% wide and 400 pixels tall. The last line of the table contains our Submit and Cancel buttons. To submit we are merely submitting the form back to the server. To cancel, we are using the javascript history object, passing negative one will revert back one page in the history. This will act as our complete template for the Edit, which will be bound the the Query provided in the previous step. Now, we need an Add form, which will automatically be displayed when No Records result from the Query. To do this, click the Template Action from the Actions tab on the Ribbon. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Template - Detail (No Results) Content -
<table width="100%" cellspacing="0" cellpadding="0">
<tr>
	<td width="50" class="SubHead">Title</td>
	<td width="100%">
		<input id="frmTitle" name="frmTitle" style="width:100%;" value="[COALESCE,topic,q,{ENCODEHTML}]"/>
	</td>
</tr>
<tr>
	<td width="50" class="SubHead">Topic</td>
	<td width="100%">
		<input id="frmTopic" name="frmTopic" style="width:100%;" value="[COALESCE,topic,q,{ENCODEHTML}]"/>
	</td>
</tr>
<tr>
	<td colspan="2">
		{TEXTEDITOR,frmContent,frmContent,Form,100%,400}
	</td>
</tr>
<tr>
	<td colspan="2" align="center">
		<button onclick="document.forms[0].submit();">Save</button><button onclick="history.go(-1);">Cancel</button>
     	</td>
</tr>
</table>
Notice that only a few lines differ from the Detail Template. In this case, we won't have a result from the Query - so the "frmWikiID" value will not be provided. The Title and Topic values are now retrieiving their defaults from the parameter coming from the querystring. And finally, the Text Editor default value will be provided by the "frmContent" Form variable itself. In this demonstration we don't have any server side validation - but this would be utilized when that is provided, being that the server received the posted values, but they require modification so the form is redisplayed with those values in place.

Saving the Record

Now that the form is in place, it's time to save the incoming value. When the save button is clicked, as specified in the previous step, the form will be posted back. Keep in mind that also present during the post back are the topic and action parameters from the querystring. With action set to "edit". Again, we need to provide additional functionality to extend what we have done within a previous step. Now, within the condition checking when "action" from the querystring is equal to "edit", add both an If and ELSE condition. Move all the existing steps within the action to be children of the ELSE condition. The If condition will check to see if "frmContent" has been received from the form, and if so - Save the record. With the newly added IF condition - set the parameters to the following: Condition Type - Standard Left Condition - [COALESCE,frmContent,Form,{LENGTH}] Comparison - > Right Condition - 0 In this case, as before, the COALESCE token is being used to format an incoming value. In this case, when the form variable named "frmContent" has a length greater than zero, the IF condition is entered. With the If condition selected - click the Actions tab on the ribbon, and then choose the Variable action. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Variable Type -

Source - frmWiki Target - @frmWiki Target Left - ' Target Right - ' Empty Target - -1 Security - Escape Single Quotes, Escape HTML Symbols, Do not escape code tags With the If condition selected - click the Actions tab on the ribbon, and then choose the Variable action. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Variable Type - Source - frmTopic Target - @frmTopic Target Left - ' Target Right - ' Empty Target - '' Security - Escape Single Quotes, Escape HTML Symbols, Escape code tags ONCE With the If condition selected - click the Actions tab on the ribbon, and then choose the Variable action. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Variable Type - Source - frmTitle Target - @frmTitle Target Left - ' Target Right - ' Empty Target - '' Security - Escape Single Quotes, Escape HTML Symbols, Escape code tags ONCE With the If condition selected - click the Actions tab on the ribbon, and then choose the Variable action. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Variable Type - Source - frmContent Target - @frmContent Target Left - ' Target Right - ' Empty Target - NULL Security - Escape Single Quotes, Escape code tags TWICE Now that all the variables are in place, add a Query Action from the Actions tab on teh ribbon. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Name - ADD/UPDATE Query -
if @frmWiki > 0
begin
	UPDATE OWS_Wiki set Content=@frmContent, Topic=@frmTopic, Title=@frmTitle
	where WikiID=@frmWiki
end
else
begin
	INSERT INTO OWS_Wiki(Title,Topic,Content)
	VALUES( 
		@frmTitle,
		@frmTopic,
		@frmContent
	)
end
As you can see from the query, this operation handles both the Add and Update operations by first checking to see if the form variable "frmWiki"" contains a value > 0. Finally, a No Query Detail Template is required to provide confirmation output of the Saved record, since no other detail will be reached based on the branching structure. To do this, click the Template Action from the Actions tab on the Ribbon. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Template - Detail (No Query) Content -
<center>Thanks!</center>
<script type="text/javascript">
document.location = "?topic=[topic,q]";
</script>
As provided by this interface, the client will see this message briefly, and then the topic will redirect to the topic present in the querystring. This is to provide both a redirection back to the View of the record, but also reduce the chances that a Save may be commited again if the user presses refresh and posts the contents to the server aghain.

Make It A Wiki

Now that we are storing and displaying the content - let's actually turn it into a Wiki. This is really a basic idea and a simple task - all we need to do is manipulate the content that is provided by parsing out its Wiki Syntax and converting it into links and other general layout elements. Now you may be concerned, thinking to yourself, "But he said it would be a simple task!". Don't fret, the task is very simple - Open Web Studio provides a formatter for this task explicitly! Before we get ahead of ourselves, we first need to make an adjustment to the table - by adding a column which will contain the newly adjusted content. This essentially acts as a Cache, so that the encoding doesn't need to be performed whenever the page is requested,but rather when the record is saved. We will call this column "Cache", and add it by executing the following statement.
ALTER TABLE [OWS_Wiki] ADD [Cache] [ntext] null
Next, we need to integrate this column in to the individual aspects of the application. Modify the Detail Template for the standard output (ELSE Condition) replacing the Content field with the Cache field. Next, add one Variable to the If condition when a Save is going to occur. With the If condition selected - click the Actions tab on the ribbon, and then choose the Variable action. Double click the newly added action to provide the property window. Assign the following settings to the properties, and press Save: Variable Type - Source - [COALESCE,@frmContent,Form,{ENCODEWIKI},{ESCAPE}] Target - @frmCache Target Left - ' Target Right - ' Empty Target - NULL Security - Escape Single Quotes, Escape code tags TWICE The EncodeWiki formatter, provided in the previos COALESCE will do the trick. Variable Type of custom was employed because a custom operation had to be performed on the value. Additionally, the ESCAPE formatter is employed here to keep any content produced as output from the form element will be ignored from the parsing engine. Finally, we are ready to store the content into the database. Modify the ADD/UPDATE query to read like the following:
if @frmWiki > 0
begin
	UPDATE OWS_Wiki set Content=@frmContent, Topic=@frmTopic, Title=@frmTitle, Cache=@frmCache
	where WikiID=@frmWiki
end
else
begin
	INSERT INTO OWS_Wiki(Title,Topic,Content,Cache)
	VALUES( 
		@frmTitle,
		@frmTopic,
		@frmContent,
		@frmCache
	)
end

Secure the Editor

Adding Features

History

Rating

ALTER TABLE [OWS_Wki] ADD Rating [float] null

Comments

 

Average (1 Ratings):
 
Want to help out?
 
 

New York, NY • Baltimore, MD • Vienna, VA • St. Louis, MO • Seattle, WA • 410.327.0007 • info@R2Integrated.com

Bookmark & Share Bookmark and Share