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)

IIS7 and 301 Permanent Redirects

Lets say your launching a new site to replace an old one.  You want to make sure that peoples bookmarks and search engine information does not return 404 page not found.  The typical way of doing this is to create a 301 permanent redirect on the old file.  In IIS6 this was a complete pain.  You had to click on every file in the IIS6 manager (before deleting the file) and setup a redirect to the new page.  Time consuming and not very good IMO.  

IIS7, and its integration with the web.config makes this process so much easier.  Look at the example below for an example of how to specify 301 redirects in your web.config file:

  <location path="ComputerLab.asp">
        <system.webServer>
            <httpRedirect enabled="true" destination="Labs/" httpResponseStatus="Permanent" />
        </system.webServer>
    </location>
    <location path="EmailSpamSolution.asp">
        <system.webServer>
            <httpRedirect enabled="true" destination="Support/Spam.aspx" httpResponseStatus="Permanent" />
        </system.webServer>
    </location>
    <location path="MicrosoftOffice2007.asp">
        <system.webServer>
            <httpRedirect enabled="true" destination="Training/Help/Office2007.aspx" httpResponseStatus="Permanent" />
        </system.webServer>
    </location>

Note: these additions go directly inside of <configuration> and NOT inside of <system.web> or <system.webServer>

 

Technorati Tags: ,,

[ Leave a Comment ]

Productivity & Organization

As a entrepreneur, web developer, husband and father of four, staying organized is not just a “good idea” it is and absolute necessity.  In this post I will unpack the productivity tools that I rely on to keep afloat in the flood of information.

 

Basics

Email is where it’s at for me.  It is the center of my productivity world.  Most of my work, in some way, touches my email.  I have used Outlook and Gmail extensively, and in my estimation Gmail wins!  For me the context threading of emails was a stroke of genius by the Google engineers, and that along with a host of other highly usable features has won my loyalty.

 

Gmail

Gmail is my information hub.  Here are a couple of things I do to keep the things flowing.

Filters & Labels

Filtering is the first line of defense.  When one of my contacts fits a category, the get a filter and a label so that I can keep all those correspondences together.  If I am on any sort of list does not require my attention, I filter off those emails so they never even appear in my inbox.  They are labeled, so i can easily get to them if needed.

ScreenShot008

ScreenShot005For labeling I use the Folders4Gmail script that turns your labels into a folder like structure.  This method helps cut down the visual noise of the "Labels” sidebar.

 

Zero Message Inbox

Several months ago I adopted the stance of trying to keep my inbox empty.  This has been excellent.  When there is information in my inbox, my eyes constantly go over it, rereading subject lines, sorting through visual noise, wasting precious time.  The biggest aid to achieving the zero message inbox was the Remember the Milk plugin for Gmail (more on this in a minute).

ScreenShot004

In short, every email that comes in is either: Deleted, Archived, or made into a Task.  In some cases a label is applied where necessary.  The idea is to keep things moving and not to allow the visual noise to build up.  Read it and decide what to do with it, don’t postpone this decision (It’ll just take longer next time).

Remember the Milk Plugin

ScreenShot003 For a long time I mourned the lack of a “todo” list inside of Gmail.  Finally, Remember the Milk (RTM) came to the rescue.  To keep my inbox empty I am constantly turning email messages into tasks (RTM has some slick ways of doing this).  I make it a task and archive the message.  When that task comes up, the email message is readily accessible through the RTM interface.

In addition to assigning emails to tasks, I can create independent tasks which are dated so that I only ever have to look at “today” and “tomorrow” to know what I need to do.

Its not complicated, and it keeps my life a bit more simplified in the deluge of information that comes to my door step every day.

 

 

Todoist

Being a developer, I need a tool to help me manage the projects I am working on.  The best interface I’ve found for a sole developer to keep track of a project is Todoist. Todoist is a super simple, super slick task management application that has a couple of core features that I find very helpful:

  1. Interface is simple and easy to use.  Simple keyboard shortcuts allow you to add, edit and organize tasks quickly.
  2. Organization of tasks into projects
     ScreenShot007
  3. Ability to organize tasks into hierarchies. 
    ScreenShot006

The third point is the real winner in my book.  Being able to quickly and easily create tasks and sub tasks really helps me to organize my development projects.  On top of this I can reorder the tasks.

What would really transform Todoist into a great web application would be the ability to interact with others.  For instance, others could assign tasks to me and vise versa, and then I could organize them appropriately.  I know this feature has been requested, so we’ll have to see where it goes from here.

 

In Closing

Above I’ve tried to outline the key tools that help keep me productive on the web.  Share your advise!  If you’ve got some processes which have really helped you be more productive, please share them in the comments below.

 

[ Leave a Comment ]

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 ]

Speed Up Web Browsing with OpenDNS Shortcuts

A couple of months back I started using OpenDNS, a DNS service that offers a number of nice services. One that I have just started to utilize more is the shortcut feature. OpenDNS allows you to define short cuts that you can type right into the address bar of your browser.  The great part of using OpenDNS for shortcuts is that they are browser and system independent.  So on any browser on any computer connected on my network (OpenDNS is setup in the router), I can access my URL shortcuts.

I've started to add more short cuts to those commonly accessed urls.  Its very easy to setup:

ScreenShot004

So looking above you can see in order to get to gmail, all I have to do is type "g" in the URL address bar.

Filtering

Another nice thing about OpenDNS is the filtering service.  If you're one of those people who doesn't enjoy naked people showing up on their computer (expectedly or unexpectedly), OpenDNS is a nice way to filter your Internet connection from all sorts of nasty stuff.   If you have kids who can get near a computer and pound away on the keyboard, you will definitely want to consider this service. 

[ 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 ]

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 ]

CushyCMS and UserVoice - found two great web applications in the same day

CushyCMS_logo

Paying attention to my daily feeds I found a new web application called CushyCMS.  CushyCMS allow users to edit web content WITHOUT the necessity of installing any third party CMS software on the server. For existing sites and small projects this seems life a fabulous tool.  It seems to be be dead simple to use and setup.  I watched the 5 minute intro and found out most of what I needed to know!  On the technical side, the designer/developer simply includes a class on any of the DOM objects that he or she wants the editor to be able to edit.  CushyCMS parses the contents (accessing your site through FTP) and only allows the editor to edit the content areas you have designated.  Seems sharp, and easy to use.

When providing some feedback about CushyCMS I found that they were utilizing another new web application called UserVoice.

ScreenShot001

UserVoice looks like a simple bug tracking and user feedback program that allows the user to tell you what problems are most important to them.  I had a few problems logging in the first time, but other than that, the program seems to work well, allowing even anonymous users to vote on which issues they are seeing as problems or features that need to be added.  When developing my next web application, I may look to this app to get at my user base.

[ 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 ]

Things I see

Emerging LocustEmerging LocustSimonbackgroundSimon - 2 monthsSimon - 2 monthsSimon - 2 monthsSimon - 2 monthsSimon - 2 monthsPlaying in the YardPlaying in the YardPlaying in the YardPlaying in the YardNY to MO to NY GatheringNY to MO to NY GatheringNY to MO to NY Gathering

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

Emerging LocustEmerging LocustSimonbackgroundSimon - 2 monthsSimon - 2 monthsSimon - 2 monthsSimon - 2 monthsSimon - 2 monthsPlaying in the YardPlaying in the YardPlaying in the YardPlaying in the YardNY to MO to NY GatheringNY to MO to NY GatheringNY to MO to NY Gathering