170
I Use This!
Very Low Activity

News

Analyzed 1 day ago. based on code collected 2 days ago.
Posted over 15 years ago by haysmark
Last week I added an unprecedented enhancement to the Dojo Object Harness (DOH) unit test framework, called doh.robot, scheduled to appear in Dojo 1.2. This enhancement adds an API to DOH that enables testers to automate their UI tests using real ... [More] , cross-platform, system-level input events. In this post, I'm going to explain the enormous value-add of this enhancement in terms of unit and accessibility testing, and how to get started using this new API. The challenge of Web UI testing Web UI testing frameworks like Selenium and Windmill already contain browser automation elements suitable for many different types of unit and acceptance tests of application code. But each of these frameworks has an underlying catch: the input events they create are synthetic. On one hand, synthetic events are great because synthetic events don't use the native input queue; you can run your tests in parallel across multiple browsers and windows all on one machine without a fight for the mouse and keyboard. But the problem with synthetic events is that browsers don't trust synthetic events enough to let them execute their default action. For example, if you create a synthetic Tab keypress (expecting the browser to shift focus to the next element in the tab order), the focus won't actually move, because the browser doesn't trust the synthetic keypress enough to allow it to execute its default action. In a worse case, if you have a widget with onmouseover and onmousedown events, you would expect that the user would not be able to trigger the onmousedown without first triggering the onmouseover. But with synthetic events, this sort of common sense fails; you can easily send a click to an element without registering mouse movement over it, never mind the onmouseout from the previous element and the *hundreds* of onmousemoves a real user would generate in between. The result is that existing Web UI frameworks fail to support the testing of common requirements of Web applications like keyboard accessibility, and can be frustrating to deal with when you have to manually dispatch synthetic mouse events that would fire automatically for a human tester. What doh.robot can do for you We designed the doh.robot to enhance the DOH runner's ability to drive unit tests. Like other test frameworks, doh.robot provides testers with an API that enables them to simulate user interaction. However, we took a different approach to dispatching events: instead of using synthetic events, we used the cross-browser and cross-platform Java applet technology to place real events on the native event queue, as if a real person performed the action. This means that when you use doh.robot to execute your unit tests, browsers will trust the events doh.robot creates from your commands and will handle any and all contingent events for you. So when you tell doh.robot to send a Tab keypress, you can fully expect the Tab to move focus to the next element in the Tab order, as if a real user pressed Tab. And when you tell doh.robot to click an element, you can fully expect to get the onmouseover before the onmousedown, as well as all of those hundreds of onmousemoves a real user would generate in between. When you use the DOH test runner in conjunction with doh.robot, you can easily automate and report the results of numerous accessibility and UI unit tests that would otherwise require manual, visual inspection by a real person. The 3 robots From a high level perspective, DOH comes with three incrementally more powerful versions of the doh.robot automation suitable for different testing requirements: - doh.robot - dojo.robot - dijit.robot doh.robot Like DOH, the basic doh.robot was built to run without Dojo. You can load it into a unit test by adding a script tag pointing to util/doh/robot.js. doh.robot is perfect for automatically testing keyboard accessibility in any Web application, even applications that don't use Dojo or simply use a version of Dojo older than 1.2. dojo.robot dojo.robot is an extension to the doh.robot included in Dojo 1.2. You load it using dojo.require("dojo.robot"). Using Dojo Core technology, the dojo.robot adds mouse movement commands to the DOH API so test writers with access to Dojo 1.2 can consistently move the mouse to UI elements even across a wide variety of browser window sizes and resolutions. dijit.robot dijit.robot is the final extension to the doh.robot packaged with dijit. You load it using dojo.require("dijit.robot"). It further augments the dojo.robot's mouse handling with Dijit's cross-browser automatic scrolling. If you are concerned about writing tests that involve scrolling a lot of elements into view, dijit.robot is the best way to ensure that elements are always in view for the mouse to click them. The doh.robot API Since there are 3 robots, you can find the latest APIs documented in util/doh/robot.js, dojo/robot.js, and dijit/robot.js starting with Dojo 1.2 and the latest trunk build. The commands all have certain semantics in common, so I will describe them here using doh.robot.typeKeys as an example: typeKeys: function(/*Function*/ sec, /*String||Number*/ chars, /*Integer, optional*/ delay, /*Integer, optional*/ speed){                 // summary:                 //            Types a string of characters in order, or types a dojo.keys.* constant.                 //                 // description:                 //           Types a string of characters in order, or types a dojo.keys.* constant.                 //           Example: doh.robot.typeKeys(sec, "dijit.ed", 500);                 //                 // sec:                 //            new Function('return window')                 //            Public key that verifies that the calling window is allowed to automate user input.                 //                 // chars:                 //            String of characters to type, or a dojo.keys.* constant                 //                 // delay:                 //            Delay, in milliseconds, to wait before firing.                 //            The delay is a delta with respect to the previous automation call.                 //            For example, the following code ends after 600ms:                 //                  doh.robot.mouseClick(sec,{left:true},100) // first call; wait 100ms                 //                  doh.robot.typeKeys(sec,"dij",500) // 500ms AFTER previous call; 600ms in all                 //                 // speed:                 //            Delay, in milliseconds, between keypresses.                 // } sec: You will notice that every method of the doh.robot API takes a function parameter as the first argument. And the function it takes has to be "new Function('return window')". Why did we do this? User security: in the unlikely event you deploy your application to a public server with all of the unit tests with it, we want to make sure malicious users from other domains don't try to take over the robot and cause it to do evil on the user's machine. Of course, this is only the first of many security measures we took to keep the user safe. The best practice for writing tests is to store the new Function('return window') in a private variable like "s" in your test case, and pass s as the first argument to each doh.robot call. You'll see some examples of how this is used in the next few sections. delay: Each doh.robot method also takes a delay parameter. Rather than forcing you to litter your code with setTimeouts, we call setTimeout for you behind the scenes. We also do some additional thread synchronization on the Java side to ensure that your events fire in the order you called them and not the order the browser feels like evaluating the setTimeouts. As the comments show, delays are incremental. Normally, when you write setTimeouts one after another other in a sequence, you have to specify the exact time each one should execute. This is fine, but when you go back to maintain your test and decide to add new actions in between the setTimeouts, you normally have to go back and add time to each and every setTimeout. But with doh.robot's incremental model, test maintenence is easy: you can freely insert or remove commands and the doh.robot will adjust the timings for you automatically. And you don't have to worry about how long it takes a command to execute; the next doh.robot command won't happen until the current one has absolutely finished. Still, it's a good idea to give the browser's rendering system and event dispatcher enough time to catch up with the robot between commands; 500ms is a good delay to use for each command. Also, if you are making AJAX requests to a remote system, such as loading data into a Grid, keep in mind that the request might take a variable amount of time. You could just set a really long timeout, but another practice would be to dojo.connect into an event handler and continue the test from there, when you are absolutely sure that the data has arrived. Writing doh.robot tests Here is a "hi again" test using the doh.robot that clicks in a textbox containing "hi" and adds " again": doh.register("doh.robot", {         name:"dojorobot1",         timeout:6900,         setUp:function(){                 document.getElementById('textbox').value="hi";         },         runTest:function(){                 var sec=new Function('return window');                 var d=new doh.Deferred();                 doh.robot.mouseMove(sec,30,30,500);                 doh.robot.mouseClick(sec, {left:true},500);                 doh.robot.typeKeys(sec," again",500,500);                 setTimeout(function(){                         if(document.getElementById('textbox').value=="hi again"){                                 document.getElementById('textbox').value = ": passed";                                 d.callback(true);                         }else{                                 document.getElementById('textbox').value = ": failed";                                 d.errback(new Error("Expected value 'hi again', got " document.getElementById('textbox').value));                         }                 },5900);                 return d;         } }); doh.run(); See it in action: http://archive.dojotoolkit.org/nightly/checkout/util/doh/tests/robot.htm... If you've ever written a DOH test or a JUnit test before, the structure should look very familiar. You register tests to groups, like "doh.robot" in this case. A test has a unique name, and a timeout where it gives up and moves on to the next test. You drive a test using setUp, runTest, and tearDown functions. You write doh.robot tests like deferred DOH tests. DOh's deferred test model indirectly enables test writers to pause the test while AJAX requests happen. doh.robot uses the deferred model to pause the test while it interacts with the page. For the uninitiated, here is how a typical deferred DOH test flows on a high level: Instantiate a doh.Deferred object. Execute your commands. Set a timeout to check whether the test passed. Return the Deferred object to runTest immediately. You can see what the concrete implementation of this flow looks like in the runTest function above. You store the doh.Deferred in a variable called d. You also store the security function I mentioned in the API section in a private variable called sec. You pass sec as the first argument of each robot call. Next, you write the robot commands themselves: the mouse moves to 30,30 on the screen, clicks the left mouse button, and types " again". Between each command, the robot waits 500ms. After about 6 seconds have passed (mouseMove mouseClick 6*500=4000, 500 to let event dispatchers resolve, 1400 for demo purposes) the setTimeout fires and asserts that the test passed. You tell DOH a test passed in the Deferred model by calling d.callback(true). You tell DOH that something bad happened by calling d.errback and pass a new Error with the problem description. You can also do some visual formatting to indicate whether the test passed, for users running the test standalone (like you). Finally, you return the doh.Deferred object to the runTest function, signaling the DOH runner to wait for this test to finish. dojo.robot and dijit.robot's value-add The above test uses the basic doh.robot, and as such has two issues that could pose a problem in more sophisticated unit tests: first, it has to manually indicate that the test passed. If you either ran the test in the DOH runner, or ran the test standalone with Dojo available, you would be able to better see the results either in the runner's log or in the console at the bottom of the page. Second, it assumes that you have an absolutely positioned text element to click. For unit tests that rely on the browser's layout manager, or percent or em measurements, to lay out the page, pixel mouse movement isn't the ideal way to move the mouse. Fortunately Dojo 1.2 fills in this gap by adding a doh.robot.mouseMoveAt command: mouseMoveAt : function(/*Function*/ sec, /*String||DOMNode*/ node, /*Number*/ delay, /*Number*/ offsetX, /*Number*/ offsetY){                 // summary:                 //            Moves the mouse over the specified node at the specified relative x,y offset.                 //                 // description:                 //           Moves the mouse over the specified node at the specified relative x,y offset.                 //           You should manually scroll off-screen nodes into view; use dijit.robot for automatic scrolling support.                 //           If you do not specify an offset, mouseMove will default to move to the middle of the node.                 //           Example: to move the mouse over a ComboBox's down arrow node, call doh.mouseMove(sec, dijit.byId('setvaluetest').downArrowNode);                 //                 // sec:                 //            new Function('return window')                 //            Public key that verifies that the calling window is allowed to automate user input.                 //                 // node:                 //            The id of the node, or the node itself, to move the mouse to.                 //            If you pass an id, the node will not be evaluated until the movement executes.                 //            This is useful if you need to move the mouse to an node that is not yet present.                 //                 // delay:                 //            Delay, in milliseconds, to wait before firing.                 //            The delay is a delta with respect to the previous automation call.                 //            For example, the following code ends after 600ms:                 //                  doh.mouseClick(sec,{left:true},100) // first call; wait 100ms                 //                  doh.typeKeys(sec,"dij",500) // 500ms AFTER previous call; 600ms in all                 //                 // offsetX:                 //            x offset relative to the node, in pixels, to move the mouse. The default is half the node's width.                 //                 // offsetY:                 //            y offset relative to the node, in pixels, to move the mouse. The default is half the node's height.                 // } Where as the simple mouseMove needs to know ahead of time where to move on the page, mouseMoveAt can compute the position of elements on the fly even for elements not on the DOM or off the screen at the start of the test! So if we were to rewrite the above DOH test using dojo.robot, it would look like: dojo.require("dojo.robot"); dojo.addOnLoad(function(){ doh.register("doh.robot", {         name:"dojorobot1",         timeout:6900,         setUp:function(){                 document.getElementById('textbox').value="hi";         },         runTest:function(){                 var sec=new Function('return window');                 var d=new doh.Deferred();                 doh.robot.mouseMoveAt(sec,document.getElementById('textbox'),500);                 doh.robot.mouseClick(sec, {left:true},500);                 doh.robot.typeKeys(sec," again",500,500);                 setTimeout(function(){                         if(document.getElementById('textbox').value=="hi again"){                                 document.getElementById('textbox').value = ": passed";                                 d.callback(true);                         }else{                                 document.getElementById('textbox').value = ": failed";                                 d.errback(new Error("Expected value 'hi again', got " document.getElementById('textbox').value));                         }                 },5900);                 return d;         } }); doh.run(); }); This would cause the mouse to click the middle of the textbox before it starts typing. The dojo.robot tries to scroll the element into view using the browser's native scrollIntoView function so that no matter where the element is, even if it is presently off the screen, the dojo.robot can scroll it in and click it. But this approach still has one problem: native scrollIntoView does not work consistently across all browsers. Enter dijit.robot: dijit.robot enhances the dojo.robot with dijit's scrollIntoView algorithm, making scrollIntoView view consistent across all browsers. It's trivial to use this feature: just swap dojo.require("dojo.robot") with dojo.require("dijit.robot") and everything will start scrolling correctly automatically. dojox.robot.recorder doh.robot includes a powerful record feature, called dojox.robot.recorder, that can track your interactions with a unit test and play them back. Record features of other frameworks do a good job tracking user interaction with native widgets, but have some trouble recording interactions with Dojo-enabled widgets and drag and drop in general. Fortunately, dojox.robot.recorder is specifically designed to record user interaction with both native and Dojo-style widgets in mind. The recorder even generates code for drag and drop, which can be a useful guideline for writing tests that work across the different browsers you test. To use dojox.robot.recorder: Add dojo.require("dojox.robot.recorder") to your unit test. Load the unit test and click the body of the page. Press Ctrl Alt Enter. You will get an alert verifying that the recording process started. Interact with the unit test. Note: it's easiest to debug test failures when you break them up into only a few actions each. When you are finished, click the body again and press Ctrl Alt Enter. Autogenerated code will appear on the page for you to copy into a dojo.addOnLoad in the unit test. Fill in the test passed condition (it is a /*comment*/ in the if) and make any tweaks you would like to the autogenerated code. When you have recorded all of your tests, remember to add a doh.run() call after all of the tests. Otherwise, the tests will not start! Examples Here are some example tests modeling common UI interactions. These tests were generated by the dojox.robot.recorder and then tweaked to work across all browsers. View each page's source to see the test code. http://archive.dojotoolkit.org/nightly/dojotoolkit/dijit/tests/form/test... (Pressing Tab to cycle focus, clicking elements, typing text) http://archive.dojotoolkit.org/nightly/dojotoolkit/dijit/tests/form/test... (drag and drop of percent width Slider) http://archive.dojotoolkit.org/nightly/dojotoolkit/dijit/tests/form/test... (holding a key down to test a typematic widget, mouse wheel support in doh.robot) http://archive.dojotoolkit.org/nightly/dojotoolkit/dojo/tests/dnd/test_d... (drag and drop of elements into containers) [Less]
Posted over 15 years ago by dante
Today, Alex Russell closed the voting on the unanimous selection of a new Dojo Project Lead: me. It is with great pleasure that I write this brief note announcing the change, and look forward to serving the Dojo Toolkit and it's developers, users ... [More] , and contributors. Both Alex and I have both posted some notes about the change. Thanks to everyone for their vote of confidence, and to Alex, who has dutifully served in this position for the past four years. Here's to dojo.greatness() ... Join me for a virtual celebration, and have yourself a dojo.beer() [Less]
Posted over 15 years ago by robertusj
Hi dojoers, In this opportunity, I would like to share my status update for gfx project with Dojo. What was achieved lately? - Revised test page. Yes, a new cool looking page! It cut around 40% loading time from previous version (because of dijit ... [More] dependancy), which from ~40 seconds become ~20 seconds. - Camera Well, I suppose say the camera is better than previous one... It uses three axis vector (U, V and N axis of camera) and lookAt algorithm for moving and rotating the camera. Unfortunatelly, it has many bugs and errors when rotating (I could not understand why it happens) but it displays better perception when rotating (try it! It is fun!). - OBJ loader Monkey in the GFX20? Yes, I did the OBJ loader so that we can load OBJ file and display it in gfx20. Have you seen suzanne from blender? If not, go to test page to check how ugly he is... What is my task in my agenda? - Real world example It is planned to give a real world example for gfx20 demonstration. What is it about? It will be kind of model viewer and I am planning to put mobile phone model to begin with... So stay tune! - Documentation I already discussed with my mentor to exchange another example to documentation. I will put couple tutorial, API reference, and dojo book to start with! Not forget to mention couple UML diagram as well such as class diagram and sequence diagram to understand gfx20 more! - Source builder Yes, to minimize the loading time, I need to research about source packager like dojo did! In order to reduce the useless GET latency time for scattered files. - Revise camera Again, modify camera algorithm to maximize the performance and robustness as well as minizing errors or bugs. - Compatibility Well this one is very hard one; the canvas 3d (firefox extension to display the 3d, which is core requirement to display gfx20 in firefox) says it needs firefox 3.0 with gecko engine 1.9 to run but it does not want to load in linux (not sure for mac OSX). I need to have decent way to tell that user can display gfx or not. This includes way to test opengl driver and canvas 3d compatibility. - Status control It is true that current version of gfx has very poor status reporting. What I mean with status reporting is information about the library loading or openning file progress (3d model file, perhaps?). Hence, I need to know how to display information status in effective way. - Slow slow slow! Hate to say but yes, gfx20 is very slow. Last time, I tried to open gfx20 in medium GPU card in the market but it is not nice to be displayed... Maybe I need to get over the algorithm again to check which is the bottleneck... - Availability Long time a go, I have a chat with one of dojo fellow from GFX. He is adding new gfx engine (project that Eugene did) in flash. This snapped idea about why we dont make an engine for gfx3d as well? This may increase the availability of the gfx20. That is all folks! I will put more update for next time, of course I would really appreciate if you give me any sugggestion or critics! Oh yeah, sorry for people who try to run gfx20 but cant get it working... It is hard to deal with availbility problem (such as decent compatibility testing and unsupported version or browser) but feel free to give me idea for future! Thanks! Note: I put a screenshot for those who are interested! [Less]
Posted over 15 years ago by gruppler
After trying unsuccesssfully for about a week to split a block of text into spans of words or letters, I finally followed the KISS rule and made something work. Originally, I was trying to recurse through every non-textNode and split the textNodes ... [More] inside their parentNodes so any HTML inside the supplied node would remain intact. However, some HTML "features" (and lack of sleep) prevented all my attempts from providing me with what I thought would be a simple, robust, and efficient bit of magic. However, now that I have something working it will be easier to refine the code into my original vision. I probably should read this story daily. It's easy to revert to my old method of productivity. You can check out the "alpha" version of the text-explode animations here. Depending on your computer, the second one might perform extremely poorly. [Less]
Posted over 15 years ago by dylan
I recently had a chance to sit down with Jayant Sai of ESRI to discuss their new Dojo-based GIS JavaScript API. DS: Let's start at the beginning. What is ESRI? JS: ESRI(r) leads the international geographic information system (GIS) software ... [More] industry with innovative solutions that help more than 300,000 organizations create, manage, visualize, and analyze information. Our clients use ArcGIS(r) software to unlock the spatial component of their data and quickly make effective decisions. ArcGIS is an integrated family of products for use in desktops, servers, or custom applications; in the field; or over the Web. www.esri.com DS: What problem or problems are you trying to solve for your customers? JS: Our customers build web sites that expose maps, data, and geographic analysis. We want their development process to be as easy as possible while giving the end user a rich and interactive application. By using Dojo we are leveraging a simple framework for building rich Internet applications. This allows us to focus on creating a simple API for the ESRI server software ArcGIS Server. DS: How did you first learn about Dojo, and how does Dojo help you accomplish your goals? JS: We first learned about Dojo when it was at 0.3. We did not evaluate it at the time for our project, but knew of the option. For the ArcGIS JavaScript API project we chose Dojo since it makes our work and our users' work easier. DS: How did you pick the Dojo Toolkit? What other toolkits did you consider? JS: During the initial implementation process, we evaluated Prototype/Scriptaculous, YUI and pondered writing a home grown solution. But the fact that Dojo had support for vector graphics (gfx), a build system (for compression and cross domain deployment) and the wide range of widgets (dijits) made it a winner. DS: What is your favorite thing about working with Dojo? GFX & Dijit templating. DS: How has the Dojo Toolkit helped your business? (faster time to market, let you focus on core competencies, etc.?) The fact that Dojo fixes browser incompatibilities, including handling graphics based on browser, it definitely helps us concentrate on working on the mapping functionality of the API. We like the fact that our users can use the whole Dojo toolkit to build their next generation web 2.0 mapping application, or use just our mapping components, without really getting into the hardcore JavaScript pieces of the toolkit. DS: If someone was evaluating Ajax development options today for building a web application, what advice would you give them? Don't reinvent the wheel. Check out Dojo or other toolkits. DS: How can Dojo developers best make use of your API? The ArcGIS JavaScript API, as the name suggests is an API. The API is hosted on our servers and edge cached, so users can access and create mapping applications from anywhere in the world. DS: Thanks Jayant for taking the time to tell us about your work. Here are some screenshots of the API in action: [inline:img2.jpg=Site Selection and Trade Analysis Area] [inline:=Surface Profile] [inline:img1.jpg=Map Routing] [Less]
Posted over 15 years ago by dylan
The Monday portion of Dojo Developer Day Boston is now "sold out" (can free events sell out?) after just a few short weeks since the announcements! There's a waiting list in case we get more space from the Ajax Experience, so do sign-up if you are ... [More] interested. And the Committer and Contributor Day on Sunday still has plenty of seats and is also free. [Less]
Posted over 15 years ago by robertusj
Hi dojoers, I would like to introduce you a new page for GFX 2.0... Now the new page focuses on the display of the canvas (it is located in the middle of the page and it is very big). How about the other (console and help page)? Dont worry, I made ... [More] such a way when you need them, all you should do just go to bottom left to click either console or help page... And a draggable panel will be shown! In terms of loading, it cuts the loading time around 50% (from 40 seconds to 20 seconds), it is due to I am using a lot of dijit component... Unfortunately, the only problem of new page is performance downgrade since the canvas size is bigger (take more time to draw)... Please go to this page to see the new look of GFX 2.0 page. [Less]
Posted over 15 years ago by jbalogh
Last week before getting sick, I worked on making it possible to export the created form. I've been procrastinating on this part of the app for a while because I was stumped on how to make it easy to use, because exportable data exists on different ... [More] levels: some parts are on the object I use to wrap each form element (soc.Element), and other parts are on the element being wrapped (the dijits). My solution is to perform all attribute lookups through the soc.Element.getattr function, which defers the lookup to the wrapped object under certain conditions. The only condition at this point is: did soc.Element inherit this attribute from a superclass or mixin? My assumption is that the user won't care about any of the attributes inherited from dijit._Widget or dijit._Templated, so we should pass the lookup to the underlying dijit. I got a bit sidetracked and wrote a Set class to help with the lookup decisions; probably not necessary, but it was fun. The names to be exported are set on soc.Canvas when it is created, so it's configurable in the normal dijit way. The export function returns an array of objects, which could then be converted to JSON or XML or Protocol Buffers, whatever you want. The form editor isn't involved in that part, it just gives you the raw data. The test page now has an export button, which sends the output to the console. There's still a couple things to be tweaked, like letting the export function take arguments so it's easy to decide what to export on-the-fly. [Less]
Posted almost 16 years ago by dante
UPDATE: The details for the evening are: Wed, July 23rd -- Chesterfield / 1101 SE Burnside 6:30pm map available: http://maps.google.com/maps?ie=UTF8&oe=utf-8&client=firefox-a&q=chesterf... (just a few blocks ( /-10?) directly south of the ... [More] Lloyd Center Max station) or in a more dojo'y way: dojo.mixin(dojo,{     dinner: function(){        return {           date:"2008-07-23",           time:"6:30pm, PST",           place:"Chesterfield PDX",           address:"1101 SE Burnside"        }     } }); console.dir(dojo.dinner()); Looking forward to seeing everyone! This is just an update for my original post: http://dojotoolkit.org/2008/07/17/ddd-4-5-portland-oregon [Less]
Posted almost 16 years ago by jbalogh
This week I've been trying to integrate the GridContainer into the form creator, so users can create forms with multiple columns. Unfortunately, it hasn't been an easy drop-in replacement, and I've discovered some bugs. #7217 turned out to be a ... [More] "mini flub", easily fixed once I found the faulty code. I think #7218 will be another simple fix (fingers crossed) as soon as I figure out what event to hook into. But there's still some bigger problems that I'm not sure how to fix yet. I have a not-pretty-or-working demo to see them in action: can't move elements across columns the container loses track of an element if you pull it outside the column; watch the target box disappear dragged elements fly back to their original position, instead of dropping onto a new spot Whether these are problems with my code or the GridContainer is still to be determined, but since the SoC is quickly coming to a close, I'm going to turn my attention to other bugs for now. [Less]