sim.plified.com

Chris Pollock

Chris Pollock - web developer (PHP/mySQL & ASP.NET)
undivided… my thoughts on world, family, church, business, technology and Jesus Christ (all in all)

Use jQuery to fix code that sucks

If you’re working inside of an institutional structure chances are you occasionally have to deal with code that sucks.  I know I do!  We have some third party apps at the institution where I work.  I believe they were designed in the early 90s before anyone knew the word “standards” or “css” and have not been revisited.  While working on one of these code bases I had the idea of using jQuery to remedy my brow furrowing. 

Problem

No IDs or class names on the the template code.  The templates were static and I didn’t want to do a global find and replace to try and fix the problem. 

jQuery to the Rescue

With jQuery’s selector support, I decided that I could use that to add the vital css, classes or ids I need to make the layout work.  Example:

   1: $(document).ready(function(){
   2:     // standard document formatting
   3:     $("BODY DIV:first").css("width", "800px").css("margin", "0 auto 0 auto");
   4: });

Instead of injecting css directly, I could have added a class and added my styling in the stylesheet like this:

   1: $(document).ready(function(){
   2:     // standard document formatting
   3:     $("BODY DIV:first").attr("class", "fixthishoriblecode");
   4: });

There you have it.  As simple as including the jQuery library and adding some lines of JavaScript. [of course is javascript is turned off, this is not going to work.. but I didn’t say this was a miracle solution for fixing your bad code, just a patch]. 

If you’ve had to deal with these types of code bases, share your story below of how you fixed the problem.

[ Leave a Comment ]

jQuery Edit in Place Implementation

For PatternTap.com we wanted to use some edit in place functionality to allow users to change their name, location, etc.  I used jQuery to create our own implementation of edit in place. 

Here is an example of the markup for the input box (I have left out the server side coding that renders this markup):

<li class="first">
    <span class="pro_label">Name:</span>
    <span id="update_real_name"><span class="editThis">[Users Name]<span class="edit_mark">edit</span></span></span>
</li>

The edit mark span is something that provides visual feedback to the user that the area is editable.   What is inside the "editThis" span is what will be edited.   The span that surrounds the both of those pieces serves as a place holder, so that the input can be swaped in and out of the DOM.

Here is the JavaScript that binds to the item and makes it editable.

    $(document).ready(function() {
        bind_update();  // bind this on page load
    });

    function bind_update()
    {
       // find all the editThis elements and find this functionality
        $('.editThis').bind("click", function(e){
            // remove the edit_this mark
            $(this).children(".edit_mark").remove();

            // capture some information about the selected element
            var parentId = this.parentNode.id;
            var editType = this.parentNode.className
            var revert = this.innerHTML;

            // check to see if this is a textarea or inputbox
            //   note the save and cancel buttons are added along with the input or textarea
            if (editType == "textarea")
                $('#' + parentId).html("<textarea id=\"input_" + parentId + "\" >" + revert + "</textarea> <button onclick=\"update_value('" + parentId + "', true);\" value=\"Save\"   >Save</button> <a id=\"cancel_" + parentId + "\" href=\"javascript:void(0);\">Cancel</a>");
            else
                $('#' + parentId).html("<input type=\"input\" id=\"input_" + parentId + "\" value=\"" + revert + "\" onblur=\"\" /> <button onclick=\"update_value('" + parentId + "', true);\" value=\"Save\"   >Save</button> <a id=\"cancel_" + parentId + "\" href=\"javascript:void(0);\">Cancel</a>");

            //set the focus on the newly embedded input box
            $("#input_" + parentId)[0].focus();
            $("#input_" + parentId)[0].select();

            //bind the cancel functionality to the cancel button
            $("#cancel_" + parentId).click(function() {
                    update_value(parentId, revert);
            });

        });
    }

    // this function sends the updated value back to the server    
    function update_value(id, update)
    {
        if (update == true)
        {
            result = $('#input_' + id).val();
            $.ajax({
                type: "POST",
                url: "/people/change_user_profile/",
                data: "user_id=<?=$user['id']?>&field=" + id + "&value=" + result,
                error: function()
                    { alert("There was a problem, please let us know.") }
            });
        }
        else
        {
            // in the case of a cancel, update is the "revet" value 
            result = update;
        }
        $('#' + id).html("<span class=\"editThis\">" + result + "<span class=\"edit_mark\">edit</span></span>");

        bind_update();
    }

 

I'm sure there are slicker ways to do this, but this certainly did the job for us.

Of course when you send the data to the server you are going to want to authenticate the user to make sure they are who they say they are.  This will prevent people from hacking the JavaScript and changing someone elses information. 

Technorati Tags: ,

[ Leave a Comment ]

Dirty, Dirty, Dirty… Implementing IsDirty with JavaScript

Sometimes when a user is editing a page, you want to let them know that if they click on a link or a section of the main navigation that they will lose their changes. 

Here's a quick walk through on an IsDirty implementation I did with jQuery and ASP.NET.

Add this hidden field somewhere on your page

 <input type="hidden" id="dirty" value="" />

Here is the JavaScript that will manipulate the value.

 

    <script src="js/jquery-1.2.3.min.js" type="text/javascript"></script>

    <script type="text/javascript">

        window.onbeforeunload = checkExit;

        function confirmExit()
        {
            // this value will be return as a part of the confirmation message
           return "If you have made any changes to the fields without clicking the Save button, your changes will be lost.";
        }

        function checkExit()
        {
            if ($("#dirty").val() == "true")
            {
                return confirmExit();
            }
        }
        function setDirty(changeVal)
        {
            $("#dirty").val(changeVal);
        }

        function confirmAndClean(msg)
        {
            setDirty(false);
            return confirm(msg);
        }
    </script>

The only thing that remains it to make sure that you call these JavaScript client functions in the appropriate places.

With ASP.NET I would do something like this:

ddlCategoryPage.Attributes.Add("onclick", "setDirty(true);");
txtTitle.Attributes.Add("onkeyup", "setDirty(true);");
btnSavePage.Attributes.Add("onclick", "setDirty(false);");
btnCancelPage.Attributes.Add("onclick", "return confirmAndClean('Any changes you have made will be lost.  Are you sure you want to cancel?')");

When I save the page I set the dirty var false so that the user is not prompted.  When the dropdown or title on the page is edited I set the dirty var to true.  The cancel button calls a function that clears the dirty var and displays a custom confirmation box.

With standard HTML I could call the functions like this:

<input type="text" onkeyup="setDirty(true)" />

<input type="submit" value="Save" onclick="setDirty(false)" />

Seems to work like a charm so far.  Hope this helps you out.  If you have questions, do not be afraid to shoot me an email or post a comment.

Technorati Tags: ,,

[ Leave a Comment ]

Package Files for Zip Download with ASP.net

In some of my other posts I've talked about an application I have built that accesses the Flickr API and provides campus administrators with a filtered view of the images in our Flickr account. 

One of the features of this site is a photo bucket where users can "mark as favorite" certain images.  I have now included a function that allows them to download all of their favorite photos in a zip file. 

Dependencies:

This app utilizes the SharpZip Library - available here.

Props:

This tutorial was particularly helpful for me - click here.  Although my implementation is quite different.

Basically the user clicks on a button and the zip file presents itself for download

Markup:

 <asp:LinkButton ID="lbDownload" runat="server" OnClientClick="$(this).html('Creating Zip File… this may take a moment')">Download
            All Images (.zip)</asp:LinkButton>

Note that I am using jQuery to handle some client feedback.

 

Code Behind:

    Public Function CreateZipOfFavorites(ByVal intUserId As Integer) As String

        Try

            'Get list of users favoriates from the database
            Dim dsFavs As DataSet = UserFavorites(intUserId)

            If Not IsNothing(dsFavs) Then

                'Zip filename will be a simple datetime string
                Dim strNow As String = String.Format("{0:MMM-dd-yyyy_hh-mm-ss}", System.DateTime.Now)
                'Create the Zip library
                Dim myZipStream As New ZipOutputStream(File.Create(HttpContext.Current.Server.MapPath("./Zips/") + strNow + ".zip"))

                'This is the Photo object that comes from the FlickrNet.dll
                Dim myPhoto As PhotoInfo
                'Loop through the favorites and add them to zip
                For Each drFav As DataRow In dsFavs.Tables(0).Rows

                    'Grab the files from flickr
                    myPhoto = myFlickr.PhotosGetInfo(ImageGetFlickrId(drFav("pc_id")))
                    'Sycronously grab the data (note, large files will take time)
                    Dim fileClient As New Net.WebClient()
                    Dim dataBuffer As Byte() = fileClient.DownloadData(myPhoto.OriginalUrl)

                    'Put the images into the zip library
                    Dim zipEntry As New ZipEntry(myPhoto.PhotoId & "." & myPhoto.OriginalFormat)
                    myZipStream.PutNextEntry(zipEntry)
                    myZipStream.Write(dataBuffer, 0, dataBuffer.Length)

                Next

                'Clean up and close up
                myZipStream.Finish()
                myZipStream.Close()

                'Return the file name
                Return strNow & ".zip"

            Else
                'Return blank if no zip is created
                Return ""
            End If

        Catch ex As Exception
            myErrorHandler.Exception = ex
            myErrorHandler.DefaultHandler()
            Return ""
        End Try

    End Function
 
    Protected Sub lbDownload_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lbDownload.Click

        Dim fileZip As String = CreateZipOfFavorites(myPhotoCentral.UserGetId(Session("LogonUser")))
        If fileZip <> "" Then
            Session("FlashMessage") = "Zip file created."

            Response.ContentType = "application/force-download"
            Response.AppendHeader("Content-disposition", "attachement; filename=" & fileZip)
            Response.TransmitFile("Zips/" & fileZip)
        Else
            Session("FlashMessage") = "Zip file creation failed."
        End If

    End Sub

 

That's about it for the implementation.  It's pretty straight forward.  Let me know if you have comments or questions.

[ Leave a Comment ]

"WHERE OR" in LINQ using "Contains"

In on of my recent implementations I was looking to loop through a series of categories and then find all the jobs in those categories and add them to a the results list.  The most logical way of doing this would have been to "Where OR" a bunch of items together.  LINQ however does not contain a "WhereOr" operator.  Instead I was able to implement by 1) shoving the selected items into an integer array, and then 2) Using the "Contains" command to filter down the job/category link table.

Here's a code snippet:

            'If the category selection method is selected then filter the jobs.
            If rblCategories.SelectedValue = "Some" Then

                'Get all the categories and throw them into an array.
                Dim CategoryIdList As New ArrayList()
                For Each li As ListItem In cblCategories.Items
                    If li.Selected Then
                        Dim intCategoryId As Integer = li.Value
                        CategoryIdList.Add(intCategoryId)
                    End If
                Next

                'Cast the array list into the an array of integers
                Dim intCategoryIdList As Integer() = CType(CategoryIdList.ToArray(GetType(Integer)), Integer())

                'Filter the category List
                Dim categories = From c In dbCareerServices.LQ_TBL_JOBS_TO_CATEGORies Select c
                categories = categories.Where(Function(ct) intCategoryIdList.Contains(ct.int_category_id))

                'Now filter the job list
                result = result.Where(Function(j) categories.Any(Function(c) c.int_job_id = j.int_job_id))
            End If

 

If anyone knows of a better way to get similar results with LINQ, please let me know.

Technorati Tags: ,,

[ Leave a Comment ]

CheckBoxList as and Unordered List (CSS Stylable)

The CheckBoxList control in ASP.NET is great because the control handles all the data for you.  However, if you want to enhance the UI a little bit the control is left wanting for sure.  This led me to do some searching for CheckBoxList alternatives.  I came up with two blogs posts (one here, the other here) that recommended creating a Custom Server Control that encapsulated the CheckBoxList inside of an unordered list. I went this route and the results were fantastic:

Roberts-Wesleyan-College---Rochester,-NY_1208529940272

I used the Server Control to change the CSS Class of the enclosing list item when the item is selected.  That allowed me to apply some nice CSS styling to to any item that was selected.  (As a side note the entire block is enclosed in an UpdatePanel, so clicking the options changes the data below dynamically).

I have enclosed my code for my custom server control below.  I borrowed from the the two blog posts above, but added some additional data to account for "AutoPostBack" and the applying CSS Styling to the selected item.  I'm am also making the compiled DLL available for download here.

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls

Namespace edu.roberts.its.CustomWebControls

    <DefaultProperty("Text"), ToolboxData("<{0}:ULCheckBoxList runat=server></{0}:ULCheckBoxList>")> _
    Public Class ULCheckBoxList
        Inherits CheckBoxList

        Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)

            Controls.Clear()

            Dim inputFormatString As String = "<input id={0}{1}{0} name={0}{2}{0} type={0}checkbox{0} value={0}{3}{0} {4} {5} />"
            Dim labelFormatString As String = "<label for={0}{1}{0}>{2}</label>"

            If (Not MyBase.CssClass Is Nothing AndAlso MyBase.CssClass <> "") Then
                writer.WriteLine("<ul class=""" & MyBase.CssClass & """>")
            Else
                writer.WriteLine("<ul>")
            End If

            For index As Integer = 0 To Items.Count - 1

                Dim inputBuilder As New StringBuilder
                Dim labelBuilder As New StringBuilder
                Dim checked As String = ""

                If (Items(index).Selected) Then
                    checked = "checked=""checked"""
                End If

                'Add selected class to the list item if the checkbox is checked.
                writer.Indent += 1
                writer.WriteLine("<li class=""" & IIf(Items(index).Selected, "selected", "") & """>")
                writer.Indent += 1

                Dim postbackScript As String = ""
                If MyBase.AutoPostBack = True Then
                    postbackScript = String.Format("onclick=""javascript:setTimeout('__doPostBack(\'{0}\',\'\')', 0)""", MyBase.UniqueID & "$" & index.ToString())
                End If

                inputBuilder.AppendFormat(inputFormatString, """", MyBase.ClientID & "_" & index.ToString(), MyBase.UniqueID & "$" & index.ToString(), Items(index).Value, checked, postbackScript)
                labelBuilder.AppendFormat(labelFormatString, """", MyBase.ClientID & "_" & index.ToString(), Items(index).Text)

                writer.WriteLine(inputBuilder.ToString())
                writer.WriteLine(labelBuilder.ToString())

                writer.Indent -= 1

                writer.WriteLine("</li>")
                writer.WriteLine()
                writer.Indent -= 1

            Next

            writer.WriteLine("</ul>")

        End Sub

    End Class

End Namespace

[ Leave a Comment ]

Parsing URLs from Flickr Descriptions

PatternTap had its beginnings in flickr.  Instead of transferring all that data by hand, flickr's API allows us to access the data very nicely.  Unfortunately, the source URL for each images was not in a separate field, but in the general description field.  I wrote the following PHP function to parse the last URL out of the description and return it as a string.

    // Returns the last URL in an HTML description
    // Input: HTML description
    // Output: URL string
    function return_url_from_description($desc)
    {
        $url = "";
        $doc = new DOMDocument();
        // shove the description in the dom
        $doc->loadHTML($desc);
        // search for anchor tags
        $a_tags = $doc->getElementsByTagName("a");
        for ($i = 0; $i < $a_tags->length; $i++) {
            // get the href attribute of the anchor tag
            $url = $a_tags->item($i)->getAttribute("href");
        }
        return $url;
    }

[ Leave a Comment ]

Creating Calendar Event Callouts for the ASP.NET Calendar Control

Story

I needed to revamp our campus calendar and found a great css/javascript calendar callout implementation while browsing Squared Eye's UI gallery (soon to become Pattern Tap).  I wanted to do a similar implementation, highlighting the individual event, instead of the whole day.

My Version

Here is the visual end result of my calendar callout:

ScreenShot001

The date (or date span) appears in the header with a close button.  The event name, time, details, link and location are included in the box. At the bottom there is a permalink to the event in case people want to link directly to the Event information.  Click here to see the live implementation(Note: the calendar was still not live at time of blog article publication)

ASP.NET Implementation

I implemented this through a combination of the ASP.NET calendar control, some Ajax call backs, and the jQuery Javascript library.  I'll try to cover the basics of the implementations and point out the pitfalls I had to overcome below.

The events are show in the calendar day through implementing the DayRender event of the ASP.NET Calendar Control.  I loop through the events, add them to a string builder and then output that string into the control. 

...

For Each dayEvent In events

    …

     myString.AppendFormat("<div id=""" & myEvent_ID & "_" & e.Day.DayNumberText & _
 """ class=""event""><a href=""javascript: showEvent(" & myEvent_ID & _
 ",'top','" & rightOrLeft & "', " & _
 e.Day.DayNumberText & ")"" class=""e"">" & DisplayedLink & _
 strDisplayedCalName & DisplayedTimeRange & "</a>{0}</div>", strEditLInk)
Next

'Write the Event Info to the cell
e.Cell.Controls.Add(New LiteralControl(myString.ToString()))

You can see that I have not included all my code, but you can see that each event is surrounded by an anchor tag that called the showEvent() javascript function.  This function passes a unique identifier of the event, how to display the box (e.g. top, bottom, left, right) and then the day number (needed to included day number because some events span multiple days with the same event number.  The day tells the javascript function which event in the UI to show the call out next to.

Javascript Functions

Here is the showEvent() function

function showEvent(id, posV, posH, day)
{
    $('.event').attr("class","event");
    $('.eventDetail').hide();
    $('#' + id + '_' + day).attr("class","event eventSelected");

    var myClass = 'eventDetail';
    if (posV == "bottom") { myClass = myClass + " bottom"; } else { myClass = myClass + " top"; }
    if (posH == "left") { myClass = myClass + " left"; } else { myClass = myClass + " right"; }

    $.ajax({
        type: "GET",
        url: "callbacks/ajaxcalendar.aspx?cmd=showEvent&id=" + id,
        success: function(htmlContent) {
            $('#' + id + '_' + day).append("<div id='hover_" + id + "_" +
            day + "' class='" + myClass + "'>" + htmlContent + "</div>");
        }
    });

}

First thing it is resets the classes.  This has the effect of closing another callout box if one is currently open.  Then the currently selected callout is selected (given the class "eventSelected").  Additional classes are added to the event to tell the box where to render in relationship to the event.

The event id is then used to make an ajax callback to get the details of the event (this prevents a large amount of data having to be loaded into the DOM on page_load()). 

To close the call out there is a very simple call that resets all the classes on the event objects.

function closeEvent()
{
    $('.event').attr("class","event");
    $('.eventDetail').hide();
}

 

CSS

The CSS if very important in this implementation because it controls how the callouts are displayed.  An interesting bug I ran into while working on this is the IE 6/7 z-index bug that has been exceptionally well documented by Aleksandar Vacić.

Here is the important CSS

.event { position: relative; z-index: 1; font-family: Arial, Verdana; font-size: 9pt; line-height: normal;  font-weight: normal; margin: 0; padding:0; }
.eventSelected { color: #fff; background-color: #b22222; z-index: 2;  }
.eventSelected a { color: #fff;  }
.eventDetail { position: absolute; width: 290px; border: 5px solid #b22222; color: #333; background: #fff; z-index: 999; }
.eventDetail .eventContent { padding: 10px; }
.eventSelected .eventDetail .eventContent a { color: #b22222; }
.eventDetail .eventHeader { background-color: #b22222; padding:0 0 6px 0; color: #fff;}
.eventDetail .eventHeader a { display: block; float: right; }
.eventDetail .eventFooter { text-align: right; margin: 5px 0 0 0; padding: 0; }
.eventDetail h1 { margin: 0; padding: 5px 0 5px 0; font-size: 1.4em; line-height: normal;}
.eventDetail h2  { margin: 0; padding: 0; font-size: 1.2em;}
.eventDetail h1 IMG { border: 0; padding: 0 5px 0 0; }

.top { top: 0; }
.right { right: -300px; }
.bottom { bottom: 0px; }
.left { left: -300px; }

You can see that the z-index of event and eventSelected needs to be set differently.  This compensates for the IE6/IE7 z-index bug, ensuring that the event detail does show on the top of future events.

That's about the scope of it.  Please post any questions or comments you have.

Special thanks to Matthew Smith of Squared Eye who advised me on the layout.

 

[ Leave a Comment ]

T-SQL Loop through SELECT Statement

I recently changed the a data structure in calendar program and needed to move some data around.  Normally to do this I would write an external app to query the database and rewrite the data.  This time I decided to try using T-SQL.  It worked great.  Below is my code:

DECLARE @Event_ID int

DECLARE my_cursor CURSOR FOR
SELECT Event_ID FROM ITS_CALENDAR_EVENTS_LIST
WHERE EVENT_SA_Flag = 1

OPEN my_cursor

FETCH NEXT FROM my_cursor
INTO @Event_ID

WHILE @@FETCH_STATUS = 0
BEGIN
    INSERT INTO ITS_CALENDAR_EVENTS_TO_FLAGS (Event_ID, Event_Flag_ID)
    VALUES (@Event_ID, 1)

    FETCH NEXT FROM my_cursor
    INTO @Event_ID
END

CLOSE my_cursor
DEALLOCATE my_cursor
Technorati Tags: ,,

[ Leave a Comment ]

Pattern Tap Tap Tapping

About a month ago I was introduced to Matthew Smith at Squared Eye.  He and I are currently engaged in a project called Pattern Tap.  Pattern Tap will be a site for organizing and filing design inspiration.  A design gallery for the web that is not based upon whole sites, but upon the component parts that make them up.

The rationale behind the site is that as developers and designers we often want to look, not just at beautiful sites, but browse beautiful UI components that make up a site.  For example, I might have a wondering about how I should format a list, a table, the navigation, etc.. and want to see how other people have handled those specific design patterns.  Enter Pattern Tap, a place where you can get into the nitty-gritty of design.  

Matt and I have started, and the development is well under way.  I will try to post regular updates as things unfold.  You can also stay updated on the progress of Pattern Tap by entering your email on our sign up page, following the Twitter feed or tuning into our Friday updates

For the Developers: I am implementing Pattern Tap on top of the Code Igniter PHP framework.  Out of the different PHP frameworks out there, this one came recommended as a good blend (kind of a mid-weight system).  For a JavaScript library I am using jQuery.  Of course the implementation will be XHTML validated code. 

 

ScreenShot003

 

[ Leave a Comment ]

Next,

My Pictures

CIMG6647CIMG6646CIMG6643CIMG6641CIMG6640CIMG6638CIMG6637CIMG6635CIMG6632CIMG6629

Chris Pollock

Web Developer - proficient in both PHP and ASP.NET.
Rochester, New York

View my web developement site.

View Chris Pollock's LinkedIn profile

My Pictures

CIMG6647CIMG6646CIMG6643CIMG6641CIMG6640CIMG6638CIMG6637CIMG6635CIMG6632CIMG6629