Thursday, June 3, 2010

Nifty New Incremental Usability Improvements


I made several modifications to the comparexy.com site today. Mainly usability tweaks. A little JavaScripting with JQuery, a little CSSing, and a little Grails/Groovying.

(Note: This blog is a continuation of the series that began with http://www.comparexy.com/compare/blog/2010-04-19/The+CompareXY+Site+Experiment)


(Screen shot with some arrows of affected features)

  1. Added a "randomList" action to the Grails site:



    • Previously, I was making round trips for every random suggestions that faded into the header. Now, I'm getting a batch of them from the server at one time.
    • Basically, now I take down a list of a hundred random articles or so at a time. Then the JavaScript and Jquery functions that randomly fade in a suggestion pull from the locally cached list until the list is exhausted (then it goes to the server to refresh if need be).

    In my Grails service I added the randomList(maxSize, maxState) method:     


    * The maxSize argument limits the maximum size of the returned list.   
    * There is not guarantee on how many records this will return.
    * The maxState argument allows for the method to distinguish between states of the articles (official, flagged, suggested, et cetera) 
    * Generates a list of random longs in between 1 and the maximum record. It will pass the list of random longs as a query param to Gorm's executeQuery() method.     
    * The controller calls this and turns it into JSON (not shown).       
    * I'm safe for probably ever, but I do have a TODO item to fix this method to not use integers, since I used the long data type as the tables primary key.   
    (excuse the formatting)   
    --snippet--


    List randomList(maxSize, maxState){
         
        int multiplyer = 5 //account for sparse data        
             int
    maxId = getMaxId()
             List ids = new ArrayList(maxSize * multiplyer)          
             for(int i = 0; i < maxSize * multiplyer; i++){
                 ids << new Random().nextInt(maxId).longValue() + 1 //add 1 to be inclusive
             }
             String hql = """
               SELECT comparison.thing1.name
                      comparison.thing2.name,
                      comparison.state
               FROM Comparison comparison
               WHERE comparison.id IN (:ids)
               AND comparison.state &lt;= :maxState
               GROUP BY comparison.thing1,
                        comparison.thing2     
              """         
             return Comparison.executeQuery(hql, [ids: ids, maxState: maxState], [max:      maxSize])  
    }

    int getMaxId(){
          String maxHql = """
              SELECT max(comparison.id)
              FROM Comparison comparison
        """         
    return Comparison.executeQuery(maxHql)[0] //returns a single unit list }
    --end snippet-
    
    
    



  2. Modified the page branding in the header, "CompareXY: A Comparison Library", so that, it will randomly morph into a clickable function call (click and it links you to the appropriate article). Maybe a little redundant with the other random suggestion box right beneath it. I'll see if it sticks to the wall I guess.

    Essentially the normal state of the branding header:
    CompareXY: A Comparison Library

    may morph into a clickable "function" link like:

    CompareXY("Hella", "Giga")

    and then back, cute :)

  3. Changed the random suggestion box that fades into the header to be weighted against less unwritten articles. The problem was, it always directing readers to unwritten articles for them to write instead of to articles that were already written. That is fine sometimes, but not most of the time. Hopefully, one day, the balance of unwritten to written articles will change.



    • I did that by calling the above mentioned randomList controller, putting the data in to a local cache and filtering out unwritten articles if there are too many.




  4. On a similar note, changed the Grails action called "random" to filter out 2/3rds of unwritten documents. Same problem as above, different way of arriving there :). This is actually just the static text link a the top of the header that calls a "random" action on the Grails server (so, no local data pulled here, although, now that I say it, I guess I could pull from the local data, and reduce one unnecessary redirection).

  5. Added a "Close" button to the ads on the right hand side (see the image):




    • This should allow user that are annoyed by an ad to just close it.

    • This should allow user that are on unusual windows sizes, or browsers to remove the ads if they don't float correctly. I know, I should really improve my cross browser CSS skills. I've got it working on IE, Firefox, Safari, Chrome, and Opera, but some older versions of IE, and my Palm Pre don't float the ads window.  Against the prevailing trends in the industry, I may just put the whole thing in a table to guarantee placement (or talk to a CSS guru). Alignment was so much simpler with table layouts :)




  6. Put a little nifty fish-eye effect on the browser search bar links when they appear in the ads section.

  7. Wrapped the ads in a border.

  8. Removed ad from showing up on the edit page.

  9. Upped the restriction on article size since I began running into it, and it is essentially arbitrary.
If you have any input/suggestions let me know. 

Tuesday, June 1, 2010

Bit.ly Links on Facebook

I noticed today by analyzing my server logs for comparexy.com that if I place a bit.ly url into a Facebook comment, when people click  on the link in Facebook, it does not go to bit.ly. Facebook has already captured the destination URL, and is bypassing bit.ly. This is a bit of bummer because I was curious about real-time analytics on the link. Oh well.