Friday, October 3, 2008

Huge performance boost during iterations

I've improved my code to the point during this latest round of optimizations, that I can get Safari 3.1 to load 4,356 divs (each with a few attached events, and 5 attributes, including styling) - to load in 657 milliseconds (.15 ms per item)

The status of my system at the time was a 50% memory allocation (of 1 GB), iTunes running, a text editor running, and the one browser. No heavy background services were running (polling).

Give it a try below and help me test! Please send me your results... :) To be fair, try closing down your apps and let ONE browser test at a time, with ONE tab. Don't let other processes get in the way. This will be the cleanest number.

If you get different results than me, or if the documentFragment results are slower, then don't freak out. Although its unlikely that this would happen, remember there is an entire world of variables to consider that make this kind of testing tough to streamline. Thats why I am exposing this and want your help.

FYI: The mouseover event does exist in both tests, and is being allocated, even if the addOption test doesn't mouseover with any visual changes. These samples are both in their own iframes, to ensure no preference.







  • You can perform two kinds of tests with both these boxes.
  1. The first is to put a large number into the box and run each. Then jot the results and refresh. (The first test simulates how a user would feel when a page loads and they have to wait for contents to render.)
  2. The second test is one where you load the boxes with a reasonable number, (say 100), then keep loading over and over again without refreshing. (The second test simulates an interface where a user is tasked with "adding elements" throughout their session. How does the box respond?)

Safari is by far the fastest rendering engine (all rendering engines are not the same! Google Chrome has added elements to their rendering engine, alongside webkit, that make it just slightly slower than Safari in the current 0.2. At least in my tests).

With this test I am creating divs that emulate a select box set of options. The top is my current performance, and the bottom is simply using addOption() to append native options to a select box in the DOM (I've tested this a dozen times in all, 10 times each browser (120 tests), ask me for the complete results and I will send.):

504 items:

Firefox 3 (me) : 198 ms (.4 ms per item avg)
Firefox 3 (native addOption) : 358 ms (.7 ms per item avg)

Opera 9.5 (me) : 177 ms (.4 ms per div)
Opera 9.5 (native addOption) : 136 ms (.3 ms per div avg)

Safari 3.1 (me) : 78 ms (.2 ms per item)
Safari 3.1 (native addOption) : 50 ms (.1 ms per item avg)

Chrome .2 (me) : 203 ms (.4 ms per item)
Chrome .2 (native addOption) : 416 ms (.8 ms per item avg)

Ie7 (me) : 359 ms (.7 ms per item)
Ie7 (native addOption) : 382 ms (.8 ms per item avg)


The key to all of this is when and where. If you write your methods correctly, you can massage where code is invoked, and when to push your performance over the edge.

1. When it comes to large scale iterations, don't use the toolkit DOM methods to create and insert the bulk of your objects.
  • I know, it's crazy. But hear me out. There are pain points somewhere in your application where things slow down when using a toolkit. What I am saying here is that during the page load, or when returning an ajax response of 150 divs (e.g.) - don't use the toolkit to wrap these up just to get special features.
  • You can use the toolkit to iterate, but during that iteration, separate out the methods to help minimize the dirtiness. Inside those methods, get dirty and write plain old javascript for a huge performance boost* (see below to see more of what I mean here).
  • Meaning, don't use the append, create or addevent (bind) methods (see more detail below), but use everything else (createElement, onmouseover = function, setAttribute). You can certainly use these for most of your operations, sure, and that's the point of a toolkit. But not for these heavy iterations!
  • Create your own internal "shadow" array in memory of these objects with its base styling and base events, then, when the DOM has rendered, and for the rest of your application, wrap jQuery (or new Elements $) around your items and proceed as normal to style and add effects - or wait for just the right time to invoke these styles and events.
2. Use a documentFragment when creating elements.
  • documentFragment is your #1 friend. Instead of appending to the DOM at the end of every iteration, append to a documentFragment Element, then lastly, append the documentFragment element to the DOM.
  • This works 3x faster because it is all kept in memory - not in the DOM, where rendering is slow. It is added to the DOM later and without any effort on your part, the documentFragment melts away.
  • This has been around for years and supported by all browsers.
3. Use very short custom attribute names.
  • Except for id, className and title, make your custom attribute names be 2 characters or less. This will shave many milliseconds off your rendering time.
4. Bind Events within Events
  • Did you know that if you really plan, that you only have to bind one event to an object? Yes, the mouseover event! Inside that event, bind the rest of your events conditionally. Why pay that price over and over again during iterations?
5. Add classes and styling carefully. (IE can choke)
  • Here is where things get hairy in IE, but if you must make ie run faster, then do this: Set the className (or "class" in non-ie browsers) by hand using setAttribute. Faster than any toolkits "addclass". Don't even use the item.className = class. Just use setAttribute.
6. For ie, use innerText, not createTextNode
  • to inject text. I saved 30-80 ms per item doing this
7. Use Native events like onmouseover = function()
  • ...not toolkit addEvents or bind. Except for the little trick I mentioned above, don't bind or addEvent() during heavy iterations.
*What I mean by dirty: I mean writing plain old javascript. And by "inside these methods" I assume that you are using some kind of OOP-like style and have separated your methods too keep them small and to make sure they do one thing well. That being the case, I assume that during an iteration, you have one method for just attaching events. Its in here that you "get dirty" and write plain old javascript.

Also...
  • Aside from the two types of tests, you need to test both types of boxes. One uses documentFragment technique, and one uses addOption by comparison.
  • Note: if you get the "browser / script is running too error" let me know. The documentFragment test works differently in different browsers, but the addOption test can't handle large numbers! Another testament to using documentFragment.
  • Note: if you want to see how I did the tests, please grab the js file in the source. If you want an explanation of what I did, please comment and I will give much more detail (probably not necessary for this).
If you want to see examples I will definitely share!

Tuesday, September 23, 2008

Select Box Factory 2.1 (with graph)

I guess I can't leave well enough alone, but once i saw the css graphs on this page http://apples-to-oranges.com/goodies/css-for-bar-graphs/, I had to figure out a way to use them. Have a look by clicking the graph icon, then mouse over the bars and labels. Then, starting loading in different colors and watch the graph grow. (removal is shown in help guide).




The thing to realize is that this is by no means a static graph. It is always accurate to the states and numbers of items in the select box (even if you add or remove items).

Granted, it took some time even beyond that demo to get the css to work. I had to deal with max-height, and list-style-type, and it took some time to wire the logic into this chart, but the results are enjoyable. The demo here is relatively positioned, but you can tell this graph and even the dropdown (or a mix) to be absolute, and it will coast over the text instead of pushing it aside. I have it relative for the demo.

The way I have this written, and with the options I added, you can use any labels and build up to 5 states, which hopefully is plenty. You can use any colors too, but the css demo uses background-position for the colors, so you will need to update a very small image. I will be building a skinning set so you can simply choose your color theme and away you go -that is not there yet.

The graphs are the default css colors and image from the site, but they are configurable, and the labels are no longer built into the image.

help guide

Sunday, September 21, 2008

Select Box Factory 2.0 for jQuery

Note: Interested in show a bar chart? Try Select Box Factory 2.1 for jQuery (Help Guide & Download)

Otherwise, see 2.0 below:

Welp, i'm finally done transforming the code to be usable as a tool if you have jQuery 1.2.6+. I've spent many a week trying to perfect this in various browsers, and compiling a help guide.

Please see this link for everything you need to know.:

Select Box Factory 2.0 for jQuery (Help Guide & Download)

(give it a second to load, i've added a ton of dropdowns and code for examples in an accordion widget).

Sunday, September 14, 2008

UI Logger v1.2j

Below is just a snapshot of the brand new version 1.2j (using jQuery - as of 9.14.08) logger so you can see it, the link provides more. See below for the various versions.

View log in action and learn about all options and settings.




download v1.2j (as of 9/14/08 1:57pm)
View 1.2j log in action.
  • Version 1.2j is new and uses uses jQuery 1.2 and the jQuery ui draggable code, and has a slightly different UI. Supports IE6+, Firefox 2+, Safari 3+, Opera 9.5+, Chrome 1+. The log.js is also about 5k smaller, for essentially the same code, but required more k of plugins.
download v1.2 (as of 9/12/08 9:15pm)
View 1.2 log in action.
  • Version 1.2 uses uses mooTools 1.2 and has more features, seen in the above link. Supports IE6+, Firefox 2+, Safari 3+, Opera 9.5+, Chrome 1+.
download v1.1 (as of9/9/08 8:27pm)
View 1.1 log in action.
  • Version 1.1 is deprecated and uses mooTools 1.11 and has less features. You can't use the resizer, there are more visual bugs, and a few display options are missing. You can still use it for development with mooTools 1.11 here.
  • Future fixes: will use position: fixed (not for ie6) to stop redraw flickering.

Friday, September 12, 2008

(about john resign and dojo)

Visual Jquery
  • "window.addEvent() is not a function" as it is in mooTools. I want to add an event to the resize() and scroll() functions of the browser window. Ok, let's see how to add an event to the browser onLoad using jQuery. Thanks to the Jquery site, J.Eggers, random acts of coding and Jorn Zaefferer I got my first glimpse at how to go about this.
Here is how I managed to get the onload events to work in JQuery. You use "ready" instead of adding the onload event to the window. Next...


$(window).ready(function(){
$(window).resize(function (evt) {
log.positionLog();
});
$(window).scroll(function(evt) {
log.positionLog();
});
});



  • Success. Is it right, is it wrong? This is where things get really hard for coders who honestly don't have the real deep, deep understanding of the frameworks. I might be happy that this works, but maybe I don't have to call the window object from within the window object. Why can't this.scroll() work once inside the object event? I don't know and honestly, I am sure I will learn in time. It is things like this that cause memory leaks and bugs. The framework allows me to do what I think is right, and I am happy that it works. But is it really right?. Time will tell.
Turns out all I need to do is this:

$(function(){
// add my events in here.
}

This is a nice shortcut.

  • Now that I have a basic understanding of at least a few ways to add events to elements, what of creating elements by scratch? in mooTools, i simply say new Element(type, options).
In Jquery, again, there are several ways to do this, but I chose a simple way and it worked.

this.container = $("

Hello

").appendTo("body");


- i dont like how mouseleave and mouseenter have no shortcuts, so now I need two different ways to bind events.

-I dont like how I have to print HTML into the div call, but i guess it may make things easier, I just prefer the conceptual difference with addEvent.

- I dont like how I have to dance to get the browser version. Much easier in mooTools.jQuery.browser.msie && (jQuery.browser.version <= 7)

- whereas I found the addition of dynamic elements to the dom intuitive and quick with mooTools, I find it frustrating with Jquery.

- I love the css styling. I love computed width and height. Mootools does this too, but it seems easier in JQuery.

- $each is now $.each and of course you don't need to bind this.

- You use a string id "#logContainer" to find an element you just added.

- $$(item) os $(item).get() in jQuery.

- fireEvent is trigger()

- makeDraggable with an onDrag function becomes draggable with drag function.

- getCoordinates has no bottom or right style.

- containment is a nice property on draggable element.
- the draggable control doesn't take into account a scrollable area, and pushes your element to the top.

- I love how you can call width() to get the offsetWidth.

- i use log.append() to add ChildNodes, andin mooTools I was also supposed to do that, but I forgot to. I like how JQuery seems to nicely guide you towards using the framwork.

The problem was, when I alerted $("logContainer").innerHTML, I kept getting "undefined".

issues: i kept finding old jquery code examples. HArd when stuff just doesnt work.


Wednesday, September 10, 2008

Select Box Factory v1.1 Wish List

I am working on version 1.1, cleaning up any logic or display bugs and trying to make it a bit more elegant... in the meantime, i am planning a list of features to include in the next revision.

Everything grayed out is now completed in version 2.o, at the top of this blog.
  • Port over to mooTools v1.2 (possible future version)
  • Port over as a jQuery 1.2. I've converted my first widget to jQuery and the transition was not bad.
  • The ability not to have to use ctrl key to add options to a multi-select box, although I will leave shift alone. (version 2.1) Also, somehow something for mac users, who have the command key...?
  • The ability for the user to expand or collapse the box as they see fit. It would literally be a pliable, resizable widget to let users see more. This will be available in limited scenarios.
  • The ability to invert selections. (version 2.1)
  • The ability to emulate and take optgroups. (version 2.1)
  • performance and display enhancements.
  • Eliminate the need to have any divs in the HTML to create a dropdown dynamically. I thought i had this covered, but it needs a few more tweaks. Apparently you still have to have 2 divs on the screen. I will clean this up asap.
  • I was considering also showing how you can use Ajax to load the dialog. I do this at work, using HTML but you can also parse XML or JSON (using mooTools), and I can show examples for how both are done. (version 2.1)
  • The possibility of a history... recording last few items found (for the sift tool). This may be too much. (possible future version)
  • I thought I might also show the dropdown being used inside a dialog. You may have some trouble getting these to work positioned absolutely, and I can show how I've solved this problem, even getting dropdowns to stack with zIndex so they don't open under each other.

Sunday, September 7, 2008

Why bugs appear in software

Where do bugs come from and why are they always there in software development. Almost every engineer will give you a different take on the subject, and this is mine. I try to focus what I feel is common to all engineers. I'll be modifying this slightly and massaging it over time, since I want it to be comprehensive, maybe even with charts. But this is "1.0" of my article.


In Summary:
Here is the summary before the breakdown. All complex systems, and i mean ALL complex systems have their form of "bugs", or deviations from the norm - since this is the nature of the universe. Seen from that most generic point of view, bugs are inevitable, unavoidable and often times expected.

Software exhibits bugs when...

  • the use cases driving the software are not fully understood or change during development.
  • the code is too rigid - lacks flexibility and robustness
  • the developer uses bad practices and makes it hard for new developers to read and use the code, or even himself 6 months down the road.
  • there are too many levels of communication in the stack of code, or layers of indirection. Concepts degrade from receiver to receiver resulting in corrupted information.
  • the long and complicated string of logic required for development is somehow interrupted.
  • any many more... please read on for a comprehensive set. I don't think this is really in any order yet.

1. Constraints

Time
  • Time is both the whip that prods the engineer and the pressure that cooks the engineer from coal to a diamond.
  • Learning how to code with time constraints forces the engineer to gain efficiency - which means less code and less bugs : elegance. And as we all know, the best code is elegant code. Elegant code is the holy grail of development. It is not the end goal, rather, functionality is the end goal, but elegance is the grail.
  • Time, however you look at it, is a force exerted upon the developer. Decisions must be made, often without the time to follow those use cases to their best end result. Because of this, the core of the system design, no matter how small - is naturally going to suffer in the realm of robustness and flexibility. When these two attributes suffer, the possibility for that or other developers to add buggy code is higher.
  • A separate metric here is experience - time as related to experience shows (graphically) that as the experience of the developer grows over time, the likelihood grows that robustness, flexibility and overall elegance of the system will be in place before the product is released.
Other projects, part 1
  • Bugs are possible even when a developer is focused on one project - but this is rarely the case. Often times, and especially in an environment that lacks sufficient talent for so many burgeoning new projects, developers are forced to do more than one project at a time. The same resource must be divided amongst many projects and this leads to the lack of sufficient time, and lack of time leads to bugs.
Lack of knowledge
  • I consider this to be a constraint. Lack of knowledge here is not lack of expertise. The knowledge here is twofold: knowledge of what the use cases are that the software should support (in use-case driven engineering) and the overall knowledge of the group within engineering - the engineer's surroundings.
  • The first aspect, use cases, shows us that bugs can get into software when use cases are either not fully understood by the engineer for whatever reason or when use cases are introduced, and then changed over time.
  • The second aspect, surroundings, shows us that bugs can be introduced when the engineer is working in a team, but for whatever reason is not synchronized with that team in terms of his or her knowledge - the knowledge about exactly what everyone is doing. This can happen over long development cycles. Again, the engineer has to backtrack or modify the code, resulting in bugs.

2. Changes

Use case changes, scope creep
  • Changes in use cases often times happens during the product development and causes many bugs. Use case changes are the most dramatic and damaging of all possible ways that bugs can be introduced. This can happen when those responsible for the use cases of the software suddenly realize that they were wrong, the customer was wrong, or that the use cases outlined are not enough.
Other Bugs
  • Bugs beget bugs! The biggest reason why bugs cause bugs is because of the inevitable lack of robustness or lack of elegance in code. When a developer has to fix a bug, it is very, very likely that they will fix one bug and cause another. This has to do with all of the bullet points listed on this entire page.

3. Emotional Coding
  • Even the most hard-nosed iNTJ, introverted genius savant will have some aspect of emotion in their code. We are emotion and logic driven creatures. Because life outside of the world of development is full of complexities, it is nearly impossible to remove all that when you code.
  • Anger, lust, lovesickness, spite, joy, disgust or overwhelming glee can occur even when developers are in their Coding trance. All of our bodily movements, and even our ability to formulate logic are driven by emotion of some kind, even at the most animal level - for we are fright-or-flight creatures first, and rational man second. Even the brain shows us in its structure hierarchy that reason and logic are built upon the concepts of movement, lower-level emotion, and survival.
  • So what does all this emotion mean? Everything. There are only so many keys on the keyboard to press in order to input characters to the screen which will ultimately become code. The neurons that fire to command your fingers to code logic one way versus another is entirely subject to the current emotional experience of the developer. Trances help to limit this kind of development, but can't be removed entirely. As a result, and over the lifetime of the software development, there are subtle variations in the robustness and flexibility of the code.

4. Distractions

Other projects, part 2
  • Bugs are possible even when a developer is focused on one project - but this is rarely the case, as I said already. Switching gears between projects increases the likelihood that ideas will be forgotten and deviations from robustness and flexibility will increase. This is a fundamentally different problem than simply having more than one project. In other projects, part 1, I outline that the division of a resource across projects reduces time per project. Here I am saying that switching gears among projects leads to confusion, inefficiency and ultimately to stress and emotional coding.
Other People
  • Those darn other humans! They keep taking me out of my coding trance! This leads me to code more emotionally. This leads me to distraction. Distraction helps ensure that I will forget the very long and complex string of logic I had to create in order to make the software work. This is a necessity in the work place since no man is an island. We work in engineering teams and must be able to focus on other people.
  • Noises, especially these days are at an all time high. People take for granted all the clicks, beeps, boops and rings that are in the office environment. It is often true that people with the talents of coding exhibit traits of introversion (but not always), but also traits of sensory sensitivity and enhanced abilities to view systems as a whole, assemble and disassemble complex patterns, and abilities to string together long strands of complicated logic. The same systems allow engineers to be easily distracted by impurities of environment. Impurities, like real flying bugs, destroy the experience.

5. Levels of Expertise

Experience
  • Achieving any level of homogeneity in an engineering team regarding experience is tough - but well worth the effort. Having most of your developers at roughly the same level of experience will ensure that they are all playing the same game. Can you imagine if a baseball team or a football team was forced to play their weakest players at all times? In the office, we can bench our weakest players, but in the end they are touching code and inexperience means bugs. Nobody is sitting on a bench doing nothing or they would be let go in the blink of an eye.
  • There is not much else here to say. The more experienced you are, the more likely you are to write sustainable, robust code. The less experienced you are, the more likely you are to write inefficient code which leads to bugs.

Complexity of the system
  • This could be considered a constraint, but there are many levels of communication in the average stack of code. From the thinest user-interaction layer of the browser, to the business logic, to the database, often times there are 3, 4, 5, 6 or more layers of independently self-sustaining software platforms or "tiers" that make the software run. And that is just the software that is being created. Imagine all the layers involved when software is installed into software! The fact that anything works is nothing short of an absolute miracle. Very few non-developers will truly appreciate this.
  • Concepts degrade from receiver to receiver resulting in corrupted information. The bible lost a lot of its original meaning when translated from language to language over the course of thousands of years - and the analogue of bugs here is the mistakes of interpretation

Finally...

When it comes down to the nitty-gritty, development, as in life shows the true nature of the engineer when things aren't going well. We do get credit for our ability to plan, but the true measure of an engineer comes when forced to deal with the inevitable bugs that arise from their or some other software.

"It's not about how you plan, its about how you deal with crisis."

Friday, September 5, 2008

Waste Management Part 1

(Taking a brief detour away from code for a moment). Have a look at the picture just below. If you are anything like me, you are absolutely baffled at how a perfectly self-sustaining bottle of medication needs to be stuffed inside of a much larger box. Yes this is exactly how it came. Read on...


It wouldn't be fair if I didn't at least try to deduce why on Earth CVS decided to use such wasteful and useless packaging. The almighty dollar is at play here, because logic, common sense and consideration are certainly not. Here is what I came up with.

  • CVS came out with this to compete with Zyrtec, and Zyrtec has quite flashy packaging. Its possible that they needed a larger box to ensure fair product placement in the aisles. Is that the reason? Then consider my idea below.


  • Merely one cardboard slab, held in a slot above the price, yet in front of the product, but just below it, would emulate the experience of fair product placement. Behind this are all the little bottles on their own. Saves space for more product. Saves cardboard, recycling, money and my sanity.

If you think, like I do, that the above is bad, then consider Prilosec. First, the amount of packaging...



Second, the amount of actual product. YES, thats it. All these pills came from that pile above. Read on....


I do rely on these medications to some degree, so I am thankful they are there - don't get me wrong. However as someone who has devoted much of his life to improving interfaces, I have to say that I have similar concerns about waste in developing software.

The concerns are aligned when i consider the sheer weight of the pages the user has to download - and the speed at which the browser must render the page. The slower the experience, the worse off we are at selling the product.

As a designer and as an engineer, I am always on the search for the simplest possible solution that gets the job done - so the above pictures are nearly criminal to me, and cause me a certain amount of grief.

Things like this are why I got into the industry in the first place - but it wouldn't be fair if I didn't say that there is less red tape working for a software start-up, then there is for an international multi-billion dollar consumer product company.

I don't like to complain without viable solutions, so I have offered one. My solutions map to what I believe the problem to be. Lets face it - the marketing department at CVS has a lot less money to play with then McNEIL-PPC, and so I assume CVS would prefer to keep their costs down in this manner. Is that a correct guess? Maybe the opposite is true. maybe CVS has money coming out the wazoo. Then, to that I ask.... why such minimalist and boring product design? (do people want boring when it comes to generics? Perhaps!) Again, maybe I'm wrong about that. Regardless, my solution is one of many and geared towards the problem I think is at hand.

Behind closed doors there are concerns I am not privy to as a consumer. Deadlines, management breathing down your neck, serious budget shortages in a down economy, not to mention the myriad of issues around safe packaging (with the litgious nation we are), as well as distribution problems. Let us not leave out manufacturing. All in all it's a magical dance where all the partners in play somehow manage to produce a consumable that we all take for granted.

Thats a fair, if not overly-simplified view of the whole thing, right?

Still... it eats away at me that this couldn't be done better. I think someone tried... maybe that one maverick who said "why the wasteful boxes?" was shut down by management with other concerns, and he moped his way home hating the world. Maybe that happened.

For CVS, I say just sell the damn bottles on their own.

For Prilosec, I wonder why they can't put these pills in bottles. Do we really have to safety seal each individual pill? Is it because the product has a short shelf-life? Is it because *the perception* of sterility is what the consumers want? I don't know, and again, there is more at play here than mere logic.

So coming in from left field, I would offer a variety of solutions that address these concerns and yet allow maximum profitability. Hopefully, these changes reduce manufacturing costs, while appealing to the current green market.

For Prilosec, I offer the Mentos platform. Yes, the candy pictured here.



This brilliant candy roll style has been popular since candy was invented. Yet Mentos one-ups the competition with foil. Yes, the same thin metal that gives many products the appearance of sterility.

While the amount of real estate for marketing is low, can't you see the benefit of Prilosec putting their pills into foil like this? And in each 1/4 sized box is 3 of these. People can stuff them in their purses or backpacks. It gives the sense that the user is eating candy and takes some of the more medicinal aspects out of the picture. Is that not a good thing? Well, what do I know.

The difference here is that betwixt each oblong shaped acid-reducing tablet is more of the foil. You see, instead of each pill bumping up against each other - simply add a thin sheet of foil between them. Same sense of sterility. 1/4 the packaging or less.

Want to market them better? Then put them in one of these cases at the end of the aisles. There are a million ways to market items in a store - but overly wasteful packaging does not and should no longer be one of them!

Monday, September 1, 2008

Select Box Factory v1.0

Versiosn 1.0 is still supported, but version 2.0 is enhanced with many new features. It is for jQuery only, where this 1.0- version is for mooTools 1.1

See Select Box Factory 2.0 for jQuery

Download v 1.0

Here, the factory has produced a multiple-select box, with "sifting" tool attached. Try searching for one of the items in the list, or typing a letter in there. Next to it is the exact same list rendered as a dropdown (takes about 5 seconds to make this transition).



Why not cram some images in there? Here are images representing ranges, so search for "upper" for upper range, and see what happens:



Or what if we took the first two examples, but this time made the first list a "select-one" list, but wanted it to be open? And maybe we don't want the eraser in the dropdown on the right... and for some reason we also want a count at the bottom.

Select-ones with toggles, like on the right side are one of the weirdest variations and I recommend not to use them, but they are there. Because they are not dropdowns, the selections do not cause the toggler to "snap" back. To do this, you make it a "dropdown".



Next is an example of a select box whose elements were not found on the page, but rather in the definition. Inside the JSON object called "definition" is a child JSON object called "choices". The order to add items was specified as ascending (descending is also possible).

The code won't sort a list for you - it assumes you know the order. Try adding or removing items below, and have a look at the code in the zip file for more. Remove does remove a predefined item, but its nothing to make this remove selected items or based on a passed-in value.



But wait... its gets even more interesting. I've added the ability to show and toggle a certain number of states. I call this a heatmap, and it has many uses. Let's say you retrieve items where some are errors, some are warnings and some are info messages. Not only can you filter on those states, you get convenience buttons too. (unfortunately, there is not a lot of room for the buttons to have text). The states are numeric (0-5), so the buttons are nice when the users don't know the states - its more visual than anything.

All you have to do is add a state property to your items as an attribute, and boom, the code crawls over your items and figures out all the states on its own. It may be tough to see the selections here, but its up to you to skin these the way that makes sense to you. Add any colors that you want. Whether to show the convenience buttons or not is up to you. These work up to a point - since your dropdown can only be so wide. The code does its best to fit them in based on your css styles. For now, the states are numeric no matter what.

Try this: in the box on the right, first click the yellow button, then type "J" in the sift box. Its a filter within a filter.

Then try this: Click the eraser to clear the box, then click the yellow button again. Except this time, in the box, add "|v" (without quotes). The box should read 2|v. See what happens. (| pipe means "or")




Above you see some of the many variations that are possible with the select box factory. You see a multiple-select box opened with a max size of 6, that is capable of using the sift tool. Here are some ways to test its capabilities.

  • Try using control key to choose items like you might in a normal select box. Do this on the select-multiple boxes.
  • Use the shift key to do the same.
  • Click the eraser and see what happens.
  • Type something in the text box and see what happens.
  • Try typing the letter I while focused in the box and see what happens.

Download v 1.0

See Comparison

Results of performance testing

About the tool in general
  • Uses divs instead of options, which is why the potential for extension is nearly unlimited.
  • Does whatever a dropdown can do, but goes far beyond.
  • It is easy to call up a dropdown, assuming you have a div on your page that you are using as a dropdown.
  • All variations can fit a container, whose style you must supply in css, or it can live by itself, using itself as a container.
  • All variations are relative positioning, but work great positioned absolutely, or stacked on top of each other with z-index. This is up to your css and design, but they fit well. The above examples have a lot of whitespace because I am showing them inside iframes with the iframe border turned to no/0.
  • All variations can be enabled and disabled.
  • All variations are very, very easy to style in css. Just edit selects.css and you are done. You can even style the scrollbars if your browser supports it. (I suppose the ultimate incarnation would not even have that overflow scrollbar, but its not as easy as it looks to make one work without using overflow this way - its not something I am going to work on.)

There are three major variations to this..

A dropdown
  • works just like a standard javacript dropdown
  • can take images, which dropdowns can't do.
  • can show as many items before rendering a scrollbar as you want.
  • has a neat eraser icon so you can "undo" your selections. normal dropdowns don't do this, but I think they should.
  • It will allow you to show it opened or closed by default, which dropdowns today can't do. This is neat, because you can "show your users" an interface you want them to touch on the onset.
  • All variations can show a count of what is selected, but only the toggle versions (select one, and dropdown) will show you in text form what that select is at the top.
  • All variations will seek out and highlight the first item in a list based on the key you press. (although i don't have this working in safari yet).
A multiple select box
  • My favorite variation, shown above.
  • You can put a sift tool on top of it for nice searching.
  • You can put no toggle or sift on it, so it looks like a normal dropdown.
  • It uses spreadsheet style selections.
A select-one box.
  • very much like setting a select box to have a size of 1, this variation would be less common but has a ton of uses.
  • This isn't a dropdown, but can act like one. The biggest difference between this and a dropdown is that a dropdown snaps back and this one stays open.
I have been working on these dropdowns for a few months now, and perfecting all the browser-compatible and performance issues.

Needless to say, there are a wide variety of ways to use these dropdowns and I hope people find them intuitive to use. They are part of a more extensive "ui factory class" that I have created to plug into mooTools. This select box factory is enough for now.

(It expects mooTools v.1.11 but honestly, the only real neat effect is a toggle() so this can easily be ported to mooTools v1.2).

I will be fixing bugs and enhancing performance in the weeks to come to make them even faster.

Saturday, August 30, 2008

Table Cell Editor v1.0


Table Cell Editor v1.0


Demo:


Download: Version 1

About the table cell editor:
Its fairly straightforward, but a nifty little tool. It allows in-line editing for cells the way I think editing should be. Right now it takes a text field, but could easily be updated to take a textarea, a dropdown menu... anything.

I have put in stubs for an ajax call, but commented it out, since I'm not interested in hooking that in. It is at work, but for the demo I just edited it out.

Doesn't look like much, does it? Well, thats a good thing. This fits into my philosophy of getting the job done with as little effort as possible while maintaining usability and intuitiveness.

However, under the surface is a whole range of concerns that the user will never be privy to. This is one of the aspects of user interface design that makes new coders go nuts. The sheer amount of use cases even for such a small interface can be overwhelming.

So, if you want to know how it all works, then read below. I have not just provided the interface, but I have anticipated a wide variety of use cases regarding submittal of the request to the server, and cleansing of data.

By the way... everything I add on my blog will always be browser compatible (IE, FireFox, Safari, Opera). I don't think anyone really needs to say that anymore. If you are coding for one browser and your not confined by the constraints of the enterprise world (the only valid excuse for this), then your doing everyone a disservice. That being said, if you can't get it to work in Opera, then don't kill yourself, just put in your Opera hack and move on.

I won't go into a tremendous amount of detail, but I do (for my sanity) assume the following things.
  • More than a moderate understanding of javascript and event handling
  • More than a basic level of JSON.
  • More than a basic understanding of javascript toolkits like mooTools. Although I am using mooTools methods, it is not hard to understand the equivalent concepts in prototype, JQuery, YUI and the like. (If you want to convert this into your own toolkit, feel free).
Regarding edits, I recommend you:
  • Leave the JSON syntax and method partitioning alone, as much as you are able to. I keep my methods short (if I can), focusing on one thing only. The idea here is to modularize your work, so that the code is easy to maintain and understand.
  • "app" is your basic program. It is the only global variable you need to create.
Overview of interface:
  • Blue text indicates editable.
  • Double-click opens edit.
  • Enter submits edit.
  • Escape rejects edit.
  • Ajax call allows edit to process and can accept or fail the request.
Overview of code:
  • For our purposes, I am coding using JSON, with mootools framework, and have segmented my methods inside of an "app" variable, which is the only global variable I need. That is why you will see references to "app".
  • I decided that showing the code here is tedious and useless, when all you have to do is download the js and look at it yourself. I will, however, highlight small bits of code out of context. This is to explain anything I feel is just not quite obvious.
initialize()
  • setUpRowEvents. allows mousenter, mouseleave, click, doubleclick and mousedown events. Don't use mooTools addEvent for hundreds of rows or memory will grow too fast.
  • standardResponseDiv: used to return the ajax request, if necessary.
  • currentConCell if a cell is being converted
  • selectedRows an array of rows for later manipulation
  • freeze: a command to stop any auto-updating code you may have, to give the edit request time to process.
forceClick()
  • You'll need this if you have click doing other things as well, as I do in my original code. You want to stop the user from moving forward unless they accept or decline their edits.
  • Do not use "blur" on the field to either accept or reject the edit. This can be called way to easily.
updateTable()
  • This is the ajax call that takes your edits and actually updates the record.
_cleanse() and _escape()
  • A couple of convenience methods to help make sure data is not cross-site script, and to ensure that the server and database can read the edits, especially regarding special characters.
generateRequest():
  • A stub used to generate your string to send over the ajax request.
evaluateButtons() and resetButtons():
  • The idea here is that you may have buttons somewhere that light up or disable depending on what row you click. I have put these stub methods in place for you to put your own logic. I inserted these method calls at exactly the right place so you don't have to worry about where they go in the event scheme.
setUpRowEvents()
  • There is a lot going on in here, but there doesn't need to be. I have code for changing the color as you mouse around, and for clicking.
  • The code for soft color change (mouseenter, mouseleave) must not be triggered when a row is selected (a hard color change).
  • The hard color change indicates row focus. This is the selected row, which can not only take edits, but when you call evaluateButtons(), it can trigger other parts of the UI to light up as well. (does not take multiple selections at the time).
  • mousedown ensures that the events don't get called out of order and they stay in-line.
  • click adds or subtracts to an array of rows. I put this in here so you could, as I said before, light up or disable other buttons or widgets based on the row in focus. I have an array here so you can add up the rows and potentially use this for multiple selections.
colors:
  • In general, I use a soft color for soft focus, or when the user is just mousing around, and a hard or "punch" color as I call it for direct focus and edit.
  • I use mouseenter and mouseleave as opposed to mouseover and mouseout because these methods fire only once instead of continuously.
*If there are any errors, regardless of the kind of browser you use, then please bring it to my attention. Nobody is perfect.

Thursday, August 28, 2008

Latest Freelance Website

Every now and then I do some freelance stuff. I do it for cheap or free (free-lance), depending on the person.

In this case, this is the first time I've started with a template and then modified the graphics, layout, text to create what you see here. I needed to put something together one or two nights and that isn't easy to do with my free time. So, I think these results are great, considering the time.

Local community theater


Optimize your javascript for enterprise v1.2

Updated 9.10.08 to 1.2. Items added/modified for 1.2 are in blue.

The following are optimizations you can use for any browser when writing client-side code... most especially for Internet Explorer (ahem), and most especially when you are focused on enterprise installs. First, read a few paragraphs on where I am coming from.

This blog will be continually updated, instead of me just making new blogs. You'll know it is updated, because I will attach a version number every time I change it.

These will help speed up the performance of your code if you are dealing with large amounts of data that you need to store in memory over long periods of time. You may see this more nowadays as you use your wonderful Ajax parsing code to keep users on the same page or view.

Unless you are using perhaps the nicest browsers ever to be created (imo), Safari, then I suggest you stick to the lowest common denominator... and what is that? It's Internet Explorer 7. Up until this year, it was IE6, with all of its shortcomings. At an ancient and withering age of 7 years old, IE6 is the official lowest of the low and the dumbest of the dumb.

Many heavy hitters that purchase enterprise software are slow to upgrade. And since IE is a standard install on Windows machines - it means - you guessed it, guys like me have to code for older browsers. With web, it's IE7. With enterprise, your lowest common denominator is ie6. (more on why this is true and a more comprehensive list of differences between web and enterprise in a future blog).

The most salient point I can make about coding for enterprise versus web is that at the end of the day, your customers absolutely must have working code - and code that works fast, is reliable and consistent. An engineering disaster-miracle like myspace.com will not cut it in the enterprise world. Often there are not millions of users hitting your system, so you have no excuse and customers know this. To that end, it is your job to find the path that gets the job done - which is not always the cleanest or best path.

Internet purists are going to scoff at me, but I am truly a standards guy. I am a purist and a perfectionist. But I am also an enterprise guy - not a web guy (although my colleague Matt is helping me turn a new leaf in this area) - so I have to do what I can to manage extremely large amounts of information on top of a leviathanic, sprawling multi-tiered enterprise framework with multiple millions of lines of code and literally billions of dollars at stake.

The analogy I use for the enterprise thin client interface is that of the Hoover dam. Have a look. That relatively tiny and thin wall is all that stands between godly oceans of information and your users. Do it right and the dam acts as a usability filter - only what is required gets through. Do it wrong... and you're soaked. Memory leaks. Browser CPU hangs. Usability issues over SSL connections and RDP. Anyone in my position understands these problems.

So, to repeat, here are optimizations that are always good, that in some cases are browser-specific, and work wonders for long-standing interfaces that must avoid memory leaks. Most of this is through my experience, but I will try to site references where I can.

1. Don't put classes directly on your HTML elements during an iteration, where said iteration is more than 25-50 items.
  • If you must use classes in order to satisfy a requirement for getElementsByClassName(), then always programmatically capture and then assign classes after the document is loaded.
  • It's IE that suffers the most from this. And as you will find, it's IE, even IE7 that suffers the most from everything you try to do intuitively. Firefox adheres to standards and deals with DOM in a way that fosters intuitive programming. IE adheres to standards and deals with DOM in a way that fosters kludges.
  • See this performance analysis I did on version 1.0 of a select box factory I am working on. Bottom line, is that it shows other browsers do better when classes are set inline, and IE does worse, but moreso than other browsers do better. Your call. Results of performance testing
2. Avoid using a table element for large matrixes, or page it if you can't.
  • Unless you have lazy loading implemented, browsers like IE will not show the table until the contents of table are loaded. This means perceptual slowness.
  • Can you get CSS to work instead? Go for it. But if you must have a table, then implement server-side or client-side paging. The assumption here is that you have so much data that you can't show it all at once. Page it.
  • In all other cases: tables are fine! Yes! I give you freedom to use tables, and get out of the world of CSS for a minute. Tables are great things - and they allow you to add a structure to a page in no time flat - without having to hack away at CSS styles for hours on end. For Enterprise, and for the more moderate amounts of data, tables are the way to go.

3. Avoid memory leaks and circular references

  • These can creep up on you, especially in IE. The best tool to use that I have found is ProcessExplorer. It tells you how much memory has been allocated by the process locally, as opposed to how much memory the process is currently using. Memory leaks are obvious once the program in question (IE) never releases memory and in fact, grows it over time. This can not only kill your process, but in some cases can hang your computer.
  • Assigning objects to references may cause circular references in IE. Try sending on the id of the object, then manipulating the item directly. Circular references can cause memory leaks or, if you are using mooTools v.1, they may cause the mooTools GarbageCollection to take longer than the browser timeout for unload(). This will make the browser alert the user that a "script is running slowly" when in fact mooTools has just not cleared the memory yet.
  • Opacity manipulation through javascript will cause memory leaks in IE.
3. Do / Don't do this in mooTools v.1.1 (and possibly in v.2).
  • Just like classNames, don't programmatically make new Elements() over iterated items because this takes up way too much memory per item. Your browser will complain when you to try unload().
  • Morphing works poorly in ie6 with mooTools v.1.1 Many styles are not supported. mooTools has fixed much of this in v1.2
  • mooTools v1.1 and ie6 is a terrible combination to deal with regarding CSS. Bottom line: you are going to hate life if you have to deal with this. The number one reason is that you can't use selectors effectively during morphs or style changes in mooTools in ie6 - so your going to have a huge CSS file with many duplicate classes to support transitions.
  • Can't seem to get the keyUp, keyDown or keyPress events to fire in Firefox when you add them to a div? Well, take that div and set the tab index to -1. div.setAttribute("tabIndex","-1"). This fixes what I think is a bug in attaching events for gecko. Source (may not be a valid link)
  • converting from mooTools 1.1 to mooTools 1.2? Oops! Don't use the document.firstChild as your droppables target, for drag and drop elements. Will cause cpu hang 100%. This was not an issue in version 1.11.
  • When converting from mooTools 1.1 to 1.2, watch for these very common transitions.
  1. window.ie is now Browser.Engine.Trident, and many more located (here)
  2. Fx.style is no longer used. try Fx.Tween.
  3. Many more to come. These were just the easiest ones to spot.

  • Still finding your cpu pegged at 100% in IE when performing a click event in mooTools but can't for the life of you find the reason? There are two ways to solve this issue:
  1. You are probably swapping innerHTML right? Or modifying it? Be careful. There is a bug in IE where you must initialize the html with a string first, then attach your html.prepended to the innerHTML you want to add. You may also lose all your events that have been added. This will cause you a major headache! To solve, place any string in quotes += " ". Be sure not to use an empty string - but anything else should work.
  2. Or, Take the focus() off the page by placing the focus() on another element. This short-circuits the process and stops the CPU from pegging out.

4. Avoid these common mistakes
  • Use THEAD if you are injecting a table into the DOM. If you don't then IE won't show it.
  • Don't rely heavily on margins. of all the CSS styles in the universe that are browser-compatible, margins have the most variation. If you use margins too heavily, then you are subject to a wide range of kludges for different browsers and different DTD declarations. Regardless, you're safer off with padding if you can use that as your styling mechanism for spacing.
  • When assigning highlight effects with mouseover and mouseout, or mouseenter and mouseleave, don't try to change the background color of two elements at once. For example, if you have a table row with a button inside the table cell - and you want the button to change also when you highlight the row - your going to pay for it. Changing two styles on two elements is extremely expensive.
  • Know the difference between keyCodes for key events during keypress and keyup. They are different. Also, SlimBrowser with ie will override your key commands if you happen to try to override them yourself (say, by disabling f5 for refresh)
5. Try these, in general.
  • In ie, use line-height to vertically align elements, because vertical-align won't work. Just make line-height the same as height.
  • Always use Regular Expressions whenever possible to parse strings. Or use a stringbuilder that I found, which is extremely fast. (StringBuilder blog coming soon)
  • Enclosures are a wonderful thing. This is also a wonderful resource : A John Resig Book. If you know about Mr R., then you know its at least a book worth reading. I recommend you try to use enclosures when you must load something where, along the way, you will need to access local functions or variables later. Enclosures allow you to addEvents to objects with ease, amongst many other things - they help you make elegant code!
  • Work modularly. To help you work less procedurally and more modularly, try working with the JSON syntax. It is not only a great way to partition your work, it minimizes global variables, a more or less known evil. I also highly recommend this book Javascript: the good parts.
  • Sometimes browsers like IE highlight the screen with dark blue text? That is the selection mechanism. To confuse it, set the focus of any element on the page that can accept focus. Until you understand the bug you have at hand, focus() on an element is a fantastic way to short-circuit the natural browser behavior. Use it sparingly.

More to come.

Sunday, August 24, 2008

Four great puzzles to keep your mind sharp.

Someone I work with likes to do a sudoku puzzle during every lunch. I don't even have to ask him to know that he loves to play them, but also that he likes to keep his mind sharp.

Coding can be quite challenging, and often depletes your energy without you having even to stand up for 8-10 hours (although I do!). When you get stuck or create bugs, it is often because you are too tired or foggy to do it properly.

Aside from a good night's rest... there are a lot of fun ways to keep your mind off your work in the downtime, but also to help maintain that razor edge intelligence I'm sure you bring to work.

If you are anything like me, then your talents are visual-spatial. When you are asked a question, you have to create the scenario in your head first, before you can answer. This kind of thinking is incredibly useful for a Software UI Engineer, but not so much for other vocations. It is this kind of talent that you should keep sharp.

I feel that the puzzles you choose to fill up your free time should reflect your type of cognitive style. Here are three sites (and more) that work really well if your intelligence is primarily visual-spatial. Even if it is not, then you may still enjoy the challenge this proposes... but just be warned... if you are more of a logical or verb-driven thinker then these may drive you crazy!


The original exploding pie game
  • Challenge the computer with three different sized levels, to take control of a board, by adding pie slices to your pies. Sounds a little silly i know... but the pie only describes the shapes of your playing pieces.
  • The game is extremely difficult, employing the absolute depths of your visual-spatial intelligence, planning, strategy and creativity. Part chess, part Stratego, and all the fun of chain-reactions.
  • This is one of the most addictive games I've played, and I really get bored of the typical addictive games. This one has you involved. It does take a little while to understand since the instructions don't begin to cover what is possible.
Combination lock
  • I loved this game because it didn't make me feel like an idiot. When I add or subtract, I have to create pictures of numbers in my head, and this is very slow. So the timer makes it all the more interesting.
Mensa intelligence tests 1-6
  • I am up to puzzle #3 and still working on it. Extremely, extremely, difficult. This is mensa here, so of course its going to be insanely hard. I'm on Puzzle #3 and I'm stumped! What the heck is puzzle #6 like? Still, I enjoyed this thoroughly.
Double Maze
  • Don't let its initial looks fool you - this is a real challenge! It will make you go "doh!"
plus...

Razzle
  • My colleague Matt has a really cool puzzle site with a wide variety of puzzles, from crosswords, to word search to hangman and more. My favorite is Ghost, where you need to play the computer to create words by adding letters. It challenges your vocabulary tremendously.

Friday, August 15, 2008

Javascript Search / Sift Tool v1.0


Javascript Search / Sift Tool v1.0


Demo:


How to use the demo: You will see various blocks with text. Inside each of these are sets of attributes that you may search on. The datasets behind every div is just below. Have a look and that will give you a sense of how the sift tool works.

So, allow me to give you a couple of starting searches. After looking at the datasets below, type the following. At each step, take note of what the sift tool is doing:

  1. mammal
  2. hit backspace until just "m" of "mammal" remains.
  3. hit the clear button.
  4. now, type "wings+ape" (nothing, but it does find items as you type).
  5. now, change the + to a | (a pipe). Interesting results! Here is where things get fun. You got any field that matched wings and any field that matched ape. So any bird or insect with wings was returned.
  6. now, leave whats in step 5, but anywhere in the search box, type "!" the exclamation point. Everything else is returned.
  7. play around with it.

Datasets:
Dog||Mammal||Bark||Paws
Seal||Mammal||Bark||Flippers
Cricket||Insect||Chirp||Wings
Whale||Mammal||Whistle||Flippers
Caterpillar||Insect||Touch||Feet
Parrot||Bird||Whistle||Wings
Human||Mammal||Words||Hands
Ape||Mammal||Grunts||Hands
Bat||Mammal||Whistle||Wings
Cat||Mammal||Meow||Paws
Bee||Insect||Dance||Wings
Sparrow||Bird||Chirp||Wings
Haddock||Fish||Swim||Fin
Water Bear||Insect||Touch||Feet

Download: Version 1

What's coming in version 2:
  1. Support for buckets of objects
  2. Support for keeping track of counts of what remains
  3. Support for search convenience buttons

About the sift tool and logic:

Sifting is a little different than searching. Just a little. I called this "search / sift" so web searches would find it. Nobody is looking for "sift". With sifting, all of the data is already available in memory, be it a whole bunch of P tags, divs or whatnot. In this blog, I use the words "sift" and "search" interchangeably even though this really does "sift". I have 10 years of saying "search" so its hard not to say it.

I was recently challenged with developing a UI that returned a sizable amount of searchable data, on the order of say, 600 items, each with 10 searchable parameters, giving us 6,000 pieces of data.

While this is not, on the whole, a lot of information... there are plenty of uses for such an application when the lists are finite and not generated by users (but even then this can be modified to suit such a purpose).

I'll assume you know how to develop interfaces, and will also assume that you have a text box somewhere. My examples will be written using mootools v1.11, but really there are only a couple of moo-related features I'm using. It won't take much to move this to version 1.2.

Overview of interface:
  • Supports OR with "|" pipe.
  • Supports AND with "+" plus.
  • Supports NOT with "!" exclamation point.
  • Searches are always wildcards
  • Allows several ways to search: by enter key, by a search button and by searching while the user types. Although the code supports all three... My example shows the "search while you type method".
  • Searches are easy to customize, and have the option of returning a value or not.
  • Note: You cannot do And with Or in the same sift.
Overview of code:
  • For our purposes, I am coding using JSON, with mootools framework, and have segmented my methods inside of an "app" variable, which is the only global variable I need. That is why you will see references to "app".
  • Also, I am not using any enclosures, since I did not find it useful for this task. (beware "overuse of cool techniques").
Performance:
  • Testing only on IE for the moment (but Firefox for me is always faster here), I've got this optimized to do 6.09 milliseconds per object searched.
  • This was tested on 2.79 Ghz CPU with 2 G ram. The faster the machine that the user sifts with, the faster the sift.

A couple rules beforehand:

  • Don't send an object in the dom to your function or assign it to a variable, since this can cause memory leaks in IE. Instead, just call it by reference.
  • Don't use mootools elements when you are creating them by the hundreds, as the garbage collection utility in mootools simply cannot handle that amount of information and will cause your browser to think its running slow scripts when onUnload() is called.
  • Don't forget commas at the end of every function in JSON, but not the last function. leave that comma-less. Since my code is broken up, I've taken them out. See the js file for the entire structure.

I apologize for the formatting issues below. This html editor keeps eating up my pre tags. For a good look at the code, just download it here: Download: Version 1

Step 1, setting up the tools :

  • setupSiftTool. I call this when the view comes into focus the first time. This could be your enclosure if you wanted.
  • I set up my box called "siftBox" by finding it in the DOM by reference. In this case, I did not inject it into the DOM but i could have. You can easily just add the events to your text box old-school style if you want.
  • "clearButton" is a button right next to the search box. This does exactly what you think it does.
  • cArray is a shadow array. It is there because of the fact that it is always faster to iterate an array in memory then it is to comb the DOM. We will use this to keep track of what has already been found so that the search gets faster the more you search.

initialize : function(){
this.arrayOfObjects = $$(".siftItem");
$each(this.arrayOfObjects, function(item, i){
item["data"] = $A(item.getAttribute("data").split("||"));
},this);
window.setTimeout(function(){
app.setupSiftTool();
},0);
},

setupSiftTool : function(){
/*
Here you can decide, based on the number of expected items how you want the
search to be triggered. I like to use a search box when the data set gets to large,
which means the user has to hit enter or click the box.
Until that time, I let the search work continuously as they fire the keyup event.
You can use if(event.keyCode === 13) to ensure it happens with enter key.
*/
$("siftBox").addEvent('keyup', function(event){
app.captureKeys();
});
$("clearButton").addEvent('click',function(event){
$('siftBox').value = "";
app.captureKeys();
});
this.cArray = [];
},




Step 2, the iterator :

  • You'll notice here how I partition my logic. All methods should be tight, small, and serve a particular purpose. Like this blog, I keep things short and sweet if I can.
  • captureKeys: responsible for iterating over a set of objects, and this is where I assume you are in-memory. I call it simply, arrayOfObjects
  • forEach is a mootools paradigm equal to a loop over an array. It is bound to "this", or app.
  • testFailAttribute is coming in step 3. This is the core logic.
  • If you want to clean up this code so that it doesn't call the same logic in both the if and the else statement, then go ahead. I have it this way for clarity.
  • Note: arrayOfObjects I assume you will build up yourself. In my case, I do it by iterating over the dom to find Divs. These are all Divs.
  • this.Tm, a test-match boolean. Explanation in step 3.

captureKeys : function(){
app.arrayOfObjects.forEach(function(obj, index){
if(app.testFailAttribute(obj,'siftBox')){
if(app.cArray.contains(obj.id)){
return false;
}else{
app.cArray[app.cArray.length] = obj.id;
}
}else{
if(app.cArray.contains(obj.id)){
app.cArray.remove(obj.id);
obj.style.display = (window.ie6) ? "inline" : "block"; // ensures a fix to ie6 margin impl.
}
}
},this);
this.tM = null;
this.isAnd = -1;
this.isOr = -1;
this.isNot = -1
this.firstStyle = "";
this.secondStyle = "";
this.returnNeg = false;
this.returnPos = true;
},



Step 3, the core logic:

  • testFailAttribute. Here you are trying to see if an object does *not* match.
  • this.Tm, a test-match boolean. We use this to ensure that we're not calling the first section of testFailAttribute every time the user searches.
  • isAnd and isOr tell us the jist of what the user is trying to do. At this time, I'm not letting them mix the two.
  • doShowObj is an associative attribute, one that tracks the lifecycle of the object. The reason this is here is so that the UI can search as the user types. In this case, I want to use the enter key, but it supports searching while typing as well.
  • testFailMatch is a list of items that the conditions must meet or the test fails.
  • escapeReqExp comes from mootools framework. You'll need to be careful not to process certain characters.

testFailAttribute : function(obj,box){
if(!this.tM){
this.firstStyle = "inline";
this.secondStyle = "none";
this.returnNeg = false;
this.returnPos = true;
this.isNot = $(box).value.indexOf("!");
this.isAnd = $(box).value.indexOf("+");
this.isOr = $(box).value.indexOf("|"); //must be one or the other.
if(this.isOr === -1) this.tM = $(box).value.toLowerCase().split(/\+/g);
if(this.isAnd === -1) this.tM = $(box).value.toLowerCase().split(/\|/g);
if(this.isOr !== -1 && this.isAnd !== -1) return;
}
obj["doShowObj"] = 0;
this.tM.forEach(function(m, index){
index = index+1;
m = m.escapeRegExp();
if(!this.testFailMatch(obj,m)){
obj["doShowObj"]++;
}else{
if(this.isOr !== -1){
if(index === 1 && obj["doShowObj"] > 0) obj["doShowObj"]--;
}else{
if(obj["doShowObj"] > 0) obj["doShowObj"]--;
}
}
},this);
if(this.isNot !== -1){
this.firstStyle = "none";
this.secondStyle = "inline";
this.returnPos = false;
this.returnNeg = true;
}
if(this.isOr === -1){
if(obj["doShowObj"] === this.tM.length){
obj.style.display = this.firstStyle;
return this.returnNeg;
}else{
obj.style.display = this.secondStyle;
return this.returnPos;
}
}
if(this.isOr !== -1){
if(obj["doShowObj"] > 0){
obj.style.display = this.firstStyle;
return this.returnNeg;
}else{
obj.style.display = this.secondStyle;
return this.returnPos;
}
}
},


Step 4, the attributes to sift on:

  • testFailMatch. This is a list of attributes on the object itself (in my case, dom attribtues added to the div.) I cut it down to one, but just add as many as you want with "&&".
  • Here you can be creative. If you want the sift to eliminate items based on lets say, a displayName, then add that. But you can be clever about it and add convenience for the user, by also adding other attributes. Lets say you have a dataType attribute. If the user searches for "date" you can surprise them by returning anything with "date" in the name, or any item that is a date dataType, even if "date" is not in the name.


testFailMatch : function(obj,testMatch){
testMatch = testMatch.replace("!","");
if(!(obj["data"][0].toLowerCase().test(testMatch)) && !(obj["data"][1].toLowerCase().test(testMatch)) && !(obj["data"][2].toLowerCase().test(testMatch)) && !(obj["data"][3].toLowerCase().test(testMatch))){
return true; // meaning, if the item passes none of these tests, hide it an add it to the array.
}
return false;
}



The Ui Guy



Since this is my first post, I guess an introduction is in order. My name is Ari, and I have been a user interface engineer for 10 years now, for enterprise and web.

I registered a few domain names to start a company a few years ago, but then decided not to bother. So, the domain names "theuiguy.com", "uiguys.com", and "theuiguys.com" all will link to this blog.

It may seem lazy for me to be using blogger, seeing that I have done software and websites for a living, but thats the reason why at the moment I don't want to bother. I'm too focused on my career and don't have the time to put into it. I currently manage my art website, Headcircus and that is enough for me.

I plan on blogging about my experiences over the past 10 years, and that may be better than full-fledged articles.

So, your probably thinking "The" Ui guy? What arrogance.

Truth be told, at the time "uiguy.com" was already taken, and same here for blogger.com. So thats what I have. It really should be "A Ui guy", but that doesn't ring as nice.

So what do I have to offer in this vast sea of blogs? A lot if you are interested in the front end of software development, especially in the User Interface arena.

And yes, I always write in small, easily digestible paragraphs, and I wish the world would do the same. Nothing says "stumble" or "back button" more than a menacing block of text.

On to the blog!