Sunday, November 29, 2009

Inhibit column titles if no records

Just 'discovered' another Alpha Five V10 cool feature - "supress column titles if no records". It's in the Column Titles and Sorting Options section of the Grid Properties. Neat because it has always looked messy and out of context to have a row of column titles with no values under them. Once the grid has at least one record, the column titles then appear.


Sunday, October 18, 2009

Quick way to 'check/uncheck all checkboxes'

I needed to allow my client to 'check/uncheck' all boxes in a multi-row grid. I found this very convenient code that creates a hyperlink to do simply that; add the link anywhere on the A5W page. Only thing, it checks/unchecks ALL boxes on the page, so it is only useful if you have just ONE group of checkboxes on your page.

<a href="javascript:(function(){%20function%20toggle(box){%20temp=box.onchange;%20box.onchange=null;%20box.checked=!box.checked;%20box.onchange=temp;%20}%20var%20x,k,f,j;%20x=document.forms;%20for%20(k=0;%20k<x.length;%20++k)%20{%20f=x[k];%20for%20(j=0;j<f.length;++j)%20if%20(f[j].type.toLowerCase()%20==%20%22checkbox%22)%20toggle(f[j]);%20}%20})();">Check All</a>

Wednesday, October 14, 2009

How to keep track of session variables in a web app

Almost every web application requires multiple session variables that need to be DIM'd and set to a value. A typical example might be setting "session.clientname" to the logged in user's first and last name, for convenient use when you want to display their name on a web page. Other variables are more important, like the logged-in users personal ID (commonly called the ULINK in Alpha web apps) so you can filter out just their records, and perhaps a Company_ID in a multi-tier application where you need to know their Company affiliation while logged in.

I have a standards set of session variables that go into each web app, ones I use all the time. Those are easy to keep track of, I know them by heart. But every web app also needs a host of session variables that are unique to this application. I devised the following method both to keep track of these unique session variable names and also to make it easier for me to add them as I build the application.

The normal process for adding a session variable is to add some Xbasic code either right where you first need the variable, or in a header type file that is included on ALL web pages. The later method ensures the variable is repopulated every time any page is refreshed. There is a reason you might want this, but I won't go into it right here.

Being data-driven to a fault, I now keep all of these extra session variables in a table, and use Xbasic to extract the information from that table in order to DIM and populate the value. I include a convenient checkbox to indicate if the variable is 'protected' or normal. "Protected session variable" is a term unique to Alpha Five.

Hint: click on the images below to get a larger view. If you cannot read all of the text, click this link to get it in a text file. You can also click on the image to get a larger view.

Here is the table structure:



And here is some representitive data for the table. Note that the 'expression' is normal Xbasic, exactly what you might enter directly on the A5W page to populate your variable. If you check 'Protected' it will automatically insert the text required to make the variable protected. If you include a 'Footer_ID' the current value for this variable will appear in the footer of your web application, which is good for debug purposes while you are testing the application online.


Here is the Xbasic on an A5W page I have named header_setvar.a5w. Note that there is NO HTML on this page, just the requried Xbasic. Note that I use 'evaluate_template()' to extract the information from the table. If I don't include that, the results just appear as normal text in the browser, not fired as Xbasic.

Here is the Xbasic on the individual pages to include this header_setvar.a5w. Typically this would go at the top of every A5W page. In reality, I do not place this header_setvar.a5w on individual pages, I include it another page named header_head.a5w, and that page is included on all other pages. But that is personal preference. Just the line that starts with A5W_Include is imporant here.



Here is the Xbasic that goes in the Footer.A5W page to be able to display the values for each of my session variables while testing the application. In the image below, I included some extra code that shows how I can toggle this 'debug' information off and on while online; that is the initial IF-ENDIF statement. The lines you care about to show the session variables are the two lines starting with dta3.



And here is what the footer actually looks like. It may appear to be nonsense to you, but it tells me exactly what is going on in terms of who is logged in and how that has affected the session variables. This is invaluable data while testing. When I go live, I toggle this debug information off.


Sunday, August 30, 2009

Positioning Login and toggle to show Logged-In username

This article shows how to position a Login component on a web page, and then toggle this area to show who is logged in.

The method described below requires some skill with CSS and the ability to work in the source area of an A5W page, editing HTML and XBASIC code.

This is the desired effect. A clean login component area with fields for Username, Password and also links to recover the password and "Remember Me" to allow the user to store their login for subsequent visits.

We also need to provide room for any error messages such as incorrect password, not a valid email address, etc.

And when the user has logged in, we want to hide the login fields and instead show the users name, a logout link and any information or links that pertain to their logged-in status. This is important as it indicates to the user that they are logged in.

We start with a graphic, called header.jpg in this article. Our image has a nice clearly defined login area to the right, about 110x230px with rounded edges. Our login dialog will be superimposed over this area using CSS.

Out of the box, the Alpha Five Login dialog takes up a bit too much real estate, so we need to use the Freeform area of the Login Dialog maker to reduce this. In the image below, the normal state is shown in the upper right, the desired version is in the lower left.


And here is a WYSIWYG view of the Freeform area, showing how we used a table to align the labels and flatten it just a bit for less overall vertical space.
In addition, we need to shorten several of the stock error messages. Remember, they have to fit in the graphic area I have provided. If they are too long, the message will wrap to a second line, and I just don't have room in the area I have provided. The image below shows where you can edit the Login dialog's error messages.
Insert the graphic header.jpg image where desired. Here is the CSS code I use to insert the header graphic.

#logo{
height:150px;
position:relative;
background-image: url(../images/header.jpg) ;
background-repeat:no-repeat;
}
Side note - I happen to use a header.a5w* at the top of every single page in a given web application. So, I only perform this operation once, in header.a5w. And then I use the a5w_include() function to place my header at the top of other pages in my web application.

Insert the login dialog in the A5W page.

First I create a DIV with ID=loginarea and place the normal Alpha Five login dialog code within this DIV. That's the two lines after the ELSE in the image below. Remember I also want to toggle this area when the person logs in, to show that they are logged in. So within this DIV I include an IF-ELSE-ENDIF statement.

The area above the ELSE defines the condition that someone IS logged in and shows their name and several links that would only be of use to someone who is logged in. The area below the ELSE is the normal login dialog code produced by Alpha Five when the login dialog was inserted. The only change I made was to move the line "?x_login.Output.Body.Login_Errors" below the line "?x_login.Output.Body.Login_HTML" because I happen to want my error messages to appear below the login dialog. I also used HTML 'strong' tag to highlight the error message.
Here is the section of my style sheet to format the loginarea DIV.

#loginarea{
left:0px;
top:0px;
position:absolute;
font-size:xx-small;
}

#loginarea .noneInput{
font-size:xx-small;
}

The selector is for positioning. I've chosen absolute positioning which means my loginarea DIV will be superimosed or "floating" on top of the previous DIV, my header logo. As I change the values for the left and top properties, the loginarea div will move from its default position to exactly where I want it to appear, to the far right. I also have set a property to reduce the font size in this area.

To exactly position the DIV, I use a Firefox add-on named Firebug. Here is a quick video showing how the DIV is positioned using the left and top properties: http://www.sqst.com/video/css_absolute_positioning.htm.

The second selector is used to also reduce the size of the data-entry field. This alters the font size for the class named "noneInput" which is provided by Alpha Five. I don't want to alter the size for all instances of the noneInput class, just those within the loginarea DIV.

Footnote

* I don't want to go in to it here, but I actually do not have just ONE header.a5w inserted using a5w_include(). I break my header in to two files, header_head.a5w and header_body.a5w. The first file contains only the portion of a normal A5W page that would be found in side the head tags, and the later contains only the portion that is found just past the body tag.

To help clarify, here is my basic page layout:

Thursday, February 26, 2009

Determine who's logged in

It's a common problem for a developer -- you need to reboot or reset your Alpha Five Application Server but you have one or more live applications running. If you reset the server when someone is only browsing, not too big a deal, they can continue to browse after a brief moment and may not even notice that you reset the server*. But if someone is logged in doing legitimate work, you dare not reset the server. They will lose all of their session variables and have to log back in. If they were in the middle of something important, you may have helped to create orphaned or incomplete records.

* This may not be true if have code that relies on the existence of a particular session variable or makes use of the physical session folder.

Alpha Five provides a function to count the active sessions, but that does not help because it really just counts the number of session folders. A typical web server may have dozens of session folders even if no human is viewing any page. Bots and your work as a developer will cause many session folders to be created.

So I needed to be able to know, at any moment, who is logged in. From that information I can make an intelligent decision if I can reset the server or have to wait.

When a Bot or human visits your website, a session folder is always created. I added some code to my Login.A5W page that placed a specific file in that session folder when the person logs in. The file has a particular name structure such that I can tell, just by looking at the filename, who is logged in. The file name looks like this:

loggedin__0847__admin_sqst_com__alphatogo_com_81.txt

It says that user "admin@sqst.com" logged in to website "alphatogo.com" on port 81 at 8:47AM.

To view this information, I created an A5W page that lists all of the files in all of my session folders with the name "loggedin_*.txt. Here is an example of that list. It shows the count of all session folders, the current server time, and the logged in users, three in this case:

Sessions: 22
Current__0952
loggedin__0847__admin_sqst_com__alphatogo_com_81.txt
loggedin__0949__cswatson_sentara_com__pdms_alphatogohost_com_81.txt
loggedin__0922__salesmanager_sqst_com__pdms_alphatogohost_com_81.txt

Since I know WHO is logged into WHAT application, I can make an intellegent decision on resetting the server.

If the person logs out or their session expires, that file will automatically disappear. You could enhance this by adding code on EVERY page that updated this filename showing the most recent screen refresh. I just show the original logged in time in my example.

CODE on the LOGIN.A5W page:
if eval_valid("submitbutton")
if eval_valid("userid")
dim session.__protected__userid as c
session.__protected__userid = userid
dim hst as c hst = alltrim(request.host)
filename = "loggedin"
filename = filename + "__" + time("0h0m")
filename = filename + "__" + userid
filename = filename + "__" + hst
filename = stritran(filename,".","_")
filename = stritran(filename,"@","_")
filename = stritran(filename,":","_")
filename = filename + ".txt"
save_to_file("loggedin",session.session_folder + filename)
end if
end if

CODE on the whosloggedin.A5W page:
?"Sessions: " + str(a5_count_websessions()) + "<br>"
?"Current__"+time("0h0m") + "<br>"
fpath = serversetting.document_root + "\session_folders"
filelist = filefind.get_recurse(fpath,"loggedin_*.txt",FILE_FIND_NORMAL,"N" + crlf())
dim lst as c = ""
for each foo in filelist
lst = lst + foo.value + "<br>"
next
?lst

Monday, January 19, 2009

Adding reports to the web without affecting data

Q: If you have an existing Alpha Five web application and create or edit an existing report, how do you get the new report up to the web without disturbing the existing data?

A: After you create or edit a report, three files will have been updated in your Alpha Five project for each table affected: ddd, ddm and ddx. Publish these three files up to the server using a 3rd party FTP software. Alpha's publishing option will not publish just these files. You DO NOT want to re-publish the dbf file since that will overwrite all of your data online.

At this time the report definitions should immediately be available to your web application.