CakePHP paginator – Identifying sort direction and column

Add Comment | Aug 10, 2010

I love CakePHP’s paginator. Its fairly easy to use and packs a punch of features. The one missing feature, though, is that there is no automagic mechanism to tell the user what column is being sorted on and in what direction. But its easy enough to do. I came up with this paginator header element that will output markup for the table header and shows what column is sorted.

Here’s the code for the element:

<?php
// required 1 input: $fields = fields of the model and corresponding text to display as column header
		$paginator->options(array('url' => $this->params['pass']));
		foreach($fields as $title => $field)
		{
		?>
			<th>
				<?php echo $paginator->sort($title, $field, array('class' => ($field == $paginator->sortKey()) ? $paginator->sortDir() : '')); ?>
			</th>
		<?php
		}
		?>

Basically, it just outputs table header tags containing the sorting link for the paginator to sort on that column. Adding the class attribute allows us to show two separate images based on the sort direction. Non-sortable columns can be added directly into the html. To use it, you have to create an array that contains the title for each column as key and the corresponding field in your model as the value. For example, if you had a Person model, you would call the element like this:

<?php
		$fields = array('ID' => 'Person.id',
					'Name' => 'Person.Name',
					'Username' => 'Person.Username',
					'Title' => 'Person.Title');
		echo $this->element('paginator_header', array('fields' => $fields));
?>

How it works:

It finds the the name of the column that is currently being sorted and the sort direction from the paginator. Then it applies an “asc” or “desc” css class to the markup of that column. So, you also need to define the css for these “asc” and “desc” css classes. What you would normally want is to put an up or down arrow images next to the column header.

Here’s two sample classes I used in my application:

a.asc {
	padding-right: 20px;
	background: url('../img/arrow_up.png') no-repeat top right;
}

a.desc {
	padding-right: 20px;
	background: url('../img/arrow_down.png') no-repeat top right;
}

Up/Down images:

arrow_down arrow_up

And here’s the end result:

up (1)

down (1)

jQuery Formhints plugin

Add Comment | Aug 09, 2010

A very simple jquery plugin for showing hints right next to form inputs. This is a jquery adaptation of the excellent javascript & css form hint script at http://www.askthecssguy.com/2007/03/form_field_hints_with_css_and.html.

I’ve made it where the form hints show up when you mouse over the input elements. You can also make a small edit to the script so that the formhints only show when the user actually clicks on an input element. Just change the “input.mouseover” to an “input.click”.

(function($){
	
	$.fn.formhints = function(params){
		$(":input", this).each(
				function(i)
				{
					var input = $(this);
					if(input.next("span").length > 0)
					{ // if this input element has a span next to it
						$(input.next("span")).hide();// initially hide all
						input.mouseover(function() {
							var pos = $(this).position();
							var left = pos.left + $(this).width() + 30;
							$(input.next("span")).css({'display':'inline', 'top':pos.top+'px',
								'left':left+'px'});
						});
						input.mouseout(function() {
							$(input.next("span")).css('display','none');
						});
					}
				}
		);
	};
	
})(jQuery);

 

In order to use it, the form html needs to be modified. Each input element with a hint must have an adjacent “span” element which contains the hint text that will be displayed to the user. Here’s a sample input element:

<div class="input text required">
	<label for="ScriptName">Script name</label>
	<input name="data[Script][name]" type="text" maxlength="200" value="" id="ScriptName" />
	<span class="hint">
		Name of the script
		<span class="hint-pointer">&nbsp;</span>
	</span>
</div>

 

Note the span element after the input element. It will contain the hint that will be displayed to the user on mouseover. You can apply css styles to the hint to make it look nice. I’m just reusing the hint class developed by askthecssguy for his script which looks quite nice.

Once you’ve gotten the span elements added to your form, add this one line to your page load function to get your form ready for action.

$(document).ready(function(){
	$("#formidhere").formhints();
});

 

And that’s it. Make sure to replace the “formidhere” with the id of your form.

Here’s the css I used for my form hint and the final result.

.hint {
  position: absolute;
  width: 200px;
  margin-top: -4px;
  border: 1px solid #c93;
  padding: 10px 12px;
  background: #ffc url(../img/hint_pointer.gif) no-repeat -100px -100px;
}

.hint .hint-pointer {
    position: absolute;
    left: -10px;
    top: 5px;
    width: 10px;
    height: 19px;
    background: url(../img/hint_pointer.gif) left top no-repeat;

}

 

hint_pointer

formhint

Moving repositories/ Creating backups in SVN

Add Comment | Mar 12, 2010

Recently, I needed to move some projects around in my SVN and it turned out to be very easy, although it took a bit of googling. This also gives you a way to take file backups of your repositories. Basically, what I needed to do was move one repository into a subfolder inside another repository. To do this, you just need two commands and you also need to do this on the SVN server. You can’t do it from an SVN client. Here are the two commands:

svnadmin dump /path/to/repository > filename.dmp

svnadmin load –-parent-dir path/to/subfolder repository-name < filename.dmp

So basically, the first command dumps your current repository including its previous revisions, branches and tags all to the standard output and you can redirect that into a file. You can use this command to take periodic backups of your repository which is really neat. I was actually searching for this feature as well and there might be other ways to take backups as well.

The second command then loads up the repository from the dump file into the subfolder. If you don’t specify the –-parent-dir, it will just load up the file into the new repository. The parent-dir path is relative to the root of your new repository.

Here are the links that helped me find this:

http://svnbook.red-bean.com/nightly/en/svn.ref.svnadmin.c.load.html

http://www.digitalmediaminute.com/article/2251/how-to-move-a-subversion-repository

Format of SVN access file for Path Based Authorization

2 Comments | Dec 17, 2009

Fine grained permissions on SVN repositories can be provided by creating an access file. Following is a sample access file explaining the basic format of the file. More details can be found by reading the SVN book.

#groups are defined here. simply list the names of members of the group delimited by comma
[groups]
admin = rudy, batman, admin
 
# to create access control for a repo, start with the directory that you are 
# defining the permissions for
# to define permissions for all directories within a repo, use /
# for example, to define permissions for all directories in the gui project
# i've used the following [gui:/]
# the syntax is [reponame:directorypath]
# to define permission for a specific directory within the repo, specify the path
# example: [gui:/branches/2.0/bug/140] defines the permissions for the 
# /gui/branches/2.0/bug/140 directory
# the syntax to define the permission itself is
# username = access
# where username is the username of the user you are writing permission for
# and access is one of r or rw, r meaning read permission and rw meaning read and
# write permission
# username could also be the name of a group. in that case, the group name is written
# as @groupname
# for example, to give the admin group rw permission on all directories in gui
# use,
# [gui:/]
# @admin = rw
# if you need to give all users permission on a directory, use the special
# character '*' to denote all users
# NOTE: The longest matching directory path permission is always applied first
# so if you have two permission rules like so,
# [gui: /]
# rudy = rw
#
# and
#
# [gui:/branches/2.0]
# nithin = r
# 
# then, nithin will only have read permission on the /gui/branches/2.0 directory
# because that is the longest matching path
# More examles below:

[/]
* = r
 
[gui:/]
@admin = rw
nithin = rw
#
[moregui:/]
@admin = rw
matt = rw
john = r
chuck = rw
#
[hardcore:/branches/2.1/broke]
@admin = rw
#
[test:/]
@admin = rw
* = rw

Create SVN repositories using a standard folder structure

Add Comment | Dec 10, 2009

This is shell script that you can use to create all of your repositories using the same standard folder structure. You need to replace the following variables for it to run:

  1. Replace [name] with the correct username of a user who will have permissions on the repository.
  2. Replace [password] with the correct password of the user
  3. Replace yourdomain.com with the path to where your svn repositories are stored

call the script: ./scriptname reponame and it will create a new repository with the name reponame.

Here’s what the script does:

  1. The script creates the new repository folder
  2. It gives apache permissions on the folder. If you are not using apache, uncomment the line.
  3. If you are using an access file to provide fine-tuned directory permissions, you may want to uncomment the two lines that refer to access.txt. Those two lines add the new repo to the access file and gives the admin group rw permissions on the repository.
  4. It then goes and creates the standard folder structure, ie, trunk, branches adn tags folder.

 

#!/bin/bash
svnadmin create $1;
chgrp -R apache $1;
chmod -R g+rw $1;
#echo "[$1:/]" >> access.txt
#echo "@admin = rw" >> access.txt
svn –username [name] –password [pass] mkdir "http://yourdomain.com/svn/"$1"/trunk" -m "ADD: /trunk";
svn –username [name] –password [pass] mkdir "http://yourdomain.com/svn/"$1"/branches" -m "ADD: /branches";
svn –username [name]—password [pass] mkdir "http://yourdomain.com/svn/"$1"/tags" -m "ADD: /tags";

echo "------------------------------------------";
echo "Standard Repo Layout Created";

Installing SVN server

Add Comment | Nov 25, 2009
  1. Install latest Apache http server
  2. Install SVN
    1. Make sure to install mod_dav_svn and mod_authz_svn. mod_authz_svn is only needed if you plan on doing fine-grained directory permissions on your SVN repositories
    2. Load the mod_dav_svn and mod_authz_svn modules in httpd.conf. You may also need to load the mod_dav module if you don’t have it yet:
    3. LoadModule  dav_module             modules/mod_dav.so
      LoadModule  dav_svn_module         modules/mod_dav_svn.so
      LoadModule  authz_svn_module       modules/mod_authz_svn.so
    4. Modify apache httpd.conf to add the following:
    5. <Location /svn>
        DAV svn
        SVNParentPath D:/svn
        SVNListParentPath on
        AuthType Basic
        AuthName "Subversion Repository"
        AuthUserFile passwd.txt
        Require valid-user
      </Location>
    6. You should now be able to browse to your SVN repos at www.yourdomain.com/svn
    7. If you would like to enable anonymous checkouts, replace the Require valid-user above with the following. Check-ins will still require authentication.
    8. # For any operations other than these, require an authenticated user.
        <LimitExcept GET PROPFIND OPTIONS REPORT>
          Require valid-user
        </LimitExcept>
    9. If you are not going to be using per-directory access control, you might as well turn off path authorization (it’s on by default). This improves performance of your server, since its not checking every single path requested to see if the user is authorized to access it. Add this line to turn it off:
    10. SVNPathAuthz off
  3. Install PHP
    1. Install an SVN browser, WebSVN is the best I’ve seen. It’s built on PHP and works well.
  4. Subclipse is the best SVN client for use with Eclipse IDE
  5. TortoiseSVN is a good SVN windows explorer client

Connecting to Excel with ADO.NET Useful Links

Add Comment | Sep 30, 2009

Thought I would put this up here for future reference. #1 Helped me figure out how to retrieve a region within an excel sheet instead of the whole sheet. I didn’t know you could do things like “SELECT * FROM [Sheet1$A1:B10]” which will only retrieve the values with those rows and columns. You can also retrieve data inside named ranges.

If you want to be able to figure out the name of the first worksheet, then have a look at link #2. You have to get it out of the database schema.

Very useful.

  1. http://support.microsoft.com/kb/257819
  2. http://blog.lab49.com/archives/196

testing syntax highlighter

Add Comment | Sep 09, 2009

Arnold Matusz’s created a great live writer plugin that uses the excellent syntax highlighter from Alex Gorbatchev. Great Stuff!!

sample:

        public object Lookup(string tblName, string returnField, string where)
        {
            SqlCommand s = new SqlCommand();
            s.Connection = conn;
            s.CommandText = "SELECT " + returnField + " FROM " + tblName + " WHERE " + where;
            return (object) s.ExecuteScalar();
        }

hmm, it doesn’t look very nice inside writer. let’s see what it looks like published.

Update: Looks like the syntax highlighting won’t show up inside live writer itself. 

How it works: The code is put inside a pre (preformatted text) tag and a css class attribute is added to it. The class specifies what language syntax highlighting to use. For example, to get the C# highlighting above, you would use class="brush: csharp;". You can find style brushes for most languages in use today. You can create a custom one if there’s not one for your language. The plugin for live writer from Arnold takes care of putting the correct class.

To get everything working, I ended up modifying the PageTemplate.ascx file for this skin to add the link tags to the required javascript files. There must be some better way to do this because if I decide to change skins, then I will lose all the syntax highlighting.

<script type="text/javascript" src="http://nithinthomas.com/syntax/scripts/shCore.js"></script>
	<script type="text/javascript" src="http://nithinthomas.com/syntax/scripts/shBrushCpp.js"></script>
	<script type="text/javascript" src="http://nithinthomas.com/syntax/scripts/shBrushCSharp.js"></script>
	<script type="text/javascript" src="http://nithinthomas.com/syntax/scripts/shBrushCss.js"></script>
	<script type="text/javascript" src="http://nithinthomas.com/syntax/scripts/shBrushJava.js"></script>
	<script type="text/javascript" src="http://nithinthomas.com/syntax/scripts/shBrushJScript.js"></script>
	<script type="text/javascript" src="http://nithinthomas.com/syntax/scripts/shBrushPhp.js"></script>
	<script type="text/javascript" src="http://nithinthomas.com/syntax/scripts/shBrushPlain.js"></script>
	<script type="text/javascript" src="http://nithinthomas.com/syntax/scripts/shBrushSql.js"></script>
	<script type="text/javascript" src="http://nithinthomas.com/syntax/scripts/shBrushVb.js"></script>
	<script type="text/javascript" src="http://nithinthomas.com/syntax/scripts/shBrushXml.js"></script>
	<link type="text/css" rel="stylesheet" href="http://nithinthomas.com/syntax/styles/shCore.css"/>
	<link type="text/css" rel="stylesheet" href="http://nithinthomas.com/syntax/styles/shThemeDefault.css"/>
	<script type="text/javascript">
	    SyntaxHighlighter.config.clipboardSwf = 'http://nithinthomas.com/syntax/scripts/clipboard.swf';
		SyntaxHighlighter.all();
	</script>

It might probably help to post the javascript files on google code and link to them instead.

Export gridview as excel & subsequent troubles

One Comment | Sep 07, 2009

I was trying to write a simple application the other day that exported data from sql server to excel for the user to edit it and then import the updated excel back into sql server. There’s lot of help online about how to export gridview to excel. Here’s what I came up after looking at various examples:

Protected Sub exportExcel()
            'Clear the response, and set the content type and mark as attachment
            HttpContext.Current.Response.Clear()
            HttpContext.Current.Response.Buffer = True
            HttpContext.Current.Response.ContentType = "application/vnd.ms-excel"
            HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=""SupportItems_" & Date.Now.Month() & "_" & Date.Now.Day & "_" & Date.Now.Year & ".xls""")

            'Clear the character set
            HttpContext.Current.Response.Charset = ""

            'Create a string and Html writer needed for output
            Dim oStringWriter As New System.IO.StringWriter()
            Dim oHtmlTextWriter As New System.Web.UI.HtmlTextWriter(oStringWriter)

            'Clear the controls from the pased grid
            ClearControls(grdViewAll)

            'Show grid lines
            grdViewAll.GridLines = GridLines.Both
            'Color header
            grdViewAll.HeaderStyle.BackColor = System.Drawing.Color.LightGray

            'Render the grid to the writer
            grdViewAll.RenderControl(oHtmlTextWriter)

            'Write out the response (file), then end the response
            HttpContext.Current.Response.Write(oStringWriter.ToString())
            HttpContext.Current.Response.[End]()
        End Sub

        Private Shared Sub ClearControls(ByVal control As Control)
            'Recursively loop through the controls, calling this method 
            For i As Integer = control.Controls.Count - 1 To 0 Step -1
                ClearControls(control.Controls(i))
            Next

            'If we have a control that is anything other than a table cell 
            If Not (TypeOf control Is TableCell) Then
                If control.[GetType]().GetProperty("SelectedItem") IsNot Nothing Then
                    Dim literal As New LiteralControl()
                    control.Parent.Controls.Add(literal)
                    Try
                        literal.Text = DirectCast(control.[GetType]().GetProperty("SelectedItem").GetValue(control, Nothing), String)
                    Catch
                    End Try
                    control.Parent.Controls.Remove(control)
                ElseIf control.[GetType]().GetProperty("Text") IsNot Nothing Then
                    Dim literal As New LiteralControl()
                    control.Parent.Controls.Add(literal)
                    literal.Text = DirectCast(control.[GetType]().GetProperty("Text").GetValue(control, Nothing), String)
                    control.Parent.Controls.Remove(control)
                End If
            End If
            Exit Sub
        End Sub
    ''' <summary>
    ''' Reads excel file into a dataset reference passed as the first argument
    ''' </summary>
    ''' <param name="ds"></param>
    ''' <param name="filename"></param>
    ''' <param name="query"></param>
    ''' <param name="headers"></param>
    ''' <remarks></remarks>
    Private Sub ReadExcel(ByRef ds As DataSet, ByVal filename As String, ByVal query As String, Optional ByVal headers As Boolean = True, Optional ByVal tablename As String = "table1")
        Dim strConnectionString As String
        Dim conExcel As OleDbConnection
        Dim dAdaptExcel As OleDbDataAdapter
        Dim cmdSelect As OleDbCommand
        'Define Excel connection
        If headers Then
            strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & filename & _
                ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"""
        Else
            strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & filename & _
                ";Extended Properties=""Excel 8.0;IMEX=1"""
        End If
        conExcel = New OleDbConnection(strConnectionString)

        Try
            'Open Connection to Excel
            conExcel.Open()
            cmdSelect = New OleDbCommand(query, conExcel)
            dAdaptExcel = New OleDbDataAdapter
            dAdaptExcel.SelectCommand = cmdSelect
            'Fill the dataset
            dAdaptExcel.Fill(ds, tablename)
        Finally
            conExcel.Close()
        End Try
    End Sub

This works okay and in IE, you get the usual open or save dialog. If you do a save, the file gets saved as some kind of html file which unfortunately, you can't import back. I'm using the Select * from [Sheet1$] method to import the data into a DataTable.

So instead, when you get the file open or save dialog, you have to open the file in excel, and then do a file -> save as and save as an xls file. That’s the only the file can be imported back into a DataTable. 2 hourse of googling and I haven’t found any other solution sadly. Hope the users can remember to do this :).

Credit goes to all the people from whom I copied most of the code for exporting the gridview.

bad indian veg restaurant

Add Comment | Sep 06, 2009

On Saturday, went to dinner at kalachandji’s. they’ve been around for about 27 years or so, but wow, the food was terrible. It really wasn’t Indian at all, just a lot of vegetables sliced and diced and mixed together. None of the food had any flavor or taste.

I heard a lot of people seem to like it though. It definitely wasn’t the traditional Indian restaurant food that I was expecting. I advise you to stay away if you are in the mood for real Indian food.

The setting was gorgeous though. The open sky, big tree in the middle and the amber lights did put me in the mood for some spicy food which I unfortunately, didn’t get.