14.8. Live Command-LineAssistive, CLI, Command-Line, Grammar, Supportive Figure 14-25. Live Command-Line14.8.1. Goal StoryFrank is using an advanced query tool to run a report on current output. He begins entering an SQL-like query: "list all." At this point, a suggestion list appears with all the things that can be listed, and he chooses "products." Continuing on, the query now reads "list all products where" and a new list appears: "creationTime," "quality," and so on. He chooses "creationTime," and. then enters the rest manually, preferring to ignore further suggestions. The query ends up as "list all products where creationTime is today and quality is faulty." There's a tick mark next to the query to indicate that it's valid. 14.8.2. ProblemHow can a command-line interface be supported? 14.8.3. Forces
14.8.4. SolutionIn command-line interfaces, monitor the command being composed and dynamically modify the interface to support the interaction. The interface changes according to data, business logic, and application logic. When the command line is to be executed on the server, as is often the case, the browser usually delegates to the server the task of evaluating the partial command. The command line is the quintessential expert interface and it's worth bearing in mind that most users are "perpetual intermediates" (http://www.codinghorror.com/blog/archives/000098.html). That is, they learn enough to get by and generally learn new things only as and when required. So, while a powerful command line may be a superior choice in the long run, most users simply don't have the time to spend learning it in advance. Traditional command lines present a problem because they offer the user a blank slate. Everything the user types must be based on prior, upfront, learning, and the only feedback occurs after the command line has been executed. That's not only inefficient for learning, but downright dangerous for sufficiently powerful commands. The model is: human enters command, computer executes command. The solution is to be more interactive: with a smarter, more proactive command line, the construction of a commandits quick evolution from nothingness to an executable stringbecomes something of a human/computer collaboration. For example, you can:
The benefits apply to novices and experts alike. In supporting novices, the technique has sometimes been referred to as a "training wheels" approach. Like training wheels on a bike, you get a feel for the more powerful interface while still being productive. Often, the command goes to the server, so it usually makes sense for the server to advise the use regarding partial commands. Basically, the procedure goes like this:
As an Ajax feature, this pattern is largely speculative: I'm not aware of any production-level Ajax Apps, but the command-line interface is growing at the same time as Ajax; it's inevitable that these things will collide, and as the discussion here suggests, there are plenty of synergies. One source of inspiration here is the evolution of IDEs over the past five years, particularly in the Java space. Environments like Eclipse (http://eclipse.org) and IntelliJ Idea (http://www.jetbrains.com/idea/) internally represent source files as data structures, leading to features such as ongoing error detection, offers to fix errors, suggestions, powerful refactorings, and alternative displays. All of this happens without the user ever having to compile the source code. As another source of inspiration, there was a recent experiment on training wheels for the command line (http://www.cs.utep.edu/nigel/papers/HCII2005.pdf). Students learned about the Unix command line from either a book or a GUI "training wheels" interface, similar to a Live Command-Line. The training wheels interface was found to be more productive and a more pleasant experience, too. 14.8.5. Decisions14.8.5.1. Where will the partial command be analyzedbrowser or server?It's possible to perform some kinds of analysis in the browserfor example, the browser can check the query against a constant regular expression. So should you try to support analysis in the browser or delegate it to the server? There are several advantages to analyzing the command server side:
The downsides are:
14.8.5.2. How much information will the server provide?Producing more information for partial commands will consume more server resources. The information will also take a bit longer to download. You'll need to trade off resources in favor of supportive information. For example:
14.8.6. Real-World ExamplesI'm not aware of an all-encompassing Live Command-Line demo. However, the examples in Live Search and Suggestion (earlier in this chapter) are special cases of Live Command-Lines. There are also some JavaScript terminal emulators around, though they don't provide Live Command-Linessee Web Shell (http://a-i-studio.com/cmd/) and JS/UNIX Unix Shell (http://www.masswerk.at/jsuix/jsuix_support/). Also, see the Try Ruby! tutorial (http://tryruby.hobix.com/) for an impressive web interface to the interactive Ruby programming environment. 14.8.6.1. YubNubYubNub (http://yubnub.org) isn't Ajaxian, but it is noteworthy as the first explicit exploration of the "search as command line" meme. Yubnub lets users submit commands, which are then mapped into external queries. For example, if you type in "sum 10 20" (http://yubnub.org/parser/parse?command=sum+10+20), you get the sum of 10 and 20; if you type in "ajax form" (http://yubnub.org/parser/parse?command=ajax+form, you get search results from ajaxpatterns.org for "form." 14.8.7. Code Example: AjaxPatterns Assistive Search DemoThe Assistive Search Demo (http://ajaxify.com/run/assistiveSearch) was inspired by services such as Google Search, which are trending toward a general-purpose command line. It aims to illustrate the "training wheels" style of command-line support. The Assitive Search Demo has a typical search engine forma free-range text input with a Submit buttonin addition to several images, one for each category that can be searched. Thus, the user is alerted to the capabilities of the search. As the user types, the categories highlight and unhighlight to help predict what kind of results will be returned (Figure 14-26). All of this information comes from the server side; the browser application doesn't know anything about the categories. It calls the server and startup to discover the categories and corresponding images. A timer monitors the command line, continually asking the server which categories it matches. The browser then highlights those categories. Figure 14-26. Assistive Search DemoThe startup sequence loads the categories and kicks off the command-line monitoring loop. The server is required to have an image for each category. If it says that there's a "phone" category, then there will be a corresponding image at Images/phone.gif. The images are all downloaded and placed alongside each other: window.onload = function( ) { initializeCategories( ); requestValidCategoriesLoop( ); ... } } function initializeCategories( ) { ajaxCaller.getPlainText("categories.php?queryType=getAllCategoriesCSV", onAllCategoriesResponse); } function onAllCategoriesResponse(text, callingContext) { allCategoryNames = text.split(","); var categoriesFragment = document.createDocumentFragment( ); for (i=0; i<allCategoryNames.length; i++) { var categoryName = allCategoryNames[i]; var categoryImage = document.createElement("img"); categoryImage.id = categoryName; categoryImage.src = "Images/"+categoryName+".gif"; categoriesFragment.appendChild(categoryImage); } document.getElementById("categories").appendChild(categoriesFragment); } The key to the Live Command-Line is the monitoring loop. Whenever a change occurs, it asks the server to return a list of all matching categories: function requestValidCategoriesLoop( ) { if (query( )!=latestServerQuery) { var vars = { queryType: "getValidCategories", queryText: escape(query( )) } ajaxCaller.get("categories.php", vars, onValidCategoriesResponse, false, null); latestServerQuery = query( ); } setTimeout('requestValidCategoriesLoop( );', THROTTLE_PERIOD); } The server uses a bunch of heuristics to calculate the valid categories for this query. For instance, it decides if something belongs to the "people" category by looking up a collection of pronouns in the dictionary. A controller will ultimately return the categories as a comma-separated list generated with the following PHP logic: function getValidCategories($queryText) { logInfo("Queried for '$queryText'\n"); $cats = array( ); eregi(".+", $queryText) && array_push($cats, 'web'); eregi("^[0-9\+][A-Z0-9 \-]*$", $queryText) && array_push($cats, 'phone'); eregi("^[0-9\.\+\/\* -]+$",$queryText) && array_push($cats, 'calculator'); isInTheNews($queryText) && array_push($cats, 'news'); isInWordList($queryText, "./pronouns") && array_push($cats, 'people'); isInWordList($queryText, "./words") && array_push($cats, 'dictionary'); return $cats; } The browser dynamically updates the category images using a CSS class indicating whether they are valid, which it determines by checking whether they were in the list. There's also an event handler to perform searches on specific categories, as long as those categories are valid: function onValidCategoriesResponse(text) { var validCategoryNames = text.split(","); // Create a data structure to make it faster to determine if a named // category is valid. For each valid category, we add an associative array // key into the array, with the key being the category name itself. validCategoryHash = new Array( ); for (i=0; i<validCategoryNames.length; i++) { validCategoryHash[validCategoryNames[i]] = "exists"; } // For all categories, show the category if it's in the valid category map for (i=0; i<allCategoryNames.length; i++) { var categoryName = allCategoryNames[i]; var categoryImage = $(categoryName); if (validCategoryHash[categoryName]) { categoryImage.onclick = onCategoryClicked; categoryImage.className="valid"; categoryImage.title = "Category '" + categoryName + "'" +" probably has results"; } else { categoryImage.onclick = null; categoryImage.className="invalid"; categoryImage.title = "Category '" + categoryName + "'" + " has no results"; } } } 14.8.8. Alternatives14.8.8.1. Point-and-clickThe command line involves typing, while point-and-click is a simpler interface style that shows available options and lets the user click on one of them. 14.8.8.2. Drag-And-DropAnother means of issuing commands is with Drag-And-Drop (Chapter 15)dragging an item into a trash can to delete it. 14.8.9. Related Patterns14.8.9.1. Submission ThrottlingInstead of processing the command upon each keystroke, use Submission Throttling (Chapter 10) to analyze it at frequent intervals. 14.8.9.2. Status AreaFeedback such as input validation and result prediction is usually shown in a Status Area (Chapter 15). 14.8.9.3. HighlightSome parts of the command can be highlighted to point out errors, incomplete text, and so on. Also, aspects of the Status Area can be highlighted to help with prediction. 14.8.9.4. Progress IndicatorIf it takes more than one second to process the command line, consider showing a Progress Indicator (see earlier). 14.8.9.5. Browser-Side CacheIntroduce a Browser-Side Cache (Chapter 13) to retain the server's analysis of partial commands. 14.8.9.6. Fat ClientConsider creating a Fat Client (Chapter 13) that tries to handle as much of the analysis as possible, thus reducing server calls. 14.8.9.7. Live SearchLive Search (see earlier) is an extreme version of Live Command-Line applied to search, where the command is effectively executed while the user types. 14.8.9.8. SuggestionProviding Suggestions (see earlier) is one characteristic of Live Command-Lines. 14.8.10. Want To Know More?
|