Wednesday, May 20, 2009

Upload user specific images in FCK Editor of DNN

Question:I would like to be able to let users upload their pictures through the editor "FCKConfig.ImageUpload=true" but i want each user that logs in to be able to upload to their assigned areas for instance, if user1 logs in then when he uploads a picture he would upload it to the user1 in the web server and then when he browses for all pictures using fckeditor he would only be able to see the pictures under the user1 folder.

Answer:If you want to be able to set the file browsing and uploading path on the fly for each user or group you will have to use the Application("FCKeditor:UserFilesPath") variable for FCKeditor on the Page_Init event. You can also use the Session("FCKeditor:UserFilesPath"), as a matter of fact, that is what the fckeditor documentation suggests. However, with dotnetnuke i couldnt get it to work properly using the session variable so instead I used the "Application" call, i think that this is the equivalent of using the web.config except that you are doing it dynamically. Anyhow, below is an example of how I am doing it in my site, notice that I am just checking the user name for the current logged in user, I am not checking group memberships like you want:

Protected Sub Page_Init
(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
Try
Dim userCtrlr As New UserController
Dim user As UserInfo = userCtrlr.GetUser(PortalId, UserId)
Application("FCKeditor:UserFilesPath") =
Page.ResolveUrl("~/Portals/" & PortalId.ToString & "/Userfiles/FlyerImgs/" &
user.Username & "/")
Catch exc As Exception 'Module failed to load
ProcessModuleLoadException(Me, exc)
End Try
End Sub


Make sure that you are using the "Page.ResolveUrl" otherwise the application will have problems converting the image path, and the image will not display properly.


Ref: http://www.dotnetnuke.com/Community/Forums/tabid/795/forumid/127/threadid/158276/scope/posts/Default.aspx

Wednesday, May 6, 2009

Urdu textbox JS file

Download js file directly.

http://justcsharp.googlepages.com/urdueditor.js

Urdu Textbox

JS file:
http://justcsharp.googlepages.com/urdueditor.js

Editor Initialization:

Initialize Editor before textbox.

initUrduEditor("");


TextBox:

input type="text" onfocus="setEditor(this)" style="font-family: Urdu Naskh Asiatype; font-size: 14px;" id="Editor" name="Editor" lang="ur"

Friday, April 24, 2009

Restrict Web Page access based on MAC / IP

This solution is a combination of .Net / Java applets. Java Applet is used to get the MAC from the client machine and then it is sent back to the server and there it will be used to restrict the client access or grant it access based on the ACL (Access Control List) defined in the XML.

Java Applet to Get MAC Address :

import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.ArrayList;
import java.applet.Applet;

public class MacAddressApplet extends Applet
{
public static String sep = ":";
public static String format = "%02X";

/**
* getMacAddress - return the first mac address found
* separator - byte seperator default ":"
* format - byte formatter default "%02X"
*
* @param ni - the network interface
* @return String - the mac address as a string
* @throws SocketException - pass it on
*/
public static String macToString( NetworkInterface ni ) throws SocketException
{
return macToString( ni, MacAddressApplet.sep, MacAddressApplet.format );
}

/**
* getMacAddress - return the first mac address found
*
* @param ni - the network interface
* @param separator - byte seperator default ":"
* @param format - byte formatter default "%02X"
* @return String - the mac address as a string
* @throws SocketException - pass it on
*/
public static String macToString( NetworkInterface ni, String separator, String format ) throws SocketException
{
byte mac [] = ni.getHardwareAddress();

if( mac != null ) {
StringBuffer macAddress = new StringBuffer( "" );
String sep = "";
for( byte o : mac ) {
macAddress.append( sep ).append( String.format( format, o ) );
sep = separator;
}
/* My extra Code for Vista*/
if (macAddress.length ()! = 0)
(
macAddress.toString return ();
)
/* End of patch*/
return macAddress.toString();
}

return null;
}

/**
* getMacAddress - return the first mac address found
*
* @return the mac address or undefined
*/
public static String getMacAddress()
{
try {
Enumeration
nis = NetworkInterface.getNetworkInterfaces();

// not all interface will have a mac address for instance loopback on windows
while( nis.hasMoreElements() ) {
String mac = macToString( nis.nextElement() );
if( mac != null )
return mac;
}
} catch( SocketException ex ) {
System.err.println( "SocketException:: " + ex.getMessage() );
ex.printStackTrace();
} catch( Exception ex ) {
System.err.println( "Exception:: " + ex.getMessage() );
ex.printStackTrace();
}

return "undefined";
}

/**
* getMacAddressesJSON - return all mac addresses found
*
* @return a JSON array of strings (as a string)
*/
public static String getMacAddressesJSON()
{
try {
String macs [] = getMacAddresses();

String sep = "";
StringBuffer macArray = new StringBuffer( "['" );
for( String mac: macs ) {
macArray.append( sep ).append( mac );
sep = "','";
}
macArray.append( "']" );

return macArray.toString();
} catch( Exception ex ) {
System.err.println( "Exception:: " + ex.getMessage() );
ex.printStackTrace();
}

return "[]";
}

/**
* getMacAddresses - return all mac addresses found
*
* @return array of strings (mac addresses) empty if none found
*/
public static String [] getMacAddresses()
{
try {
Enumeration
nis = NetworkInterface.getNetworkInterfaces();

ArrayList
macs = new ArrayList();
while( nis.hasMoreElements() ) {
String mac = macToString( nis.nextElement() );
// not all interface will have a mac address for instance loopback on windows
if( mac != null ) {
macs.add( mac );
}
}
return macs.toArray( new String[0] );
} catch( SocketException ex ) {
System.err.println( "SocketException:: " + ex.getMessage() );
ex.printStackTrace();
} catch( Exception ex ) {
System.err.println( "Exception:: " + ex.getMessage() );
ex.printStackTrace();
}

return new String[0];
}

/**
* getMacAddresses - return all mac addresses found
*
* @param sep - use a different separator
*/
public static void setSep( String sep )
{
try {
MacAddressApplet.sep = sep;
} catch( Exception ex ) {
// don't care
}
}

/**
* getMacAddresses - return all mac addresses found
*
* @param format - the output format string for bytes that can be overridden default hex.
*/
public static void setFormat( String format )
{
try {
MacAddressApplet.format = format;
} catch( Exception ex ) {
// don't care
}
}

public static void main( String... args )
{
System.err.println( " MacAddress = " + getMacAddress() );

setSep( "-" );
String macs [] = getMacAddresses();

for( String mac : macs )
System.err.println( " MacAddresses = " + mac );

setSep( ":" );
System.err.println( " MacAddresses JSON = " + getMacAddressesJSON() );
}
}


Java Applet to Get OS Version :

import java.net.*;

public class GetOSName extends java.applet.Applet {
public String OSName;
public String Vendor;
public String URL;
public String Version;
public String OSArch;
public String OSVersion;

URL location;
public void start() {
Vendor = System.getProperty("java.vendor");
URL = System.getProperty("java.vendor.url");
Version = System.getProperty("java.version");
OSArch = System.getProperty("os.arch");
OSName = System.getProperty("os.name");
OSVersion = System.getProperty("os.version");
}

public String getOSName() {
OSName = System.getProperty("os.name");
return OSName;
}


}


The above two applets are used in the CheckAccess.aspx file to get the MAC Address and then the page will autopost back with the MAC Address to the server.

CheckAccess.aspx File:

In this file add both applets and onload of page call the following functions to get the MAC address and then postback that form back to the server.

Add the both applets in the Page.

<!--[if !IE]> Firefox and others will use outer object -->
<embed type="application/x-java-applet"
name="macaddressapplet"
width="0"
height="0"
code="MacAddressApplet"
archive="macaddressapplet.jar"
pluginspage="http://java.sun.com/javase/downloads/index.jsp"
style="position:absolute; top:-1000px; left:-1000px;">
<noembed>
<!--<![endif]-->
<!---->
<object classid="clsid:CAFEEFAC-0016-0000-FFFF-ABCDEFFEDCBA"
type="application/x-java-applet"
name="macaddressapplet"
style="position:absolute; top:-1000px; left:-1000px;"
>
<param name="code" value="MacAddressApplet">
<param name="archive" value="macaddressapplet.jar" >
<param name="mayscript" value="true">
<param name="scriptable" value="true">
<param name="width" value="0">
<param name="height" value="0">
</object>
<!--[if !IE]> Firefox and others will use outer object -->
</noembed>
</embed>
<!--<![endif]-->



<!--[if !IE]> Firefox and others will use outer object -->
<embed type="application/x-java-applet"
name="GetOSName"
width="0"
height="0"
code="GetOSName"
archive="GetOSName.jar"
pluginspage="http://java.sun.com/javase/downloads/index.jsp"
style="position:absolute; top:-1000px; left:-1000px;">
<noembed>
<!--<![endif]-->
<!---->
<object classid="clsid:CAFEEFAC-0016-0000-FFFF-ABCDEFFEDCBA"
type="application/x-java-applet"
name="GetOSName"
style="position:absolute; top:-1000px; left:-1000px;"
>
<param name="code" value="GetOSName">
<param name="archive" value="GetOSName.jar" >
<param name="mayscript" value="true">
<param name="scriptable" value="true">
<param name="width" value="0">
<param name="height" value="0">
</object>
<!--[if !IE]> Firefox and others will use outer object -->
</noembed>
</embed>
<!--<![endif]-->

Script to Get MAC Address:


<script type="text/javascript">



var macs = {
getMacAddress : function()
{
document.macaddressapplet.setSep( "-" );
//alert( "Mac Address = " + document.macaddressapplet.getMacAddress() );
var myText = document.getElementById("txt_Mac");
myText.value = document.macaddressapplet.getMacAddress() ;

},

getMacAddressesJSON : function()
{
document.macaddressapplet.setSep( "-" );
document.macaddressapplet.setFormat( "%02x" );
var macs = eval( String( document.macaddressapplet.getMacAddressesJSON() ) );
var mac_string = "";
for( var idx = 0; idx < addresses = " + mac_string ); var myText = document.getElementById(" value =" mac_string;" style="font-weight: bold;">Hidden Fields:

<input type="text" value="" id="txt_Mac" runat="server" />
<input type="text" value="" id="txt_OS" />

Function to get MAC Adress depending on OS Version:

function GetMACAddress()
{
var OSName = document.GetOSName.getOSName();
var my_OS = document.getElementById("txt_OS");
my_OS.value = OSName;
if(OSName == "Windows XP")
{
macs.getMacAddress();
}
else
{
macs.getMacAddressesJSON();
}
}

Auto Postback functions:
function SubmitForm()
{
var myText = document.getElementById("txt_Mac");

if(myText.value.length > 0)
{
var jsVar = "http://localhost:2582/CheckAccess.aspx";
__doPostBack('callPostBack', jsVar);
}
}

CS file:


protected void Check_IP_MAC()
{
XPathDocument xpDoc = new XPathDocument("ACL XML File");
XPathNavigator xpNav = xpDoc.CreateNavigator();

//Gets the IP addresses from the file and compare it with the users IP

XPathExpression xpExpression = xpNav.Compile(@"/users/user/ip");
XPathNodeIterator xpIter = xpNav.Select(xpExpression);

string _userIP = Request.UserHostAddress.ToString();
string _userMAC = txt_Mac.Value;

bool _IPCheck = false;
bool _MACCheck = false;

while (xpIter.MoveNext())
{

if (xpIter.Current.Value == _userIP)
{
_IPCheck = true;
}

}

//Gets the MAC addresses from the file and compare it with the users MAC

xpExpression = xpNav.Compile(@"/users/user/mac");
xpIter = xpNav.Select(xpExpression);

while (xpIter.MoveNext())
{

if (xpIter.Current.Value == _userMAC)
{
_MACCheck = true;
}

}

//Sets the Session if the MAC / IP validates
if (_IPCheck == true && _MACCheck == true)
{
Server.Transfer("WEB PAGE LANDING FILE");
}
else
{
Server.Transfer("ERROR FILE");
}
}

Ref: http://techdetails.blogmatrix.com/:entry:techdetails-2008-02-11-0000/ , http://www.spiration.co.uk/post/1186/Java%20detect%20brower,%20JVM%20vendor,%20Java%20version%20etc

Tuesday, December 23, 2008

Support rich text with the Yahoo! User Interface Library

During a recent project, my team's task was to redesign a Web page that utilized an ActiveX control as a rich text editor. One goal of the project was to replace the ActiveX control with a more standardized approach. We chose to use the rich text editor available with the Yahoo! User Interface (YUI) Library. This week I examine using the YUI Library's Rich Text Editor.

YUI Library

The YUI Library is a set of utilities and controls in JavaScript, as well as CSS templates for building richly interactive Web applications using standard technologies such as DHTML, DOM scripting, and AJAX.

You can download the YUI Library 2.3.1 for free from SourceForge.net. The download allows you to install the libraries on a Web server. Another option is to use the library files directly from Yahoo! servers. Yahoo! provides an excellent overview of how to use its servers for applications implementing functionality via the YUI Library.

Rich Text Editor

A recent addition to the YUI Library is the Rich Text Editor. It is a user interface control that replaces the standard HTML textarea element. It allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images.

A critical feature of the Rich Text Editor is its toolbar, which provides access to various features like text formatting, color choices, and so forth. You may choose which toolbar features to include in an implementation via scripting. In addition, the toolbar is extensible via a plug-in architecture so that advanced implementations can achieve a high degree of customization.

Putting the Rich Text Editor to work

If you want to use the Rich Text Editor, it requires a YUI Library CSS skin to properly render the control. The following YUI Library files (CSS and JavaScript source files) are necessary to use the Rich Text Editor. The following lines reference the files on the previously mentioned Yahoo! servers, but you may use a local installation as well.

<!-- Skin CSS file --> 

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.3.1/build/assets/skins/sam/skin.css">

<!-- Utility Dependencies -->

<script type="text/javascript" src="http://yui.yahooapis.com/2.3.1/build/yahoo-dom-event/yahoo-dom-event.js"></script>

<script type="text/javascript" src="http://yui.yahooapis.com/2.3.1/build/element/element-beta-min.js"></script>

<!-- Needed for Menus, Buttons and Overlays used in the Toolbar -->

<script src="http://yui.yahooapis.com/2.3.1/build/container/container_core-min.js"></script>

<script src="http://yui.yahooapis.com/2.3.1/build/menu/menu-min.js"></script>

<script src="http://yui.yahooapis.com/2.3.1/build/button/button-beta-min.js"></script>

<!-- Source file for Rich Text Editor-->

<script src="http://yui.yahooapis.com/2.3.1/build/editor/editor-beta-min.js"></script>

The following base HTML is used to deliver the Rich Text Box, but you'll still need to add scripting to fully implement the control.

<body class="yui-skin-sam"> 

<textarea name="texteditor" id="texteditor" cols="50" rows="10">

This text will be displayed in the text area.

</textarea></body>

Now the cols and rows attributes of the HTML texarea element will be overridden by settings specified in the Rich Text Editor's script. The name assigned to the HTML textarea element is important, since it will be used in the JavaScript code when establishing the relationship between a textarea element and a Rich Text Editor.

Also, the class assigned to the HTML body element (yui-skin-sam) is used to visually format the Rich Text Editor control. This CSS skin is defined in the CSS file imported into the application (see previous list). The skin should be applied to the parent HTML element of the textarea element. In this case, the HTML body element is used, but it could be any element that contains the textarea.

Once the textarea has been defined along with the proper YUI Library files included in the page, the Rich Text Editor control must be rendered. The rendering is accomplished via JavaScript placed within the page. The script can be used to define various Rich Text Editor options such as the toolbar. As an example, I may use the following JavaScript to format our Rich Text Editor:

var rtf = new YAHOO.widget.Editor('texteditor', { 

height: '300px',

width: '522px'});

rtf.render();

This snippet establishes the height and width of the editor while declaring an instance of the Rich Text Editor. Also, it assigns the textarea called texteditor to the Rich Text Editor. The final line in the script actually causes the Rich Text Editor to display when it calls its render method.

When you use the Rich Text Editor control without any specifics about the toolbar, it results in the default behavior of including all toolbar features like text alignment, font face, font size, color, and so forth. You may choose to limit the toolbar options available to users.

The final example uses a Rich Text Editor, but the toolbar options are defined in the JavaScript code to render it. The following options are used:

  • The toolbar options are defined in its own variable. This is later used to instantiate the editor.
  • A title is assigned to the editor via the toolbar's titlebar property.
  • The collapse property signals whether the user may collapse/hide the toolbar.
  • The buttons property allows you to define the buttons displayed in the toolbar. In this example, buttons are displayed for text formatting as well as selecting colors.

Once the toolbar options are defined, a Rich Text Editor object is instantiated with the toolbar variable passed to it along with the HTML textarea element. The final step is to render the control. A complete list of options is available in the YUI Library API documentation.

<html><head> 

<title>Working with YUI Library Rich Text Editor</title>

<!-- Skin CSS file -->

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.3.1/build/assets/skins/sam/skin.css" />

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.3.1/build/fonts/fonts-min.css" />

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.3.1/build/container/assets/skins/sam/container.css" />

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css" />

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.3.1/build/button/assets/skins/sam/button.css" />

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.3.1/build/editor/assets/skins/sam/editor.css" />

<!-- Utility Dependencies -->

<script type="text/javascript" src="http://yui.yahooapis.com/2.3.1/build/yahoo-dom-event/yahoo-dom-event.js"></script>

<script type="text/javascript" src="http://yui.yahooapis.com/2.3.1/build/element/element-beta-min.js"></script>

<!-- Needed for Menus, Buttons and Overlays used in the Toolbar -->

<script src="http://yui.yahooapis.com/2.3.1/build/container/container_core-min.js"></script>

<script src="http://yui.yahooapis.com/2.3.1/build/menu/menu-min.js"></script>

<script src="http://yui.yahooapis.com/2.3.1/build/button/button-beta-min.js"></script>

<!-- Source file for Rich Text Editor-->

<script src="http://yui.yahooapis.com/2.3.1/build/editor/editor-beta-min.js"></script>

<style>

body { margin:0; padding:0; font-face: arial; font-size: 10pt;}

.yui-editor-container {z-index: 999;}

.editable {

border: 5px solid black;

argin-top: 100px;

margin: .25em;

float: left;

width: 350px;

height: 100px;

overflow: auto;

}

.textbox {

margin-left: 10px;

width: 100px;

height: 25px;

}

.label {

margin-left: 10px;

width: 50px;

height: 25px;

font-weight: bold;

}

</style></head>

<body class="yui-skin-sam">

<span class="label">First Name:</span><input type="text" name="firstName" id="firstName" class="textbox" /><br />

<span class="label">Last Name:</span><input type="text" name="lastName" id="lastName" class="textbox" /><br />

<textarea name="texteditor" id="texteditor">

Test within TextArea.

</textarea>

<script>

var toolbar = {

height: '200px',

width: '420px',

toolbar: {

titlebar: 'TechRepublic.com Editor',

collapse: true,

buttons: [

{ group: 'textstyle', label: 'Font Style',

buttons: [

{ type: 'push', label: 'Bold', value: 'bold' },

{ type: 'push', label: 'Italic', value: 'italic' },

{ type: 'push', label: 'Underline', value: 'underline' },

{ type: 'separator' },

{ type: 'select', label: 'Arial', value: 'fontname', disabled: true,

menu: [

{ text: 'Arial', checked: true },

{ text: 'Arial Black' },

{ text: 'Comic Sans MS' },

{ text: 'Courier New' },

{ text: 'Lucida Console' },

{ text: 'Tahoma' },

{ text: 'Times New Roman' },

{ text: 'Trebuchet MS' },

{ text: 'Verdana' }

] },

{ type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true },

{ type: 'separator' },

{ type: 'color', label: 'Font Color', value: 'forecolor', disabled: true },

{ type: 'color', label: 'Background Color', value: 'backcolor', disabled: true }

] } ] } };

myEditor = new YAHOO.widget.Editor('texteditor', toolbar);

myEditor.render();



  • Date: November 5th, 2007
  • Author: Tony Patton


</script></body></html>

It is worth noting that the text is formatted using standard HTML to format the text within the Rich Text Editor, so bold text uses the HTML strong element; the font element is used for font styling, and so forth.

An improved interface

I have been a big fan of the YUI Library since I first discovered it more than a year ago. It allows developers to build powerful Web interfaces using code that has been fully tested for proper functionality. The Rich Text Editor is just one example of the power controls available in the YUI Library.

Moving to CSS-based layouts with the YUI Library

While initiating a recent project to make substantial changes to an existing Web application, it was decided to dump the table-based layout used in its original design in favor of CSS. We opted to use the Yahoo! User Interface (YUI) Library after evaluating different approaches. The YUI Library provides core CSS resources that have been developed by a professional team of developers and extensively tested by the Web community.

This tutorial walks you through the steps of how to move from a table-based design to a CSS-based layout with the help of the YUI Library.

The layout

It is worth considering the division of screen real estate in the application to understand how it is coded using both tables and CSS. The overall page is divided into two horizontal sections: a header and a body.

The header portion can be further divided into three horizontal strips. The first strip contains a strip of color at the top. The middle row contains text and a logo on a white background. The final row has its own background color along with a breadcrumb.

The body portion of the page is divided into two columns. The first column is a navigation area featuring a list of navigation links. The second column is divided into two rows with a small footer row at the bottom, and the rest is devoted to page content.

The site design does not change from the original product developed with Dreamweaver and HTML tables. The introduction of CSS will deliver cleaner code with a smaller footprint and simplified maintenance.

Table-based layout

The original design used six HTML tables to divide the page and deliver the solution. It used CSS to style text on the page, but CSS usage stopped at that point. The following listing includes the HTML source. Background colors are assigned to each table (via the bgcolor attribute) to provide a visual cue of the layout.

<html>
<head><title>Table-based page layout</title></head>
<body>
<table bgcolor="yellow" width="100%" height="100%" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr><td colspan="3" width="100%"></td></tr>
<tr><td colspan="3">
<table bgcolor="red" border="0" width="100%" cellspacing="0">
<tr>
<td width="85%" valign="middle">Header Text</td>
<td width="15%"><img src="logo.jpg" mce_src="logo.jpg" /></td>
</tr></table></td></tr>
<tr>
<td width="16%" height="20" nowrap>Breadcrumb</td>
<td width="40%" height="20" align="right" nowrap></td>
</tr>
<tr>
<td width="10%" rowspan="2" valign="top">
<table bgcolor="green" width="101%" height="100%" border="0" cellpadding="0"
cellspacing="0">
<tr>
<td height="167" valign="top">
<table bgcolor="light blue" width="100%" border="0" cellspacing="0">
<tr><td colspan="3">Menu</td></tr>
<tr>
<td width="8"> </td>
<td>Nav Link</td>
<td width="4"> </td>
</tr></table></td></tr></table></td>
<td height="100%" colspan="2" valign="top">
<table bgcolor="brown" width="100%" height="100%" cellpadding="0" cellspacing="0">
<tr><td valign="top">
<table bgcolor="silver" width="96%" height="220" border="0" cellpadding="10">
<tbody><tr>
<td valign=top align=left width="100%">
<p>Content goes here</p>
</td></tr></tbody></table></td></tr><tr>
<td height="40" valign="middle">
Footer
</td></tr>
</table></td></tr></table></body></html>

The table-based layout solution delivers the desired results, but it can be confusing to make layout changes. A quick perusal of the code demonstrates the confusing nature of using tables for layout.

It takes time to make layout changes and to convert a table-based solution to a CSS alternative, so selling such a change to a client can be daunting. In our case, the client was technically savvy and easily convinced when we showed the simplified approach offered by CSS.

YUI Grids CSS

The use of the YUI Grids CSS feature of the YUI Library added another level of acceptance via a tested solution. YUI Grids CSS provides a CSS solution for delivering page layouts that divide the page into areas.

A great aspect of the YUI Grids CSS feature is its A-level browser support, which provides the highest support level in terms of browsers. This means you don't have to worry about the quirks in different browsers when using CSS for layout.

CSS layout

YUI Grids CSS offers preset page widths and templates, along with the ability to nest and stack layouts to generate what you need. Yahoo boasts the capability to deliver more than 1,000 layout combinations with it. YUI Grids CSS is part of the YUI Library download.

We used the following features of the YUI Grids CSS feature:

  • The 100% page width is employed via the doc3 id attribute assigned to the overall <DIV> container.
  • The entire page is divided into three rows using three <DIV> elements. The YUI Grids CSS standard id attributes for header (hd), body (bd), and footer (ft) are used.
  • The header has three rows using two <P> elements and a <DIV> element. The <DIV> includes another <DIV> that uses YUI Grids CSS features. This includes the 100% page width (doc3 attribute), as well as a preset template that has two columns with the narrower column on the left with a width of 180 pixels. The narrower column is assigned the class id of yui-b with the larger column assigned the yui-main attribute. The two columns are used to ensure the breadcrumb appears above the content area of the page.
  • The middle or body row of the whole page layout is divided into two columns with a left column width of 180 pixels. This is accomplished with a predefined template employed by assigning the yui-t2 class to the body's <DIV> container. The smaller left column is designated with the yui-b class assignment, and the main area is designated with the yui-main class assignment.
  • The footer row uses the same approach as the body with two columns — a left column of 180 pixels.
  • The smaller left column of the body row of the page contains a navigation menu. The menu is created with an HTML unordered list and styled via CSS.
  • The YUI Grids CSS is contained in one CSS file available in the YUI Library download. The file is called grids.css and has a small footprint of 4KB.

Here is the source of the reworked page:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Reworked with YUI Grids CSS</title>     
<link rel="stylesheet" type="text/css" href="grids.css" mce_href="grids.css">
</head>
<body>
<div id="doc3">
<div id="hd">
<p class="header1"></p>
<p class="header3">
<span>Text</span>
<span class="logo"></span>
</p>
<div>
<div id="doc3" class="yui-t2">
<div class="yui-b"></div>  
<div id="yui-main">
<div class="yui-b">Breadcrumb</div>
</div>
</div>
</div>
</div>
<div id="bd">
<div id="doc3" class="yui-t2">
<div class="yui-b">
<ul class="nav">
<li class="main">Menu</li>
<li class="sub">Nav Link</li>
</ul>
</div>  
<div id="yui-main">
<div class="yui-b">
Content goes here
</div>
</div>
</div>
</div>
<div id="ft">
<div id="doc3" class="yui-t2">
<div class="yui-b">
</div>  
<div id="yui-main">
<div class="yui-b">
Footer
</div>
</div>
</div>
</div>
</div>
</body></html>

You may cringe at the sight of so many <DIV> elements, but this is much easier to follow compared to its table counterpart. Also, the CSS approach allows you to easily modify the layout by editing the CSS or changing what YUI Grids CSS features are used.

For example, we could easily modify the layout to use a layout with a left column of 160 pixels by changing the class assigned to the <DIV> elements from yui-t2 to yui-t1. In order to use this approach, you need to be familiar with using YUI Grids CSS.

There's a caveat to working with the free CSS elements of the YUI Library: It's tricky to alter the source CSS. The code contains many so-called hacks in order to work with all browsers that you may not be fully aware of all of them when you're editing the CSS. For me, I avoid working directly with the source and work within the confines of the YUI Library.

Making the switch

CSS has matured to the point where using it for layout is now acceptable. However, this approach does have pitfalls, which include browser quirks. For this reason, I find the freely available YUI Grids CSS portion of the YUI Library to be an excellent resource for building Web interfaces that use Web standards.

Are you embracing CSS for Web page layout? Do you use any aspect of the YUI Library in your applications? Share your experiences with the Web Developer community.

Additional TechRepublic resources about the YUI Library


  • Date: March 17th, 2008
  • Author: Tony Patton

Build directory structures using SQL Server 2005

If you ever work with directory structures on the filing system, you know how challenging it can be to traverse through folders to find specific file(s). If you store this type of information structure in the database, you are even more aware of what it takes to retrieve the data. Writing queries to pull this information is sometimes difficult to achieve and inefficient. You can use the recursion and XML features in SQL Server 2005 to build a file location on the fly.

Example

This example searches for a document and builds the path to the document based upon a parent-folder to child-folder relationship in the database. One file will belong to one folder, which may be a child folder in a long lineage of parent folders. The ultimate goal is to provide a file to be searched for, and the process will build the location to the file.

I've seen file path locations stored several ways in the database, usually with the purpose of storing the location of a file to be pulled for a Web site. Most of the time, the full path to a file is stored in one database field, but I have also seen the location of a file "normalized" so that the past must be built when needed. My goal for this article is to solve the issue of building the path from the hierarchical structure.

The script below creates a Documents table and a Folders table. The Documents table stores the filenames and the folder that the document resides in. The Folders table stores the directory structure of one or more local or network drives. Most of the work in this example will involve traversing through this folder structure to build the path to the file.

IF OBJECT_ID('Documents','U') IS NOT NULL
DROP TABLE Documents

IF OBJECT_ID('Folders','U') IS NOT NULL
DROP TABLE Folders

IF OBJECT_ID('udf_BuildDocumentPath','FN') IS NOT NULL
DROP FUNCTION udf_BuildDocumentPath

CREATE TABLE Documents
(
        DocumentID SMALLINT,
        FolderID SMALLINT,
        DocumentName VARCHAR(255)
)

CREATE TABLE Folders
(
        FolderID SMALLINT,
        ParentFolderID SMALLINT,
        FolderName VARCHAR(255)
)

The code below adds data to our newly created tables. I am adding data for three documents, all of which are located in the same folder.

INSERT INTO Documents(DocumentID, FolderID, DocumentName)
VALUES(1,5,'SalesForecast2008.xls')
INSERT INTO Documents(DocumentID, FolderID, DocumentName)
VALUES(2,5,'SalesProjection.doc')
INSERT INTO Documents(DocumentID, FolderID, DocumentName)
VALUES(3,5,'SalesForecastPresentation.ppt')

INSERT INTO Folders(FolderID, ParentFolderID, FolderName)
VALUES(1,null, 'D:')
INSERT INTO Folders(FolderID, ParentFolderID, FolderName)
VALUES(2,1, 'Sales')
INSERT INTO Folders(FolderID, ParentFolderID, FolderName)
VALUES(3,2, 'Forecasts')
INSERT INTO Folders(FolderID, ParentFolderID, FolderName)
VALUES(4,3, 'Data')
INSERT INTO Folders(FolderID, ParentFolderID, FolderName)
VALUES(5,4, '2008')
GO

The script below creates the function that will build the full path to the file based upon the DocumentID in the Documents table. This function uses a recursive common table expression (CTE) to traverse through the directory structure, linking the child folder ID to the parent folder ID in the table. Once the set of records are found that comprise the full path to the document, the FOR XML PATH('') construct is used to "pivot" these values from values in different rows to values concatenated in the same row. From there, it is just a matter of returning the build path to the caller.

FOR XML Path() is one of my favorite features in SQL Server 2005 because it makes it so easy to take a list of column values from different rows and concatenate them together so that they are on the same row. It is an ideal tool for dynamically building SQL statements that require list of different values for use in an IN() statement.

CREATE FUNCTION udf_BuildDocumentPath
(
        @DocumentID SMALLINT
)
RETURNS VARCHAR(400)
AS
BEGIN
        DECLARE @ReturnPath VARCHAR(400)

;WITH DirectoryPathCTE(DocumentID, FolderID, ParentFolderID, DocumentName, FolderName, LevelNumber)
        AS
        (
        SELECT
               DocumentID, f.FolderID, ParentFolderID, DocumentName, f.FolderName, 0
        FROM
               Documents d
               INNER JOIN folders f on d.FolderID = f.FolderID
        WHERE
               DocumentID = @DocumentID
        UNION ALL
        SELECT
               DocumentID, f.FolderID, f.ParentFolderID, DocumentName, f.FolderName, p.LevelNumber + 1
        FROM
               Folders f
               INNER JOIN DirectoryPathCTE p on p.ParentFolderID = f.FolderID
        )
        SELECT @ReturnPath =
        (
               SELECT
                  FolderName + '' + CASE WHEN LevelNumber = 0 THEN DocumentName ELSE '' END
               FROM
                       DirectoryPathCTE p
               ORDER BY LevelNumber DESC
               FOR XML PATH('')
        )

        RETURN(@ReturnPath)

END
GO

Now that my function is built, I can call it for every document I have in my Documents table, and the path to the file will be built based upon the DocumentID in the Documents table.

SELECT dbo.udf_BuildDocumentPath(d.DocumentID)
FROM Documents d

Conclusion

Even if you never need to implement the example in this article, I hope you'll take away some ideas from the recursion and the FOR XML PATH clause to solve some tricky problems you may encounter in the future.


  • Date: March 17th, 2008
  • Author: Tim Chapman

Search