Monday, April 21, 2014

­ the anti- 

Many of you probably know about &nbsp; the "non-breaking space" -- I think it gets used more often for padding than anything else. Lesser known but possibly more useful is &shy; the "soft-hyphen", like when you have a compound word or what not, maybe something separated by - or /, and you want to say "it's ok to insert a linebreak here, but otherwise keep these parts next to each other." Word is most browsers now support this. (For a while it was in competition with the oddball tag <wbr>, but it seems to have won in this HTML5-ish world.)

Saturday, April 19, 2014

cheap infinite scroll in jquery

"Infinite scroll" is what you see on twitter and tumblr, where scrolling to the bottom of the current set of entries triggers the load of the next set.

I was looking for something similar for a work project. The jscroll project seemed to be it at first, but on closer inspection is about loading the next set of static content, and I was looking for a "simpler" trigger of a callback to load the next set of data via jQuery.

I ended up rolling my own, with a little help from the stack overflow entry Check if element is visible after scrolling.  (Note for this and the next code bit: for this project, my company uses the more verbose "jQuery()" rather than "$()" because of namespace conflicts. Also, I am encouraging the use of "jqo" as a Hungarian Notation prefix to indicate a jQuery Object.)

So when I set up the table, it's something like:
jqoTable = jQuery("<table class='mixgrowGrid'></table>");
jqoSpot.append(jqoTable);

jqoScrollTrigger = jQuery("<div class='mixgrowGrid_scrollTrigger'></div>");
jqoSpot.append(jqoScrollTrigger);

jQuery(window).scroll(checkForInfiniteScroll).resize(checkForInfiniteScroll);


I made a variable noMoreToLoad that is set to true when the query has returned all available records (in practice, this is set when the "next batch" query returns an empty array). So at the end of of my data receiving function, I write
if(!noMoreToLoad) checkForInfiniteScroll();

And then the supporting code is:

var checkForInfiniteScroll = function(){
    if(isTriggerScrolledIntoView()){
        if(!noMoreToLoad){
            loadNextSet();
        }
    }
}
var isTriggerScrolledIntoView = function(){
    var docViewTop = jQuery(window).scrollTop();
    var docViewBottom = docViewTop + jQuery(window).height();

    var elemTop = jQuery(jqoScrollTrigger).offset().top;
    var elemBottom = elemTop + jQuery(jqoScrollTrigger).height();

    return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom)
        && (elemBottom <= docViewBottom) &&  (elemTop >= docViewTop) );
}

So why am I doing all this? "mixgrowGrid" is meant to be a substitute for jQuery datatables. Datatables is great if you want to take an existing html table on a page and bless it with client side functions like sorting and filtering. It handles infinite scrolling too, but poorly in my opinion: you pretty much have to have a fixed height display window (datatables seems more geared at pages where a table is just one element in the page flow, rather than being the center of attention, like it is on my company's dashboards) For the most part, I am less happy with widgets that carry their own scrollbar. My other beef with Datatables (besides its general complexity, which is par for the course for a genral purpose tool that tries to solve a LOT of different people's problems...) is that it is not great for mixed data; like if you have some parent/children rows, and especially if you would like some of the children rows to use "colspan". My mixgrowGrid says what it features in the name: mix-ed data (each type can have different column definitions) and designed to grow on the page.

There's a lot to do before this is ready for prime time: I will be making a footer that uses position:fixed to glue it to the bottom of the page, independent of the scrolling, and will probably have to do something similar for the headers, as well as install a "loading" notification. But one of the nice thing about rolling your own (the classic "Make vs Buy" conundrum) is that you can have a lot of control over that kind of detail, without having to learn and/or hack on someone else's big code base.

FOLLOWUP:
The header turned out to be pretty cool to do; I had to make a separate table above the main table (which means I had to make a separate function to make sure the widths were consistent with the main table, I didn't get that for free) and I had it be position:relative - the nice thing about that setting vs float is that it still preserves its space in the page flow, so things are simpler when it's "normally" visible, I don't have to think about making space for it. Then, on window scroll and resize (i.e. the same events as for infinite scrolling) I had this function, for the wrapper element (also position:relative, so that any children will be repositioned relative to it) and header table:
    var adjustHeaderLocation = function(){
        var eTop = jqoTableWrapper.offset().top; 
        var scrollTop = - jQuery(window).scrollTop();
        var newOffset =  -(scrollTop + eTop);
        if(newOffset < 0) newOffset = 0;
        jqoHeaderTable.css("top",newOffset+"px");
    }

FOLLOWUP TO THE FOLLOWUP:
I re-ran into a problem we had already solved, where it can be surprisingly tricky to make two tables the exact same width: border and padding and what not makes things weirder than you might expect. Some people suggest making a div version of the headers instead, but the short of it is you want to read the .outerWidth, not the .width()of the "td"s in question, and then apply that as the width, max-width, and min-width of the respective matching "th"s. Stackoverflow had some good discussion, including this bit of democode -- it looks like it could be a plugin, almost. I wasn't sure if the complex table I was building (with multirow headers) would use it as a drop-in, but I'll keep it in mind for the future.

Friday, April 18, 2014

more improvements to object like encapsulation in js

An improvement to what I wrote about here-- I was still thinking in terms of a singleton pattern, but I think it can be easily extended to be reusable:

With a setup
function someObject(init){
    var somePrivateVariable = init;
    var somePrivateFunction = function(){
        alert('shh');
    }
    this.somePublicVariable = null;
    this.somePublicFunction = function(){
//still has access because of function level scoping
        alert(somePrivateVariable); 
        somePrivateFunction();
    }
}

You can make multiple instances

        var m = new someObject(1);
        var n = new someObject(2);
        m.somePublicFunction();
        n.somePublicFunction();

Wednesday, April 16, 2014

simple pixel programs for OSX

There were two things I started missing when I switched from Windows to OSX: one is the program IrfanView for folder based image viewing and basic manipulation (resizing, cropping, rotation). Those functions are handled pretty well though with a combination of Finder's builtin viewer (hit space when a file is selected, then use arrow keys to navigate through the folder itself) and OSX Preview.

The other was an editor more advanced pixel work, without running smack into the cost and/or usability hurdles of Photoshop or GIMP. On Windows I enjoyed Paint.NET (after a decade of getting by with an ancient copy of Paint Shop Pro). It was tougher on OSX -- Pixelmator was somewhat ok, but did a lot of things oddly, and fell into the mistake of assuming its native format was preferable for everything. (Sometimes you just want to open a PNG, edit some pixels, and save it again, but that wasn't trivial in Pixelmator.)

Now, however, I think I might have found my new favorite: "Acorn". I didn't experiment with it before, but it (temporarily?) knocked down its price from $50 to $15, and it seems well worth it.

So: "Acorn" for OSX. Recommended, and well-priced. (For the time being at least.)

Monday, April 14, 2014

ye olde joins

Just a summary of some stuff I used to know pretty well, but it has been a while: (and also a little exercise in differences in how people visualize stuff...)
JOINS IN SQL LAND

Roughly, there are for kinds. Lets say you have a table A and a table B, joined via some ID.

  • INNER JOIN - gets you rows that appear in both A and B
  • LEFT JOIN - would return rows that appeared in A, whether or not they showed up in B
  • RIGHT JOIN - same as left, but swapping A + B
  • OUTER JOIN - would return all rows from A and B, whether or not they had entries in other table
To keep track of that, I found it useful to draw it out, the chart on the left. The syntax is a little wonky, of course. Scott, who was going over this stuff with me, thought Venn diagrams made more sense- his stickie is there on the right. I find it harder to wrap my brain around it, but I'm including it here as a nice display of different learning/visualization styles. 


(this reminds me of how odd it kind of is, how much of my SQL background was Oracle's flavor. Its old PL-SQL used a kind of wonky "(+)" symbol to indicate an outer (or optional, as they thought of it) join.)

Friday, April 11, 2014

a more joyous phone ui

I admit I kind of want a phone that looks like

with a UI that moves like
I was pointed to this interesting work from the site Minimally Minimal. I'm not sure if such happy bouncing and what not is within minimalism principles or not, but I dig it.

Wednesday, April 9, 2014

TRIPLE EQUALS CONSIDERED OVERRATED === = :-(

So, a recent popular idea in Javascript land is that it's always better to compare values using "triple equals", ===, which won't do type conversion, over good ol' "double equals", ==.

So quick example:
  var foo = 123;  //foo is an integer
 foo == "123"; //true, foo "double equals" the string 123
 foo === "123"; //false, because they are different types

I find myself disagreeing strongly with the preference for "===", for 3 iffy reasons, and I think one good one.

1. What I'm used to

I can sound like a cranky old hack sometimes, and remembering to type === and !== seems like a pain, and just kind of looks ugly.  Moreover, I cut my teeth on loosely-typed "Duck languages" like Perl. So if I read in a string and wanted to compare it to a numeric value such as 123, I wouldn't want to fail just because they were "different things", or came from a different source.

2. How I think about Java

Java's String primitive/object has a parallel situation that is deceptively similar, with .equals() vs ==, and I think I draw a false analogy.  To whit: for Java objects, == is only true when you have two references to the same object in memory, while equals() should be true if two different objects are equivalent. So for instance,
 String foo = "bar";
 foo.equals("bar"); //of course true!
 foo == "bar"; //don't count on it, buddy

So I learned to be careful, and use the "less strict" equals() for most stuff I was interested in. This makes me nervous about ===. Like, I'm almost skeptical that Javascript
 "foobar" === "foo" + "bar";  //true (amazingly ;-)
Yeah it works, but because I think of it in terms of what it looks like in Java, I don't want to trust it.

3. === is used to show off

It feels like an elitist shibboleth to me. (And yes, I love that knowing what "shibboleth" means is in itself a shibboleth.) To be fair, these people probably point to funkiness in the truthiness tables, and just odd asymmetries there, but in my heart of heart I think it's just a way for the with-it hipster coders to show they are with-it hipsters.

4. if(arg == undefined) //true for argument not passed, and null, but not for zero

Finally, this might be my most serious argument.

Say I have a function funk(arg), and returns its argument or a default of -1, if no argument is passed. (And of course it should work with 0 as a value) So:

function funk(arg){
  if(arg == undefined) arg = -1;
  return arg;
}

That works pretty well... (if I used the conditional if(!arg), that would accidentally catch 0 and return -1, and so in general I shun simple boolean expressions, preferring to check for undefined.)

So what I like about == is that is that funk(null) would be caught, and replaced with -1, but if I used === funk(null)would return null, because undefined === null is false.  (Of course, "null" and undefined are kind of odd beasts in Javascript land; some people think the "undefined" value is just an accident of history anyway.) (PS don't do stuff like using undefined as a real value, like calling funk(undefined) - that's just R,O,N,G, wrong.)

So basically, I prefer the behavior of double equals, and prefer its made up "this would fail!" arguments to the ones made in favor of trouble equals.

(Quick tip: if you don't know it already, the "console" you can get to in Chrome inspector or Firefox Firebug is great for doing this kind of little functional definition, tooling around with making and calling functions, just ignoring the page it's on. And of course it's an invaluable tool for poking around your Javascript in general.)

FOLLOWUP: A friend of mine points out "NaN" kind of messes up my simple != undefined filter, since it is defined, but probably not what we were expecting to work with what I described.